Skip to content

Commit

Permalink
verify headers shall use parent block if not present in the chain (et…
Browse files Browse the repository at this point in the history
  • Loading branch information
wjrjerome authored Apr 1, 2022
1 parent cb67e8e commit 0241d40
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 19 deletions.
20 changes: 15 additions & 5 deletions consensus/XDPoS/engines/engine_v2/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,16 +689,25 @@ func (x *XDPoS_v2) ProposedBlockHandler(chain consensus.ChainReader, blockHeader
*/

// 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(blockChainReader consensus.ChainReader, blockInfo *utils.BlockInfo) error {
func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, blockInfo *utils.BlockInfo, blockHeader *types.Header) 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())
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())
}
} else {
// If blockHeader present, then its value shall consistent with what's provided in the blockInfo
if blockHeader.Hash() != blockInfo.Hash {
log.Warn("[VerifyBlockInfo] BlockHeader and blockInfo mismatch", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockHeaderHash", blockHeader.Hash())
return fmt.Errorf("[VerifyBlockInfo] Provided blockheader does not match what's in the blockInfo")
}
}

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())
Expand Down Expand Up @@ -792,7 +801,8 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
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)

return x.VerifyBlockInfo(blockChainReader, quorumCert.ProposedBlockInfo, parentHeader)
}

// Update local QC variables including highestQC & lockQuorumCert, as well as commit the blocks that satisfy the algorithm requirements
Expand Down
2 changes: 1 addition & 1 deletion consensus/XDPoS/engines/engine_v2/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote)
return nil
}

err := x.VerifyBlockInfo(chain, voteMsg.ProposedBlockInfo)
err := x.VerifyBlockInfo(chain, voteMsg.ProposedBlockInfo, nil)
if err != nil {
return err
}
Expand Down
10 changes: 5 additions & 5 deletions consensus/tests/engine_v2_tests/verify_blockinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(1),
Number: currentBlock.Number(),
}
err := engineV2.VerifyBlockInfo(blockchain, blockInfo)
err := engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.Nil(t, err)

// Insert another Block, but it won't trigger commit
Expand All @@ -35,30 +35,30 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(2),
Number: block902.Number(),
}
err = engineV2.VerifyBlockInfo(blockchain, blockInfo)
err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.Nil(t, err)

blockInfo = &utils.BlockInfo{
Hash: currentBlock.Hash(),
Round: utils.Round(2),
Number: currentBlock.Number(),
}
err = engineV2.VerifyBlockInfo(blockchain, blockInfo)
err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err)

blockInfo = &utils.BlockInfo{
Hash: block902.Hash(),
Round: utils.Round(3),
Number: block902.Number(),
}
err = engineV2.VerifyBlockInfo(blockchain, blockInfo)
err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err)

blockInfo = &utils.BlockInfo{
Hash: block902.Hash(),
Round: utils.Round(2),
Number: currentBlock.Number(),
}
err = engineV2.VerifyBlockInfo(blockchain, blockInfo)
err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err)
}
75 changes: 67 additions & 8 deletions consensus/tests/engine_v2_tests/verify_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,20 +235,79 @@ func TestShouldVerifyHeaders(t *testing.T) {
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, 0)
adaptor := blockchain.Engine().(*XDPoS.XDPoS)

// var results <-chan error
// var abort <-chan struct{}

// Happy path
var happyPathHeaders []*types.Header
happyPathHeaders = append(happyPathHeaders, blockchain.GetBlockByNumber(899).Header(), blockchain.GetBlockByNumber(900).Header(), blockchain.GetBlockByNumber(901).Header(), blockchain.GetBlockByNumber(902).Header())
// Randomly set full verify
var fullVerifies []bool
fullVerifies = append(fullVerifies, false, true, true, false)
_, results := adaptor.VerifyHeaders(blockchain, happyPathHeaders, fullVerifies)
select {
case result := <-results:
assert.Nil(t, result)
case <-time.After(time.Duration(2) * time.Second): // It should be very fast to verify headers
t.Fatalf("Taking too long to verify headers")
var verified []bool
for {
select {
case result := <-results:
if result != nil {
panic("Error received while verifying headers")
}
verified = append(verified, true)
case <-time.After(time.Duration(5) * time.Second): // It should be very fast to verify headers
if len(verified) == len(happyPathHeaders) {
return
} else {
panic("Suppose to have verified 3 block headers")
}
}
}
}

func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
assert.Nil(t, err)
configString := string(b)

var config params.ChainConfig
err = json.Unmarshal([]byte(configString), &config)
assert.Nil(t, err)
// Enable verify
config.XDPoS.V2.SkipV2Validation = false
// Skip the mining time validation by set mine time to 0
config.XDPoS.V2.MinePeriod = 0
// Block 901 is the first v2 block with round of 1
blockchain, _, block910, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, 0)
adaptor := blockchain.Engine().(*XDPoS.XDPoS)

var headersTobeVerified []*types.Header

// Create block 911 but don't write into DB
blockNumber := 911
roundNumber := int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
block911 := CreateBlock(blockchain, &config, block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil)

// Create block 912 and not write into DB as well
blockNumber = 912
roundNumber = int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
block912 := CreateBlock(blockchain, &config, block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil)

headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header())
// Randomly set full verify
var fullVerifies []bool
fullVerifies = append(fullVerifies, true, true, true)
_, results := adaptor.VerifyHeaders(blockchain, headersTobeVerified, fullVerifies)

var verified []bool
for {
select {
case result := <-results:
if result != nil {
panic("Error received while verifying headers")
}
verified = append(verified, true)
case <-time.After(time.Duration(5) * time.Second): // It should be very fast to verify headers
if len(verified) == len(headersTobeVerified) {
return
} else {
panic("Suppose to have verified 3 block headers")
}
}
}
}

0 comments on commit 0241d40

Please sign in to comment.