Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix hash calculation for proposal for go-ibft's update #1065

Merged
merged 25 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
681e6e9
Changing the signatures of the backend methods.
lazartravica Dec 15, 2022
99cd4a9
Fixed all method signatures that expect a proposal.
lazartravica Dec 15, 2022
544daa2
Verify committed seals created by ethereum block and round number
Kourin1996 Dec 15, 2022
4f0759a
Merge remote-tracking branch 'origin/hotfix/EVM-279' into hotfix/EVM-279
Kourin1996 Dec 15, 2022
7d37f4e
Remove unnecessary fields before hash calculation for CS
Kourin1996 Dec 15, 2022
51e632f
Fix missing field in packProposerSealIntoExtra
Kourin1996 Dec 16, 2022
1db9754
Fix hash calculation for the block including round number
Kourin1996 Dec 16, 2022
b527ecb
Refactor hash calculation with round
Kourin1996 Dec 21, 2022
434a93c
Fix build error test
Kourin1996 Dec 23, 2022
4a7fdf7
Revert "Refactor hash calculation with round"
Kourin1996 Dec 23, 2022
bcf2bcf
Fix failed test
Kourin1996 Dec 26, 2022
cc481eb
Fix HasQuorum
Kourin1996 Dec 26, 2022
f3cd3dc
Rename method in IBFT Backend
Kourin1996 Dec 27, 2022
06b3ccb
Fix method comment
Kourin1996 Dec 27, 2022
db6ace4
Rename IsValidBlock to IsValidProposal in IBFTBackend
Kourin1996 Dec 27, 2022
a5665ab
Fix parsing of RoundNumber in IBFTExtra
Kourin1996 Dec 27, 2022
4f5ec06
Fix packCommittedSealsAndRoundNumberIntoExtra
Kourin1996 Dec 27, 2022
ee68bba
Revert packCommittedSealsAndRoundNumberIntoExtra
Kourin1996 Dec 27, 2022
c0d1d00
Fix hash calculation for committed seals and revert interface of bloc…
Kourin1996 Jan 18, 2023
d78ae88
Merge remote-tracking branch 'origin/hotfix/EVM-279' into hotfix/EVM-279
Kourin1996 Jan 18, 2023
9fa4845
Update go-ibft
Kourin1996 Jan 30, 2023
9c508f6
Fix lint error
Kourin1996 Jan 30, 2023
0fd2657
Fix marshaling of IBFT Extra
Kourin1996 Jan 30, 2023
c2fee48
Fix minor issues
Kourin1996 Jan 30, 2023
63f4cc0
Fix comment
Kourin1996 Jan 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions consensus/ibft/consensus_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package ibft
import (
"context"
"fmt"
"math"
"time"

"github.com/0xPolygon/go-ibft/messages"
"github.com/0xPolygon/go-ibft/messages/proto"
"github.com/0xPolygon/polygon-edge/consensus"
"github.com/0xPolygon/polygon-edge/consensus/ibft/signer"
"github.com/0xPolygon/polygon-edge/helper/hex"
Expand Down Expand Up @@ -40,12 +40,13 @@ func (i *backendIBFT) BuildProposal(blockNumber uint64) []byte {
return block.MarshalRLP()
}

func (i *backendIBFT) InsertBlock(
proposal []byte,
// InsertProposal inserts a proposal of which the consensus has been got
func (i *backendIBFT) InsertProposal(
proposal *proto.Proposal,
committedSeals []*messages.CommittedSeal,
) {
newBlock := &types.Block{}
if err := newBlock.UnmarshalRLP(proposal); err != nil {
if err := newBlock.UnmarshalRLP(proposal.RawProposal); err != nil {
i.logger.Error("cannot unmarshal proposal", "err", err)

return
Expand All @@ -63,7 +64,7 @@ func (i *backendIBFT) InsertBlock(
copy(extraDataBackup, extraDataOriginal)

// Push the committed seals to the header
header, err := i.currentSigner.WriteCommittedSeals(newBlock.Header, committedSealsMap)
header, err := i.currentSigner.WriteCommittedSeals(newBlock.Header, proposal.Round, committedSealsMap)
if err != nil {
i.logger.Error("cannot write committed seals", "err", err)

Expand Down Expand Up @@ -138,7 +139,11 @@ func (i *backendIBFT) MaximumFaultyNodes() uint64 {
return uint64(CalcMaxFaultyNodes(i.currentValidators))
}

func (i *backendIBFT) Quorum(blockNumber uint64) uint64 {
func (i *backendIBFT) HasQuorum(
blockNumber uint64,
messages []*proto.Message,
msgType proto.MessageType,
) bool {
validators, err := i.forkManager.GetValidators(blockNumber)
if err != nil {
i.logger.Error(
Expand All @@ -147,13 +152,21 @@ func (i *backendIBFT) Quorum(blockNumber uint64) uint64 {
"err", err,
)

// return Math.MaxInt32 to prevent overflow when casting to int in go-ibft package
return math.MaxInt32
return false
}

quorumFn := i.quorumSize(blockNumber)

return uint64(quorumFn(validators))
quorum := i.quorumSize(blockNumber)(validators)

switch msgType {
case proto.MessageType_PREPREPARE:
return len(messages) > 0
case proto.MessageType_PREPARE:
return len(messages) >= quorum-1
case proto.MessageType_COMMIT, proto.MessageType_ROUND_CHANGE:
return len(messages) >= quorum
default:
return false
}
}

// buildBlock builds the block, based on the passed in snapshot and parent header
Expand Down
37 changes: 35 additions & 2 deletions consensus/ibft/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,25 @@ func (i *backendIBFT) VerifyHeader(header *types.Header) error {
return err
}

extra, err := headerSigner.GetIBFTExtra(header)
if err != nil {
return err
}

hashForCommittedSeal, err := i.calculateProposalHash(
headerSigner,
header,
extra.RoundNumber,
)
if err != nil {
return err
}

// verify the Committed Seals
// CommittedSeals exists only in the finalized header
if err := headerSigner.VerifyCommittedSeals(
header,
hashForCommittedSeal,
extra.CommittedSeals,
validators,
i.quorumSize(header.Number)(validators),
); err != nil {
Expand Down Expand Up @@ -570,15 +585,33 @@ func (i *backendIBFT) verifyParentCommittedSeals(
i.forkManager,
parent.Number,
)
if err != nil {
return err
}

parentHeader, ok := i.blockchain.GetHeaderByHash(parent.Hash)
if !ok {
return fmt.Errorf("header %s not found", parent.Hash)
}

parentExtra, err := parentSigner.GetIBFTExtra(parentHeader)
if err != nil {
return err
}

parentHash, err := i.calculateProposalHash(
parentSigner,
parentHeader,
parentExtra.RoundNumber,
)
if err != nil {
return err
}

// if shouldVerifyParentCommittedSeals is false, skip the verification
// when header doesn't have Parent Committed Seals (Backward Compatibility)
return parentSigner.VerifyParentCommittedSeals(
parent,
parentHash,
header,
parentValidators,
i.quorumSize(parent.Number)(parentValidators),
Expand Down
23 changes: 13 additions & 10 deletions consensus/ibft/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"google.golang.org/protobuf/proto"

protoIBFT "github.com/0xPolygon/go-ibft/messages/proto"
"github.com/0xPolygon/polygon-edge/types"
)

func (i *backendIBFT) signMessage(msg *protoIBFT.Message) *protoIBFT.Message {
Expand All @@ -21,25 +20,29 @@ func (i *backendIBFT) signMessage(msg *protoIBFT.Message) *protoIBFT.Message {
}

func (i *backendIBFT) BuildPrePrepareMessage(
proposal []byte,
rawProposal []byte,
certificate *protoIBFT.RoundChangeCertificate,
view *protoIBFT.View,
) *protoIBFT.Message {
block := &types.Block{}
if err := block.UnmarshalRLP(proposal); err != nil {
return nil
proposedBlock := &protoIBFT.Proposal{
RawProposal: rawProposal,
Round: view.Round,
}

proposalHash := block.Hash().Bytes()
// hash calculation begins
proposalHash, err := i.calculateProposalHashFromBlockBytes(rawProposal, &view.Round)
if err != nil {
return nil
}

msg := &protoIBFT.Message{
View: view,
From: i.ID(),
Type: protoIBFT.MessageType_PREPREPARE,
Payload: &protoIBFT.Message_PreprepareData{
PreprepareData: &protoIBFT.PrePrepareMessage{
Proposal: proposal,
ProposalHash: proposalHash,
Proposal: proposedBlock,
ProposalHash: proposalHash.Bytes(),
Certificate: certificate,
},
},
Expand Down Expand Up @@ -87,7 +90,7 @@ func (i *backendIBFT) BuildCommitMessage(proposalHash []byte, view *protoIBFT.Vi
}

func (i *backendIBFT) BuildRoundChangeMessage(
proposal []byte,
proposal *protoIBFT.Proposal,
certificate *protoIBFT.PreparedCertificate,
view *protoIBFT.View,
) *protoIBFT.Message {
Expand All @@ -96,7 +99,7 @@ func (i *backendIBFT) BuildRoundChangeMessage(
From: i.ID(),
Type: protoIBFT.MessageType_ROUND_CHANGE,
Payload: &protoIBFT.Message_RoundChangeData{RoundChangeData: &protoIBFT.RoundChangeMessage{
LastPreparedProposedBlock: proposal,
LastPreparedProposal: proposal,
LatestPreparedCertificate: certificate,
}},
}
Expand Down
13 changes: 11 additions & 2 deletions consensus/ibft/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func TestSign_CommittedSeals(t *testing.T) {
var (
h = &types.Header{}
err error

roundNumber uint64 = 1
)

correctValSet := pool.ValidatorSet()
Expand Down Expand Up @@ -95,11 +97,18 @@ func TestSign_CommittedSeals(t *testing.T) {
seals[acc.Address()] = seal
}

sealed, err := signerA.WriteCommittedSeals(h, seals)
sealed, err := signerA.WriteCommittedSeals(h, roundNumber, seals)
assert.NoError(t, err)

committedSeal, err := signerA.GetIBFTExtra(sealed)
assert.NoError(t, err)

return signerA.VerifyCommittedSeals(sealed, correctValSet, OptimalQuorumSize(correctValSet))
return signerA.VerifyCommittedSeals(
sealed.Hash,
committedSeal.CommittedSeals,
correctValSet,
OptimalQuorumSize(correctValSet),
)
}

// Correct
Expand Down
87 changes: 84 additions & 3 deletions consensus/ibft/signer/extra.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package signer

import (
"encoding/binary"
"errors"
"fmt"

"github.com/0xPolygon/polygon-edge/types"
Expand All @@ -20,6 +22,8 @@ var (
IstanbulExtraSeal = 65

zeroBytes = make([]byte, 32)

errRoundNumberOverflow = errors.New("round number is out of range for 64bit")
)

// IstanbulExtra defines the structure of the extra field for Istanbul
Expand All @@ -28,6 +32,7 @@ type IstanbulExtra struct {
ProposerSeal []byte
CommittedSeals Seals
ParentCommittedSeals Seals
RoundNumber *uint64
}

type Seals interface {
Expand All @@ -37,6 +42,36 @@ type Seals interface {
UnmarshalRLPFrom(*fastrlp.Parser, *fastrlp.Value) error
}

// parseRound parses RLP-encoded bytes into round
func parseRound(v *fastrlp.Value) (*uint64, error) {
roundBytes, err := v.Bytes()
if err != nil {
return nil, err
}

if len(roundBytes) > 8 {
return nil, errRoundNumberOverflow
}

if len(roundBytes) == 0 {
return nil, nil
}

round := binary.BigEndian.Uint64(roundBytes)

return &round, nil
}

// toRoundBytes converts uint64 round to bytes
// Round begins with zero and it can be nil for backward compatibility.
// For that reason, Extra always has 8 bytes space for a round when the round has value.
func toRoundBytes(round uint64) []byte {
roundBytes := make([]byte, 8)
binary.BigEndian.PutUint64(roundBytes, round)

return roundBytes
}

// MarshalRLPTo defines the marshal function wrapper for IstanbulExtra
func (i *IstanbulExtra) MarshalRLPTo(dst []byte) []byte {
return types.MarshalRLPTo(i.MarshalRLPWith, dst)
Expand All @@ -60,10 +95,20 @@ func (i *IstanbulExtra) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value {
vv.Set(i.CommittedSeals.MarshalRLPWith(ar))

// ParentCommittedSeal
if i.ParentCommittedSeals != nil {
if i.ParentCommittedSeals == nil {
vv.Set(ar.NewNullArray())
} else {
vv.Set(i.ParentCommittedSeals.MarshalRLPWith(ar))
}

if i.RoundNumber == nil {
vv.Set(ar.NewNull())
} else {
vv.Set(ar.NewBytes(
toRoundBytes(*i.RoundNumber),
))
}

return vv
}

Expand Down Expand Up @@ -105,6 +150,16 @@ func (i *IstanbulExtra) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) er
}
}

// Round
if len(elems) >= 5 {
roundNumber, err := parseRound(elems[4])
if err != nil {
return err
}

i.RoundNumber = roundNumber
}

return nil
}

Expand All @@ -129,6 +184,16 @@ func (i *IstanbulExtra) unmarshalRLPFromForParentCS(p *fastrlp.Parser, v *fastrl
}
}

// Round
if len(elems) >= 5 {
roundNumber, err := parseRound(elems[4])
if err != nil {
return err
}

i.RoundNumber = roundNumber
}

return nil
}

Expand Down Expand Up @@ -213,15 +278,21 @@ func packProposerSealIntoExtra(
newArrayValue.Set(oldValues[3])
}

// Round
if len(oldValues) >= 5 {
newArrayValue.Set(oldValues[4])
}

return nil
},
)
}

// packCommittedSealsIntoExtra updates only CommittedSeal field in Extra
func packCommittedSealsIntoExtra(
// packCommittedSealsAndRoundNumberIntoExtra updates only CommittedSeal field in Extra
func packCommittedSealsAndRoundNumberIntoExtra(
extraBytes []byte,
committedSeal Seals,
roundNumber *uint64,
) []byte {
return packFieldsIntoExtra(
extraBytes,
Expand All @@ -242,6 +313,16 @@ func packCommittedSealsIntoExtra(
// ParentCommittedSeal
if len(oldValues) >= 4 {
newArrayValue.Set(oldValues[3])
} else {
newArrayValue.Set(ar.NewNullArray())
}

if roundNumber == nil {
newArrayValue.Set(ar.NewNull())
} else {
newArrayValue.Set(ar.NewBytes(
toRoundBytes(*roundNumber),
))
}

return nil
Expand Down
Loading