From 85f08c7732764bf887d4b3b1b7003e5cb998c7cb Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Sat, 26 Jul 2025 18:18:50 +0800 Subject: [PATCH] eth: skip VerifyHeader in traceBlock to fix #1185 (#1265) --- consensus/XDPoS/XDPoS.go | 4 +- consensus/XDPoS/engines/engine_v1/engine.go | 30 +++++------- consensus/consensus.go | 2 +- consensus/ethash/consensus.go | 2 +- .../engine_v2_tests/verify_header_test.go | 46 +++++++++---------- core/blockchain.go | 2 +- core/blockchain_test.go | 4 +- eth/api_tracer.go | 8 ++-- eth/handler.go | 2 +- 9 files changed, 47 insertions(+), 53 deletions(-) diff --git a/consensus/XDPoS/XDPoS.go b/consensus/XDPoS/XDPoS.go index 5a66194a06..856021c632 100644 --- a/consensus/XDPoS/XDPoS.go +++ b/consensus/XDPoS/XDPoS.go @@ -190,12 +190,12 @@ func (x *XDPoS) Author(header *types.Header) (common.Address, error) { } // VerifyHeader checks whether a header conforms to the consensus rules. -func (x *XDPoS) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool, verifyCheckpoint bool) error { +func (x *XDPoS) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { switch x.config.BlockConsensusVersion(header.Number, header.Extra, ExtraFieldCheck) { case params.ConsensusEngineVersion2: return x.EngineV2.VerifyHeader(chain, header, fullVerify) default: // Default "v1" - return x.EngineV1.VerifyHeader(chain, header, fullVerify, verifyCheckpoint) + return x.EngineV1.VerifyHeader(chain, header, fullVerify) } } diff --git a/consensus/XDPoS/engines/engine_v1/engine.go b/consensus/XDPoS/engines/engine_v1/engine.go index 81f922852c..da8188e377 100644 --- a/consensus/XDPoS/engines/engine_v1/engine.go +++ b/consensus/XDPoS/engines/engine_v1/engine.go @@ -112,8 +112,8 @@ func (x *XDPoS_v1) Author(header *types.Header) (common.Address, error) { } // VerifyHeader checks whether a header conforms to the consensus rules. -func (x *XDPoS_v1) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool, verifyCheckpoint bool) error { - return x.verifyHeaderWithCache(chain, header, nil, fullVerify, verifyCheckpoint) +func (x *XDPoS_v1) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { + return x.verifyHeaderWithCache(chain, header, nil, fullVerify) } // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The @@ -122,7 +122,7 @@ func (x *XDPoS_v1) VerifyHeader(chain consensus.ChainReader, header *types.Heade func (x *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool, abort <-chan struct{}, results chan<- error) { go func() { for i, header := range headers { - err := x.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i], true) + err := x.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i]) select { case <-abort: @@ -133,12 +133,12 @@ func (x *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.H }() } -func (x *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool, verifyCheckpoint bool) error { +func (x *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { _, check := x.verifiedHeaders.Get(header.Hash()) if check { return nil } - err := x.verifyHeader(chain, header, parents, fullVerify, verifyCheckpoint) + err := x.verifyHeader(chain, header, parents, fullVerify) if err == nil { x.verifiedHeaders.Add(header.Hash(), struct{}{}) } @@ -149,7 +149,7 @@ func (x *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *ty // caller may optionally pass in a batch of parents (ascending order) to avoid // looking those up from the database. This is useful for concurrently verifying // a batch of new headers. -func (x *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool, verifyCheckpoint bool) error { +func (x *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { // If we're running a engine faking, accept any block as valid if x.config.SkipV1Validation { return nil @@ -207,14 +207,14 @@ func (x *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Heade return utils.ErrInvalidUncleHash } // All basic checks passed, verify cascading fields - return x.verifyCascadingFields(chain, header, parents, fullVerify, verifyCheckpoint) + return x.verifyCascadingFields(chain, header, parents, fullVerify) } // verifyCascadingFields verifies all the header fields that are not standalone, // rather depend on a batch of previous headers. The caller may optionally pass // in a batch of parents (ascending order) to avoid looking those up from the // database. This is useful for concurrently verifying a batch of new headers. -func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool, verifyCheckpoint bool) error { +func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { // The genesis block is the always valid dead-end number := header.Number.Uint64() if number == 0 { @@ -253,7 +253,7 @@ func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty } signers := snap.GetSigners() - err = x.checkSignersOnCheckpoint(chain, header, signers, verifyCheckpoint) + err = x.checkSignersOnCheckpoint(chain, header, signers) if err == nil { return x.verifySeal(chain, header, parents, fullVerify) } @@ -262,7 +262,7 @@ func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty if err != nil { return err } - err = x.checkSignersOnCheckpoint(chain, header, signers, verifyCheckpoint) + err = x.checkSignersOnCheckpoint(chain, header, signers) if err == nil { return x.verifySeal(chain, header, parents, fullVerify) } @@ -270,7 +270,7 @@ func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty return err } -func (x *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header *types.Header, signers []common.Address, verifyCheckpoint bool) error { +func (x *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header *types.Header, signers []common.Address) error { number := header.Number.Uint64() // ignore signerCheck at checkpoint block. if common.IsIgnoreSignerCheckBlock(number) { @@ -301,12 +301,6 @@ func (x *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header signers = removePenaltiesFromBlock(chain, signers, number-uint64(i)*x.config.Epoch) } } - - // fix issue #1185 - if !verifyCheckpoint { - return nil - } - extraSuffix := len(header.Extra) - utils.ExtraSeal masternodesFromCheckpointHeader := common.ExtractAddressFromBytes(header.Extra[utils.ExtraVanity:extraSuffix]) validSigners := utils.CompareSignersLists(masternodesFromCheckpointHeader, signers) @@ -496,7 +490,7 @@ func (x *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash com // If we're at block zero, make a snapshot if number == 0 { genesis := chain.GetHeaderByNumber(0) - if err := x.VerifyHeader(chain, genesis, true, true); err != nil { + if err := x.VerifyHeader(chain, genesis, true); err != nil { return nil, err } signers := make([]common.Address, (len(genesis.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength) diff --git a/consensus/consensus.go b/consensus/consensus.go index 738c410e4b..080b22406f 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -59,7 +59,7 @@ type Engine interface { // VerifyHeader checks whether a header conforms to the consensus rules of a // given engine. Verifying the seal may be done optionally here, or explicitly // via the VerifySeal method. - VerifyHeader(chain ChainReader, header *types.Header, fullVerify bool, verifyCheckpoint bool) error + VerifyHeader(chain ChainReader, header *types.Header, fullVerify bool) error // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // concurrently. The method returns a quit channel to abort the operations and diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 2f018fa1f6..2bcfd6e0b6 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -68,7 +68,7 @@ func (ethash *Ethash) Author(header *types.Header) (common.Address, error) { // VerifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum ethash engine. -func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool, verifyCheckpoint bool) error { +func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { // If we're running a full engine faking, accept any input as valid if ethash.config.PowMode == ModeFullFake { return nil diff --git a/consensus/tests/engine_v2_tests/verify_header_test.go b/consensus/tests/engine_v2_tests/verify_header_test.go index 1c77e44e1f..1237c49914 100644 --- a/consensus/tests/engine_v2_tests/verify_header_test.go +++ b/consensus/tests/engine_v2_tests/verify_header_test.go @@ -33,77 +33,77 @@ func TestShouldVerifyBlock(t *testing.T) { // Happy path happyPathHeader := blockchain.GetBlockByNumber(901).Header() - err = adaptor.VerifyHeader(blockchain, happyPathHeader, true, true) + err = adaptor.VerifyHeader(blockchain, happyPathHeader, true) assert.Nil(t, err) // Unhappy path // Verify non-epoch switch block - err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(902).Header(), true, true) + err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(902).Header(), true) assert.Nil(t, err) nonEpochSwitchWithValidators := blockchain.GetBlockByNumber(902).Header() nonEpochSwitchWithValidators.Validators = acc1Addr.Bytes() - err = adaptor.VerifyHeader(blockchain, nonEpochSwitchWithValidators, true, true) + err = adaptor.VerifyHeader(blockchain, nonEpochSwitchWithValidators, true) assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err) noValidatorBlock := blockchain.GetBlockByNumber(902).Header() noValidatorBlock.Validator = []byte{} - err = adaptor.VerifyHeader(blockchain, noValidatorBlock, true, true) + err = adaptor.VerifyHeader(blockchain, noValidatorBlock, true) assert.Equal(t, consensus.ErrNoValidatorSignatureV2, err) blockFromFuture := blockchain.GetBlockByNumber(902).Header() blockFromFuture.Time = big.NewInt(time.Now().Unix() + 10000) - err = adaptor.VerifyHeader(blockchain, blockFromFuture, true, true) + err = adaptor.VerifyHeader(blockchain, blockFromFuture, true) assert.Equal(t, consensus.ErrFutureBlock, err) invalidQcBlock := blockchain.GetBlockByNumber(902).Header() invalidQcBlock.Extra = []byte{2} - err = adaptor.VerifyHeader(blockchain, invalidQcBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidQcBlock, true) assert.Equal(t, utils.ErrInvalidV2Extra, err) // Epoch switch invalidAuthNonceBlock := blockchain.GetBlockByNumber(901).Header() invalidAuthNonceBlock.Nonce = types.BlockNonce{123} - err = adaptor.VerifyHeader(blockchain, invalidAuthNonceBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidAuthNonceBlock, true) assert.Equal(t, utils.ErrInvalidVote, err) emptyValidatorsBlock := blockchain.GetBlockByNumber(901).Header() emptyValidatorsBlock.Validators = []byte{} - err = adaptor.VerifyHeader(blockchain, emptyValidatorsBlock, true, true) + err = adaptor.VerifyHeader(blockchain, emptyValidatorsBlock, true) assert.Equal(t, utils.ErrEmptyEpochSwitchValidators, err) invalidValidatorsSignerBlock := blockchain.GetBlockByNumber(901).Header() invalidValidatorsSignerBlock.Validators = []byte{123} - err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true) assert.Equal(t, utils.ErrInvalidCheckpointSigners, err) // non-epoch switch invalidValidatorsExistBlock := blockchain.GetBlockByNumber(902).Header() invalidValidatorsExistBlock.Validators = []byte{123} - err = adaptor.VerifyHeader(blockchain, invalidValidatorsExistBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidValidatorsExistBlock, true) assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err) invalidPenaltiesExistBlock := blockchain.GetBlockByNumber(902).Header() invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20) - err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true) assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err) merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb123" parentNotExistBlock := blockchain.GetBlockByNumber(901).Header() parentNotExistBlock.ParentHash = common.HexToHash(merkleRoot) - err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true, true) + err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true) assert.Equal(t, consensus.ErrUnknownAncestor, err) block901 := blockchain.GetBlockByNumber(901).Header() tooFastMinedBlock := blockchain.GetBlockByNumber(902).Header() tooFastMinedBlock.Time = big.NewInt(block901.Time.Int64() - 10) - err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true, true) + err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true) assert.Equal(t, utils.ErrInvalidTimestamp, err) invalidDifficultyBlock := blockchain.GetBlockByNumber(902).Header() invalidDifficultyBlock.Difficulty = big.NewInt(2) - err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true) assert.Equal(t, utils.ErrInvalidDifficulty, err) // Create an invalid QC round @@ -144,7 +144,7 @@ func TestShouldVerifyBlock(t *testing.T) { invalidRoundBlock := blockchain.GetBlockByNumber(902).Header() invalidRoundBlock.Extra = extraInBytes - err = adaptor.VerifyHeader(blockchain, invalidRoundBlock, true, true) + err = adaptor.VerifyHeader(blockchain, invalidRoundBlock, true) assert.Equal(t, utils.ErrRoundInvalid, err) // Not valid validator @@ -152,19 +152,19 @@ func TestShouldVerifyBlock(t *testing.T) { notQualifiedSigner, notQualifiedSignFn, err := getSignerAndSignFn(voterKey) assert.Nil(t, err) sealHeader(blockchain, coinbaseValidatorMismatchBlock, notQualifiedSigner, notQualifiedSignFn) - err = adaptor.VerifyHeader(blockchain, coinbaseValidatorMismatchBlock, true, true) + err = adaptor.VerifyHeader(blockchain, coinbaseValidatorMismatchBlock, true) assert.Equal(t, utils.ErrCoinbaseAndValidatorMismatch, err) // Make the validators not legit by adding something to the validator validatorsNotLegit := blockchain.GetBlockByNumber(901).Header() validatorsNotLegit.Validators = append(validatorsNotLegit.Validators, acc1Addr[:]...) - err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true, true) + err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true) assert.Equal(t, utils.ErrValidatorsNotLegit, err) // Make the penalties not legit by adding something to the penalty penaltiesNotLegit := blockchain.GetBlockByNumber(901).Header() penaltiesNotLegit.Penalties = append(penaltiesNotLegit.Penalties, acc1Addr[:]...) - err = adaptor.VerifyHeader(blockchain, penaltiesNotLegit, true, true) + err = adaptor.VerifyHeader(blockchain, penaltiesNotLegit, true) assert.Equal(t, utils.ErrPenaltiesNotLegit, err) } @@ -215,7 +215,7 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) { // after 910 require 4 signs, but we only give 3 signs block912 := blockchain.GetBlockByNumber(912).Header() block912.Extra = extraInBytes - err = adaptor.VerifyHeader(blockchain, block912, true, true) + err = adaptor.VerifyHeader(blockchain, block912, true) assert.Equal(t, utils.ErrInvalidQCSignatures, err) @@ -254,7 +254,7 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) { // QC contains 910, so it requires 3 signatures, not use block number to determine which config to use block911 := blockchain.GetBlockByNumber(911).Header() block911.Extra = extraInBytes - err = adaptor.VerifyHeader(blockchain, block911, true, true) + err = adaptor.VerifyHeader(blockchain, block911, true) // error ErrValidatorNotWithinMasternodes means verifyQC is passed and move to next verification process assert.Equal(t, utils.ErrValidatorNotWithinMasternodes, err) @@ -298,7 +298,7 @@ func TestConfigSwitchOnDifferentMasternodeCount(t *testing.T) { adaptor.EngineV2.SetNewRoundFaker(blockchain, 899, false) - err = adaptor.VerifyHeader(blockchain, header1800, true, true) + err = adaptor.VerifyHeader(blockchain, header1800, true) // error ErrValidatorNotWithinMasternodes means verifyQC is passed and move to next verification process assert.Equal(t, utils.ErrValidatorNotWithinMasternodes, err) @@ -352,7 +352,7 @@ func TestConfigSwitchOnDifferentMindPeriod(t *testing.T) { block911 := blockchain.GetBlockByNumber(911).Header() block911.Extra = extraInBytes block911.Time = big.NewInt(blockchain.GetBlockByNumber(910).Time().Int64() + 2) //2 is previous config, should get the right config from round - err = adaptor.VerifyHeader(blockchain, block911, true, true) + err = adaptor.VerifyHeader(blockchain, block911, true) assert.Equal(t, utils.ErrInvalidTimestamp, err) } @@ -403,7 +403,7 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) { headerWithDuplicatedSignatures := currentBlock.Header() headerWithDuplicatedSignatures.Extra = extraInBytes // Happy path - err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true, true) + err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true) assert.Equal(t, utils.ErrInvalidQCSignatures, err) } diff --git a/core/blockchain.go b/core/blockchain.go index 7a8a884617..675278d05a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1988,7 +1988,7 @@ func (bc *BlockChain) PrepareBlock(block *types.Block) (err error) { log.Debug("Stop prepare a block because inserting", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator) return nil } - err = bc.engine.VerifyHeader(bc, block.Header(), false, true) + err = bc.engine.VerifyHeader(bc, block.Header(), false) if err != nil { return err } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 1821dd4ce1..319394124a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -140,7 +140,7 @@ func printChain(bc *BlockChain) { func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { for _, block := range chain { // Try and process the block - err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true, true) + err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true) if err == nil { err = blockchain.validator.ValidateBody(block) } @@ -178,7 +178,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error { for _, header := range chain { // Try and validate the header - if err := blockchain.engine.VerifyHeader(blockchain, header, false, true); err != nil { + if err := blockchain.engine.VerifyHeader(blockchain, header, false); err != nil { return err } // Manually insert the header into the database, but don't reorganise (allows subsequent testing) diff --git a/eth/api_tracer.go b/eth/api_tracer.go index e476e7e162..b45c1a472f 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -433,10 +433,10 @@ func (api *DebugAPI) TraceBlockFromFile(ctx context.Context, file string, config // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requestd tracer. func (api *DebugAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { - // skip verify signer list on checkpoint block to fix #1185 - if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true, false); err != nil { - return nil, err - } + // Skip VerifyHeader to fix #1185 + // if err := api.eth.engine.VerifyHeader(api.eth.blockchain, block.Header(), true); err != nil { + // return nil, err + // } // Create the parent state database parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { diff --git a/eth/handler.go b/eth/handler.go index bcbc0971b0..421044c21e 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -211,7 +211,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne manager.downloader = downloader.New(chaindb, manager.eventMux, blockchain, nil, manager.removePeer, handleProposedBlock) validator := func(header *types.Header) error { - return engine.VerifyHeader(blockchain, header, true, true) + return engine.VerifyHeader(blockchain, header, true) } heighter := func() uint64 {