mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
verify headers shall use parent block if not present in the chain (#77)
This commit is contained in:
parent
cb67e8e26a
commit
0241d40699
4 changed files with 88 additions and 19 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue