From b790b077c9334e9ea188929ad9c42c70e23135ba Mon Sep 17 00:00:00 2001 From: wgr523 Date: Fri, 25 Mar 2022 23:22:24 +0800 Subject: [PATCH] XIN-164 add GapNumber inside Vote, and tests (#74) --- consensus/XDPoS/engines/engine_v2/engine.go | 26 ++++- consensus/XDPoS/engines/engine_v2/vote.go | 31 ++++- consensus/XDPoS/utils/types.go | 9 +- consensus/XDPoS/utils/types_test.go | 21 ++-- .../tests/engine_v2_tests/adaptor_test.go | 4 + consensus/tests/engine_v2_tests/helper.go | 14 ++- .../tests/engine_v2_tests/initial_test.go | 3 + .../engine_v2_tests/verify_header_test.go | 20 +++- consensus/tests/engine_v2_tests/vote_test.go | 107 +++++++++++++++++- eth/bft/bft_handler_test.go | 1 + 10 files changed, 203 insertions(+), 33 deletions(-) diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 05b920200b..6a01b89eba 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -98,6 +98,7 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) * Number: big.NewInt(0), }, Signatures: []utils.Signature{}, + GapNumber: 0, }, highestVotedRound: utils.Round(0), highestCommitBlock: nil, @@ -142,6 +143,7 @@ func (x *XDPoS_v2) Initial(chain consensus.ChainReader, header *types.Header) er quorumCert = &utils.QuorumCert{ ProposedBlockInfo: blockInfo, Signatures: nil, + GapNumber: header.Number.Uint64()-x.config.Gap, } // can not call processQC because round is equal to default @@ -554,7 +556,7 @@ func (x *XDPoS_v2) SyncInfoHandler(chain consensus.ChainReader, syncInfo *utils. func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *utils.Vote) (bool, error) { /* 1. Check vote round with current round for fast fail(disqualifed) - 2. Get masterNode list from snapshot + 2. Get masterNode list from snapshot by using vote.GapNumber 3. Check signature: - Use ecRecover to get the public key - Use the above public key to find out the xdc address @@ -566,11 +568,14 @@ func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *utils.Vo return false, nil } - snapshot, err := x.getSnapshot(chain, vote.ProposedBlockInfo.Number.Uint64(), false) + snapshot, err := x.getSnapshot(chain, vote.GapNumber, true) if err != nil { log.Error("[VerifyVoteMessage] fail to get snapshot for a vote message", "BlockNum", vote.ProposedBlockInfo.Number, "Hash", vote.ProposedBlockInfo.Hash, "Error", err.Error()) } - verified, _, err := x.verifyMsgSignature(utils.VoteSigHash(vote.ProposedBlockInfo), vote.Signature, snapshot.NextEpochMasterNodes) + verified, _, err := x.verifyMsgSignature(utils.VoteSigHash(&utils.VoteForSign{ + ProposedBlockInfo: vote.ProposedBlockInfo, + GapNumber: vote.GapNumber, + }), vote.Signature, snapshot.NextEpochMasterNodes) if err != nil { for i, mn := range snapshot.NextEpochMasterNodes { log.Warn("[VerifyVoteMessage] Master node list item", "index", i, "Master node", mn.Hex()) @@ -735,7 +740,8 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert * - Use ecRecover to get the public key - Use the above public key to find out the xdc address - Use the above xdc address to check against the master node list from step 1(For the received QC epoch) - 4. Verify blockInfo + 4. Verify gapNumber = epochSwitchNumber - epochSwitchNumber%Epoch - Gap + 5. Verify blockInfo */ epochInfo, err := x.getEpochSwitchInfo(blockChainReader, nil, quorumCert.ProposedBlockInfo.Hash) if err != nil { @@ -771,7 +777,10 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert * for _, signature := range signatures { go func(sig utils.Signature) { defer wg.Done() - verified, _, err := x.verifyMsgSignature(utils.VoteSigHash(quorumCert.ProposedBlockInfo), sig, epochInfo.Masternodes) + verified, _, err := x.verifyMsgSignature(utils.VoteSigHash(&utils.VoteForSign{ + ProposedBlockInfo: quorumCert.ProposedBlockInfo, + GapNumber: quorumCert.GapNumber, + }), sig, epochInfo.Masternodes) if err != nil { log.Error("[verifyQC] Error while verfying QC message signatures", "Error", err) haveError = fmt.Errorf("Error while verfying QC message signatures") @@ -788,7 +797,12 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert * if haveError != nil { return haveError } - + epochSwitchNumber := epochInfo.EpochSwitchBlockInfo.Number.Uint64() + gapNumber := epochSwitchNumber - epochSwitchNumber%x.config.Epoch - x.config.Gap + if gapNumber != quorumCert.GapNumber { + log.Error("[verifyQC] gap number mismatch", "BlockInfoHash", quorumCert.ProposedBlockInfo.Hash, "Gap", quorumCert.GapNumber, "GapShouldBe", gapNumber) + return fmt.Errorf("gap number mismatch %v", quorumCert) + } return x.VerifyBlockInfo(blockChainReader, quorumCert.ProposedBlockInfo) } diff --git a/consensus/XDPoS/engines/engine_v2/vote.go b/consensus/XDPoS/engines/engine_v2/vote.go index f25a6ff37f..084e95f1a5 100644 --- a/consensus/XDPoS/engines/engine_v2/vote.go +++ b/consensus/XDPoS/engines/engine_v2/vote.go @@ -19,7 +19,17 @@ func (x *XDPoS_v2) sendVote(chainReader consensus.ChainReader, blockInfo *utils. // Third step: Construct the vote struct with the above signature & blockinfo struct // Forth step: Send the vote to broadcast channel - signedHash, err := x.signSignature(utils.VoteSigHash(blockInfo)) + epochSwitchInfo, err := x.getEpochSwitchInfo(chainReader, nil, blockInfo.Hash) + if err != nil { + log.Error("getEpochSwitchInfo when sending out Vote", "BlockInfoHash", blockInfo.Hash, "Error", err) + return err + } + epochSwitchNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64() + gapNumber := epochSwitchNumber - epochSwitchNumber%x.config.Epoch - x.config.Gap + signedHash, err := x.signSignature(utils.VoteSigHash(&utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: gapNumber, + })) if err != nil { log.Error("signSignature when sending out Vote", "BlockInfoHash", blockInfo.Hash, "Error", err) return err @@ -29,6 +39,7 @@ func (x *XDPoS_v2) sendVote(chainReader consensus.ChainReader, blockInfo *utils. voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: gapNumber, } err = x.voteHandler(chainReader, voteMsg) @@ -69,6 +80,18 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote) x.votePool.ClearPoolKeyByObj(voteMsg) return err } + // verify vote.GapNumber + epochSwitchInfo, err := x.getEpochSwitchInfo(chain, nil, voteMsg.ProposedBlockInfo.Hash) + if err != nil { + log.Error("getEpochSwitchInfo when handle Vote", "BlockInfoHash", voteMsg.ProposedBlockInfo.Hash, "Error", err) + return err + } + epochSwitchNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64() + gapNumber := epochSwitchNumber - epochSwitchNumber%x.config.Epoch - x.config.Gap + if gapNumber != voteMsg.GapNumber { + log.Error("[voteHandler] gap number mismatch", "BlockInfoHash", voteMsg.ProposedBlockInfo.Hash, "Gap", voteMsg.GapNumber, "GapShouldBe", gapNumber) + return fmt.Errorf("gap number mismatch %v", voteMsg) + } err = x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg, proposedBlockHeader) if err != nil { @@ -95,7 +118,10 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole for h, vote := range pooledVotes { go func(hash common.Hash, v *utils.Vote, i int) { defer wg.Done() - verified, _, err := x.verifyMsgSignature(utils.VoteSigHash(v.ProposedBlockInfo), v.Signature, masternodes) + verified, _, err := x.verifyMsgSignature(utils.VoteSigHash(&utils.VoteForSign{ + ProposedBlockInfo: v.ProposedBlockInfo, + GapNumber: v.GapNumber, + }), v.Signature, masternodes) if !verified || err != nil { log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "Error", err.Error(), "verified", verified) } else { @@ -123,6 +149,7 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole quorumCert := &utils.QuorumCert{ ProposedBlockInfo: currentVoteMsg.(*utils.Vote).ProposedBlockInfo, Signatures: validSignatureSlice, + GapNumber: currentVoteMsg.(*utils.Vote).GapNumber, } err := x.processQC(chain, quorumCert) if err != nil { diff --git a/consensus/XDPoS/utils/types.go b/consensus/XDPoS/utils/types.go index aec39132ee..36ad62556d 100644 --- a/consensus/XDPoS/utils/types.go +++ b/consensus/XDPoS/utils/types.go @@ -76,6 +76,7 @@ type BlockInfo struct { type Vote struct { ProposedBlockInfo *BlockInfo Signature Signature + GapNumber uint64 } // Timeout message in XDPoS 2.0 @@ -95,6 +96,7 @@ type SyncInfo struct { type QuorumCert struct { ProposedBlockInfo *BlockInfo Signatures []Signature + GapNumber uint64 } // Timeout Certificate struct in XDPoS 2.0 @@ -146,7 +148,12 @@ func (m *SyncInfo) Hash() common.Hash { return rlpHash(m) } -func VoteSigHash(m *BlockInfo) common.Hash { +type VoteForSign struct { + ProposedBlockInfo *BlockInfo + GapNumber uint64 +} + +func VoteSigHash(m *VoteForSign) common.Hash { return rlpHash(m) } diff --git a/consensus/XDPoS/utils/types_test.go b/consensus/XDPoS/utils/types_test.go index 764eb69587..a8971db884 100644 --- a/consensus/XDPoS/utils/types_test.go +++ b/consensus/XDPoS/utils/types_test.go @@ -10,10 +10,10 @@ import ( func toyExtraFields() *ExtraFields_v2 { round := Round(307) - blockInfo := &BlockInfo{Hash: common.BigToHash(big.NewInt(2047)), Round: round - 1, Number: big.NewInt(1)} + blockInfo := &BlockInfo{Hash: common.BigToHash(big.NewInt(2047)), Round: round - 1, Number: big.NewInt(900)} signature := []byte{1, 2, 3, 4, 5, 6, 7, 8} signatures := []Signature{signature} - quorumCert := &QuorumCert{ProposedBlockInfo: blockInfo, Signatures: signatures} + quorumCert := &QuorumCert{ProposedBlockInfo: blockInfo, Signatures: signatures, GapNumber: 450} e := &ExtraFields_v2{Round: round, QuorumCert: quorumCert} return e } @@ -35,16 +35,19 @@ func TestExtraFieldsEncodeDecode(t *testing.T) { func TestHashAndSigHash(t *testing.T) { round := Round(307) - blockInfo1 := &BlockInfo{Hash: common.BigToHash(big.NewInt(2047)), Round: round - 1, Number: big.NewInt(1)} - blockInfo2 := &BlockInfo{Hash: common.BigToHash(big.NewInt(4095)), Round: round - 1, Number: big.NewInt(1)} + gapNumer := uint64(450) + blockInfo1 := &BlockInfo{Hash: common.BigToHash(big.NewInt(2047)), Round: round - 1, Number: big.NewInt(900)} + blockInfo2 := &BlockInfo{Hash: common.BigToHash(big.NewInt(4095)), Round: round - 1, Number: big.NewInt(900)} + voteForSign1 := &VoteForSign{ProposedBlockInfo: blockInfo1, GapNumber: gapNumer} + voteForSign2 := &VoteForSign{ProposedBlockInfo: blockInfo2, GapNumber: gapNumer} signature1 := []byte{1, 2, 3, 4, 5, 6, 7, 8} signature2 := []byte{1, 2, 3, 4, 5, 6, 7, 7} signatures1 := []Signature{signature1} signatures2 := []Signature{signature2} - quorumCert1 := &QuorumCert{ProposedBlockInfo: blockInfo1, Signatures: signatures1} - quorumCert2 := &QuorumCert{ProposedBlockInfo: blockInfo1, Signatures: signatures2} - vote1 := Vote{ProposedBlockInfo: blockInfo1, Signature: signature1} - vote2 := Vote{ProposedBlockInfo: blockInfo1, Signature: signature2} + quorumCert1 := &QuorumCert{ProposedBlockInfo: blockInfo1, Signatures: signatures1, GapNumber: 450} + quorumCert2 := &QuorumCert{ProposedBlockInfo: blockInfo1, Signatures: signatures2, GapNumber: 450} + vote1 := Vote{ProposedBlockInfo: blockInfo1, Signature: signature1, GapNumber: gapNumer} + vote2 := Vote{ProposedBlockInfo: blockInfo1, Signature: signature2, GapNumber: gapNumer} if vote1.Hash() == vote2.Hash() { t.Fatalf("Hash of two votes shouldn't equal") } @@ -58,7 +61,7 @@ func TestHashAndSigHash(t *testing.T) { if syncInfo1.Hash() == syncInfo2.Hash() { t.Fatalf("Hash of two sync info shouldn't equal") } - if VoteSigHash(blockInfo1) == VoteSigHash(blockInfo2) { + if VoteSigHash(voteForSign1) == VoteSigHash(voteForSign2) { t.Fatalf("SigHash of two block info shouldn't equal") } round2 := Round(999) diff --git a/consensus/tests/engine_v2_tests/adaptor_test.go b/consensus/tests/engine_v2_tests/adaptor_test.go index 51bce6ad35..19def80f7e 100644 --- a/consensus/tests/engine_v2_tests/adaptor_test.go +++ b/consensus/tests/engine_v2_tests/adaptor_test.go @@ -96,6 +96,7 @@ func TestAdaptorIsEpochSwitch(t *testing.T) { quorumCert := &utils.QuorumCert{ ProposedBlockInfo: parentBlockInfo, Signatures: nil, + GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64()-blockchain.Config().XDPoS.Gap, } extra := utils.ExtraFields_v2{ Round: 1, @@ -116,6 +117,7 @@ func TestAdaptorIsEpochSwitch(t *testing.T) { quorumCert = &utils.QuorumCert{ ProposedBlockInfo: parentBlockInfo, Signatures: nil, + GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64()-blockchain.Config().XDPoS.Gap, } extra = utils.ExtraFields_v2{ Round: 2, @@ -136,6 +138,7 @@ func TestAdaptorIsEpochSwitch(t *testing.T) { quorumCert = &utils.QuorumCert{ ProposedBlockInfo: parentBlockInfo, Signatures: nil, + GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64()-blockchain.Config().XDPoS.Gap, } extra = utils.ExtraFields_v2{ Round: utils.Round(blockchain.Config().XDPoS.Epoch) + 1, @@ -156,6 +159,7 @@ func TestAdaptorIsEpochSwitch(t *testing.T) { quorumCert = &utils.QuorumCert{ ProposedBlockInfo: parentBlockInfo, Signatures: nil, + GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64()-blockchain.Config().XDPoS.Gap, } extra = utils.ExtraFields_v2{ Round: utils.Round(blockchain.Config().XDPoS.Epoch) + 2, diff --git a/consensus/tests/engine_v2_tests/helper.go b/consensus/tests/engine_v2_tests/helper.go index adef49848c..7723afa4f7 100644 --- a/consensus/tests/engine_v2_tests/helper.go +++ b/consensus/tests/engine_v2_tests/helper.go @@ -633,20 +633,26 @@ func generateV2Extra(roundNumber int64, currentBlock *types.Block, signer common Round: round, Number: currentBlock.Number(), } + gapNumber := currentBlock.Number().Uint64() - currentBlock.Number().Uint64()%params.TestXDPoSMockChainConfig.XDPoS.Epoch - params.TestXDPoSMockChainConfig.XDPoS.Gap + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: proposedBlockInfo, + GapNumber: gapNumber, + } - signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes()) + signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(voteForSign).Bytes()) if err != nil { panic(fmt.Errorf("Error generate QC by creating signedHash: %v", err)) } // Sign from acc 1, 2, 3 - acc1SignedHash := SignHashByPK(acc1Key, utils.VoteSigHash(proposedBlockInfo).Bytes()) - acc2SignedHash := SignHashByPK(acc2Key, utils.VoteSigHash(proposedBlockInfo).Bytes()) - acc3SignedHash := SignHashByPK(acc3Key, utils.VoteSigHash(proposedBlockInfo).Bytes()) + acc1SignedHash := SignHashByPK(acc1Key, utils.VoteSigHash(voteForSign).Bytes()) + acc2SignedHash := SignHashByPK(acc2Key, utils.VoteSigHash(voteForSign).Bytes()) + acc3SignedHash := SignHashByPK(acc3Key, utils.VoteSigHash(voteForSign).Bytes()) var signatures []utils.Signature signatures = append(signatures, acc1SignedHash, acc2SignedHash, acc3SignedHash, signedHash) quorumCert := &utils.QuorumCert{ ProposedBlockInfo: proposedBlockInfo, Signatures: signatures, + GapNumber: gapNumber, } extra := utils.ExtraFields_v2{ diff --git a/consensus/tests/engine_v2_tests/initial_test.go b/consensus/tests/engine_v2_tests/initial_test.go index 182a3b201c..a1983061eb 100644 --- a/consensus/tests/engine_v2_tests/initial_test.go +++ b/consensus/tests/engine_v2_tests/initial_test.go @@ -33,6 +33,7 @@ func TestInitialFirstV2Blcok(t *testing.T) { expectedQuorumCert := &utils.QuorumCert{ ProposedBlockInfo: blockInfo, Signatures: nil, + GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64()-blockchain.Config().XDPoS.Gap, } assert.Equal(t, utils.Round(1), round) assert.Equal(t, expectedQuorumCert, highQC) @@ -73,6 +74,7 @@ func TestInitialOtherV2Block(t *testing.T) { quorumCert := &utils.QuorumCert{ ProposedBlockInfo: blockInfo, Signatures: nil, // after decode it got default value []utils.Signature{} + GapNumber: 450, } extra := utils.ExtraFields_v2{ Round: 11, @@ -103,6 +105,7 @@ func TestInitialOtherV2Block(t *testing.T) { expectedQuorumCert := &utils.QuorumCert{ ProposedBlockInfo: blockInfo, Signatures: []utils.Signature{}, + GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64()-blockchain.Config().XDPoS.Gap, } assert.Equal(t, utils.Round(11), round) assert.Equal(t, expectedQuorumCert, highQC) diff --git a/consensus/tests/engine_v2_tests/verify_header_test.go b/consensus/tests/engine_v2_tests/verify_header_test.go index 7ed44dd5c2..3411a504ef 100644 --- a/consensus/tests/engine_v2_tests/verify_header_test.go +++ b/consensus/tests/engine_v2_tests/verify_header_test.go @@ -108,20 +108,25 @@ func TestShouldVerifyBlock(t *testing.T) { Round: utils.Round(2), Number: blockchain.GetBlockByNumber(902).Number(), } + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: proposedBlockInfo, + GapNumber: 450, + } // Genrate QC - signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes()) + signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(voteForSign).Bytes()) if err != nil { panic(fmt.Errorf("Error generate QC by creating signedHash: %v", err)) } // Sign from acc 1, 2, 3 - acc1SignedHash := SignHashByPK(acc1Key, utils.VoteSigHash(proposedBlockInfo).Bytes()) - acc2SignedHash := SignHashByPK(acc2Key, utils.VoteSigHash(proposedBlockInfo).Bytes()) - acc3SignedHash := SignHashByPK(acc3Key, utils.VoteSigHash(proposedBlockInfo).Bytes()) + acc1SignedHash := SignHashByPK(acc1Key, utils.VoteSigHash(voteForSign).Bytes()) + acc2SignedHash := SignHashByPK(acc2Key, utils.VoteSigHash(voteForSign).Bytes()) + acc3SignedHash := SignHashByPK(acc3Key, utils.VoteSigHash(voteForSign).Bytes()) var signatures []utils.Signature signatures = append(signatures, signedHash, acc1SignedHash, acc2SignedHash, acc3SignedHash) quorumCert := &utils.QuorumCert{ ProposedBlockInfo: proposedBlockInfo, Signatures: signatures, + GapNumber: 450, } extra := utils.ExtraFields_v2{ @@ -183,7 +188,11 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) { Round: utils.Round(1), Number: parentBlock.Number(), } - signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes()) + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: proposedBlockInfo, + GapNumber: 450, + } + signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(voteForSign).Bytes()) assert.Nil(t, err) var signatures []utils.Signature // Duplicate the signatures @@ -191,6 +200,7 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) { quorumCert := &utils.QuorumCert{ ProposedBlockInfo: proposedBlockInfo, Signatures: signatures, + GapNumber: 450, } extra := utils.ExtraFields_v2{ diff --git a/consensus/tests/engine_v2_tests/vote_test.go b/consensus/tests/engine_v2_tests/vote_test.go index da209f5162..7ee0398c4b 100644 --- a/consensus/tests/engine_v2_tests/vote_test.go +++ b/consensus/tests/engine_v2_tests/vote_test.go @@ -3,6 +3,7 @@ package engine_v2_tests import ( "fmt" "math/big" + "strings" "testing" "github.com/XinFinOrg/XDPoSChain/accounts" @@ -24,7 +25,11 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te Round: utils.Round(1), Number: big.NewInt(901), } - voteSigningHash := utils.VoteSigHash(blockInfo) + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } + voteSigningHash := utils.VoteSigHash(voteForSign) // Set round to 5 engineV2.SetNewRoundFaker(blockchain, utils.Round(1), false) @@ -34,6 +39,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -49,6 +55,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) assert.Nil(t, err) @@ -64,6 +71,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -86,7 +94,11 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) { Round: utils.Round(5), Number: big.NewInt(905), } - voteSigningHash := utils.VoteSigHash(blockInfo) + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } + voteSigningHash := utils.VoteSigHash(voteForSign) // Set round to 5 engineV2.SetNewRoundFaker(blockchain, utils.Round(5), false) @@ -96,6 +108,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) { voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -109,6 +122,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) assert.Nil(t, err) @@ -127,6 +141,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: randomlySignedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) assert.Nil(t, err) @@ -141,6 +156,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -172,6 +188,7 @@ func TestThrowErrorIfVoteMsgRoundIsMoreThanOneRoundAwayFromCurrentRound(t *testi voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: []byte{1}, + GapNumber: 450, } // voteRound > currentRound @@ -204,12 +221,17 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) { Round: utils.Round(5), Number: big.NewInt(905), } - voteSigningHash := utils.VoteSigHash(blockInfo) + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } + voteSigningHash := utils.VoteSigHash(voteForSign) // Create two vote message which will not reach vote pool threshold signedHash := SignHashByPK(acc1Key, voteSigningHash.Bytes()) voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err := engineV2.VoteHandler(blockchain, voteMsg) @@ -223,6 +245,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc2Key, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) assert.Nil(t, err) @@ -233,6 +256,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc3Key, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -318,7 +342,11 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) { Round: utils.Round(6), Number: big.NewInt(906), } - voteSigningHash := utils.VoteSigHash(blockInfo) + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } + voteSigningHash := utils.VoteSigHash(voteForSign) // Set round to 6 engineV2.SetNewRoundFaker(blockchain, utils.Round(6), false) @@ -326,6 +354,7 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) { voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc1Key, voteSigningHash.Bytes()), + GapNumber: 450, } err := engineV2.VoteHandler(blockchain, voteMsg) @@ -334,6 +363,7 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc2Key, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) assert.Nil(t, err) @@ -342,6 +372,7 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc3Key, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -360,6 +391,7 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(voterKey, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -389,12 +421,17 @@ func TestProcessVoteMsgFailIfVerifyBlockInfoFail(t *testing.T) { Round: utils.Round(5), Number: big.NewInt(905), } - voteSigningHash := utils.VoteSigHash(blockInfo) + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } + voteSigningHash := utils.VoteSigHash(voteForSign) // Create two vote message which will not reach vote pool threshold signedHash := SignHashByPK(acc1Key, voteSigningHash.Bytes()) voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signedHash, + GapNumber: 450, } err := engineV2.VoteHandler(blockchain, voteMsg) @@ -408,6 +445,7 @@ func TestProcessVoteMsgFailIfVerifyBlockInfoFail(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc2Key, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) assert.Nil(t, err) @@ -418,6 +456,7 @@ func TestProcessVoteMsgFailIfVerifyBlockInfoFail(t *testing.T) { voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: SignHashByPK(acc3Key, voteSigningHash.Bytes()), + GapNumber: 450, } err = engineV2.VoteHandler(blockchain, voteMsg) @@ -434,11 +473,16 @@ func TestVerifyVoteMsg(t *testing.T) { Round: utils.Round(14), Number: big.NewInt(915), } + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } // Valid message but disqualified as the round does not match voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: []byte{1}, + GapNumber: 450, } engineV2.SetNewRoundFaker(blockchain, utils.Round(15), false) verified, err := engineV2.VerifyVoteMessage(blockchain, voteMsg) @@ -452,13 +496,64 @@ func TestVerifyVoteMsg(t *testing.T) { assert.Equal(t, "Error while verifying message: invalid signature length", err.Error()) // Valid vote message from a master node - signHash, _ := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(blockInfo).Bytes()) + signHash, _ := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(voteForSign).Bytes()) voteMsg = &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: signHash, + GapNumber: 450, } verified, err = engineV2.VerifyVoteMessage(blockchain, voteMsg) assert.True(t, verified) assert.Nil(t, err) } + +func TestVoteMessageHandlerWrongGapNumber(t *testing.T) { + blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, 0) + engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 + + blockInfo := &utils.BlockInfo{ + Hash: currentBlock.Hash(), + Round: utils.Round(5), + Number: big.NewInt(905), + } + voteForSign := &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 450, + } + voteSigningHash := utils.VoteSigHash(voteForSign) + + // Set round to 5 + engineV2.SetNewRoundFaker(blockchain, utils.Round(5), false) + // Create two vote messages which will not reach vote pool threshold + signedHash, _ := signFn(accounts.Account{Address: signer}, voteSigningHash.Bytes()) + voteMsg := &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: signedHash, + GapNumber: 450, + } + engineV2.VoteHandler(blockchain, voteMsg) + signedHash = SignHashByPK(acc1Key, voteSigningHash.Bytes()) + voteMsg = &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: signedHash, + GapNumber: 450, + } + engineV2.VoteHandler(blockchain, voteMsg) + + // Create a vote message that has wrong gap number + voteForSign = &utils.VoteForSign{ + ProposedBlockInfo: blockInfo, + GapNumber: 451, + } + voteSigningHash = utils.VoteSigHash(voteForSign) + signedHash = SignHashByPK(acc3Key, voteSigningHash.Bytes()) + voteMsg = &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: signedHash, + GapNumber: 451, + } + + err := engineV2.VoteHandler(blockchain, voteMsg) + assert.True(t, strings.Contains(err.Error(), "gap number mismatch")) +} diff --git a/eth/bft/bft_handler_test.go b/eth/bft/bft_handler_test.go index 7b4524e7fb..2f785af448 100644 --- a/eth/bft/bft_handler_test.go +++ b/eth/bft/bft_handler_test.go @@ -21,6 +21,7 @@ func makeVotes(n int) []utils.Vote { votes = append(votes, utils.Vote{ ProposedBlockInfo: &utils.BlockInfo{}, Signature: []byte{byte(i)}, + GapNumber: 0, }) } return votes