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)
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())
@ -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

View file

@ -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
}

View file

@ -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
@ -35,7 +35,7 @@ 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{
@ -43,7 +43,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
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{
@ -51,7 +51,7 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
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{
@ -59,6 +59,6 @@ func TestShouldVerifyBlockInfo(t *testing.T) {
Round: utils.Round(2),
Number: currentBlock.Number(),
}
err = engineV2.VerifyBlockInfo(blockchain, blockInfo)
err = engineV2.VerifyBlockInfo(blockchain, blockInfo, nil)
assert.NotNil(t, err)
}

View file

@ -235,9 +235,6 @@ 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())
@ -245,10 +242,72 @@ func TestShouldVerifyHeaders(t *testing.T) {
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")
}
}
}
}