From c77a64163816d9c83bf83c34114eae4a9b652f27 Mon Sep 17 00:00:00 2001 From: Jianrong Date: Sun, 20 Feb 2022 20:45:08 +1100 Subject: [PATCH] add verify blockInfo function --- consensus/XDPoS/XDPoS.go | 4 -- consensus/XDPoS/engines/engine_v2/engine.go | 38 ++++++++++++- consensus/tests/verify_blockinfo_test.go | 63 +++++++++++++++++++++ 3 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 consensus/tests/verify_blockinfo_test.go diff --git a/consensus/XDPoS/XDPoS.go b/consensus/XDPoS/XDPoS.go index df2f283a9e..41fd7510b6 100644 --- a/consensus/XDPoS/XDPoS.go +++ b/consensus/XDPoS/XDPoS.go @@ -501,7 +501,3 @@ func (x *XDPoS) VerifyTimeout(*utils.Timeout) error { func (x *XDPoS) VerifySyncInfo(*utils.SyncInfo) error { return nil } - -func (x *XDPoS) VerifyBlockInfo(*utils.BlockInfo) error { - return nil -} diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index edbbc1cfae..97bfaf57cf 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -572,6 +572,10 @@ func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *utils.Vo - Use the above xdc address to check against the master node list from step 1(For the running epoch) 4. Broadcast(Not part of consensus) */ + err := x.VerifyBlockInfo(chain, vote.ProposedBlockInfo) + if err != nil { + return false, err + } snapshot, err := x.getSnapshot(chain, vote.ProposedBlockInfo.Number.Uint64()) 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()) @@ -821,11 +825,41 @@ func (x *XDPoS_v2) ProposedBlockHandler(blockChainReader consensus.ChainReader, */ // To be used by different message verification. Verify local DB block info against the received block information(i.e hash, blockNum, round) -func (x *XDPoS_v2) VerifyBlockInfo(blockInfo *utils.BlockInfo) error { +func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, blockInfo *utils.BlockInfo) error { /* 1. Check if is able to get header by hash from the chain 2. Check the header from step 1 matches what's in the blockInfo. This includes the block number and the round */ + blockHeader := blockChainReader.GetHeaderByHash(blockInfo.Hash) + if blockHeader == nil { + log.Warn("[VerifyBlockInfo] No such header in the chain", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "currentHeaderNum", blockChainReader.CurrentHeader().Number) + return fmt.Errorf("[VerifyBlockInfo] header doesn't exist for the received blockInfo at hash: %v", blockInfo.Hash.Hex()) + } + if blockHeader.Number.Cmp(blockInfo.Number) != 0 { + log.Warn("[VerifyBlockInfo] Block Number mismatch", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number) + return fmt.Errorf("[VerifyBlockInfo] chain header number does not match for the received blockInfo at hash: %v", blockInfo.Hash.Hex()) + } + + // Switch block is a v1 block, there is no valid extra to decode, nor its round + if blockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 { + if blockInfo.Round != 0 { + log.Error("[VerifyBlockInfo] Switch block round is not 0", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number) + return fmt.Errorf("[VerifyBlockInfo] switch block round have to be 0") + } + return nil + } + // Check round + var decodedExtraField utils.ExtraFields_v2 + err := utils.DecodeBytesExtraFields(blockHeader.Extra, &decodedExtraField) + if err != nil { + log.Error("[VerifyBlockInfo] Fail to decode extra field", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number) + return err + } + if decodedExtraField.Round != blockInfo.Round { + log.Warn("[VerifyBlockInfo] Block extra round mismatch with blockInfo", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number, "blockRound", decodedExtraField.Round) + return fmt.Errorf("[VerifyBlockInfo] chain block's round does not match from blockInfo at hash: %v and block round: %v, blockInfo Round: %v", blockInfo.Hash.Hex(), decodedExtraField.Round, blockInfo.Round) + } + return nil } @@ -870,7 +904,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert * return haveError } - return x.VerifyBlockInfo(quorumCert.ProposedBlockInfo) + return x.VerifyBlockInfo(blockChainReader, quorumCert.ProposedBlockInfo) } // TODO: Unhold, wait till proposal finalise diff --git a/consensus/tests/verify_blockinfo_test.go b/consensus/tests/verify_blockinfo_test.go new file mode 100644 index 0000000000..9812172e25 --- /dev/null +++ b/consensus/tests/verify_blockinfo_test.go @@ -0,0 +1,63 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" + "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" + "github.com/XinFinOrg/XDPoSChain/params" + "github.com/stretchr/testify/assert" +) + +func TestShouldVerifyBlockInfo(t *testing.T) { + // Block 901 is the first v2 block with round of 1 + blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 901, params.TestXDPoSMockChainConfig, 0) + engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 + + blockInfo := &utils.BlockInfo{ + Hash: currentBlock.Hash(), + Round: utils.Round(1), + Number: currentBlock.Number(), + } + err := engineV2.VerifyBlockInfo(blockchain, blockInfo) + assert.Nil(t, err) + + // Insert another Block, but it won't trigger commit + blockNum := 902 + blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum) + block902 := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 2, blockCoinBase, signer, signFn, nil) + blockchain.InsertBlock(block902) + + blockInfo = &utils.BlockInfo{ + Hash: block902.Hash(), + Round: utils.Round(2), + Number: block902.Number(), + } + err = engineV2.VerifyBlockInfo(blockchain, blockInfo) + assert.Nil(t, err) + + blockInfo = &utils.BlockInfo{ + Hash: currentBlock.Hash(), + Round: utils.Round(2), + Number: currentBlock.Number(), + } + err = engineV2.VerifyBlockInfo(blockchain, blockInfo) + assert.NotNil(t, err) + + blockInfo = &utils.BlockInfo{ + Hash: block902.Hash(), + Round: utils.Round(3), + Number: block902.Number(), + } + err = engineV2.VerifyBlockInfo(blockchain, blockInfo) + assert.NotNil(t, err) + + blockInfo = &utils.BlockInfo{ + Hash: block902.Hash(), + Round: utils.Round(2), + Number: currentBlock.Number(), + } + err = engineV2.VerifyBlockInfo(blockchain, blockInfo) + assert.NotNil(t, err) +}