verify headers shall use parent block if not present in the chain (#77)

This commit is contained in:
Jerome 2022-04-01 17:11:04 +11:00 committed by GitHub
parent cb67e8e26a
commit 0241d40699
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 19 deletions

View file

@ -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) // 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 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 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 { 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) blockHeader = blockChainReader.GetHeaderByHash(blockInfo.Hash)
return fmt.Errorf("[VerifyBlockInfo] header doesn't exist for the received blockInfo at hash: %v", blockInfo.Hash.Hex()) 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 { 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) 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()) return fmt.Errorf("[VerifyBlockInfo] chain header number does not match for the received blockInfo at hash: %v", blockInfo.Hash.Hex())
@ -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) log.Error("[verifyQC] gap number mismatch", "BlockInfoHash", quorumCert.ProposedBlockInfo.Hash, "Gap", quorumCert.GapNumber, "GapShouldBe", gapNumber)
return fmt.Errorf("gap number mismatch %v", quorumCert) 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 // Update local QC variables including highestQC & lockQuorumCert, as well as commit the blocks that satisfy the algorithm requirements

View file

@ -77,7 +77,7 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote)
return nil return nil
} }
err := x.VerifyBlockInfo(chain, voteMsg.ProposedBlockInfo) err := x.VerifyBlockInfo(chain, voteMsg.ProposedBlockInfo, nil)
if err != nil { if err != nil {
return err return err
} }

View file

@ -20,7 +20,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(1), Round: utils.Round(1),
Number: currentBlock.Number(), Number: currentBlock.Number(),
} }
err := engineV2.VerifyBlockInfo(blockchain, blockInfo) err := engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.Nil(t, err) assert.Nil(t, err)
// Insert another Block, but it won't trigger commit // Insert another Block, but it won't trigger commit
@ -35,7 +35,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(2), Round: utils.Round(2),
Number: block902.Number(), Number: block902.Number(),
} }
err = engineV2.VerifyBlockInfo(blockchain, blockInfo) err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.Nil(t, err) assert.Nil(t, err)
blockInfo = &utils.BlockInfo{ blockInfo = &utils.BlockInfo{
@ -43,7 +43,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(2), Round: utils.Round(2),
Number: currentBlock.Number(), Number: currentBlock.Number(),
} }
err = engineV2.VerifyBlockInfo(blockchain, blockInfo) err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err) assert.NotNil(t, err)
blockInfo = &utils.BlockInfo{ blockInfo = &utils.BlockInfo{
@ -51,7 +51,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(3), Round: utils.Round(3),
Number: block902.Number(), Number: block902.Number(),
} }
err = engineV2.VerifyBlockInfo(blockchain, blockInfo) err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err) assert.NotNil(t, err)
blockInfo = &utils.BlockInfo{ blockInfo = &utils.BlockInfo{
@ -59,6 +59,6 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(2), Round: utils.Round(2),
Number: currentBlock.Number(), Number: currentBlock.Number(),
} }
err = engineV2.VerifyBlockInfo(blockchain, blockInfo) err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err) assert.NotNil(t, err)
} }

View file

@ -235,9 +235,6 @@ func TestShouldVerifyHeaders(t *testing.T) {
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, 0) blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, 0)
adaptor := blockchain.Engine().(*XDPoS.XDPoS) adaptor := blockchain.Engine().(*XDPoS.XDPoS)
// var results <-chan error
// var abort <-chan struct{}
// Happy path // Happy path
var happyPathHeaders []*types.Header var happyPathHeaders []*types.Header
happyPathHeaders = append(happyPathHeaders, blockchain.GetBlockByNumber(899).Header(), blockchain.GetBlockByNumber(900).Header(), blockchain.GetBlockByNumber(901).Header(), blockchain.GetBlockByNumber(902).Header()) happyPathHeaders = append(happyPathHeaders, blockchain.GetBlockByNumber(899).Header(), blockchain.GetBlockByNumber(900).Header(), blockchain.GetBlockByNumber(901).Header(), blockchain.GetBlockByNumber(902).Header())
@ -245,10 +242,72 @@ func TestShouldVerifyHeaders(t *testing.T) {
var fullVerifies []bool var fullVerifies []bool
fullVerifies = append(fullVerifies, false, true, true, false) fullVerifies = append(fullVerifies, false, true, true, false)
_, results := adaptor.VerifyHeaders(blockchain, happyPathHeaders, fullVerifies) _, results := adaptor.VerifyHeaders(blockchain, happyPathHeaders, fullVerifies)
select { var verified []bool
case result := <-results: for {
assert.Nil(t, result) select {
case <-time.After(time.Duration(2) * time.Second): // It should be very fast to verify headers case result := <-results:
t.Fatalf("Taking too long to verify headers") 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")
}
}
} }
} }