From cf3a1c3cd19bd6162fda3b51ca683d0ccfc2b014 Mon Sep 17 00:00:00 2001 From: 0g-wh Date: Tue, 15 Jul 2025 06:22:46 +0000 Subject: [PATCH] geth 1 --- core/block_validator.go | 31 ++++++++-------- core/block_validator_test.go | 5 ++- core/blockchain.go | 68 ++++++++++++++++++++++++++++-------- core/blockchain_test.go | 4 +-- core/stateless.go | 5 +-- core/types.go | 3 +- eth/catalyst/api.go | 4 +-- 7 files changed, 84 insertions(+), 36 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index 591e472bc1..30e7962aa9 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -119,13 +119,14 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // ValidateState validates the various changes that happen after a state transition, // such as amount of used gas, the receipt roots and the state root itself. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error { +// Returns a new header with the actual state root instead of comparing with the original header. +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) (*types.Header, error) { if res == nil { - return errors.New("nil ProcessResult value") + return nil, errors.New("nil ProcessResult value") } header := block.Header() if block.GasUsed() != res.GasUsed { - return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed) + return nil, fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed) } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. @@ -135,33 +136,35 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD // everything. rbloom := types.MergeBloom(res.Receipts) if rbloom != header.Bloom { - return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) + return nil, fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } // In stateless mode, return early because the receipt and state root are not // provided through the witness, rather the cross validator needs to return it. if stateless { - return nil + return nil, nil } // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { - return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) + return nil, fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) } // Validate the parsed requests match the expected header value. if header.RequestsHash != nil { reqhash := types.CalcRequestsHash(res.Requests) if reqhash != *header.RequestsHash { - return fmt.Errorf("invalid requests hash (remote: %x local: %x)", *header.RequestsHash, reqhash) + return nil, fmt.Errorf("invalid requests hash (remote: %x local: %x)", *header.RequestsHash, reqhash) } } else if res.Requests != nil { - return errors.New("block has requests before prague fork") + return nil, errors.New("block has requests before prague fork") } - // Validate the state root against the received state root and throw - // an error if they don't match. - if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { - return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error()) - } - return nil + // Get the actual state root from the statedb + actualRoot := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)) + + // Create a new header with the actual state root + newHeader := *header + newHeader.Root = actualRoot + + return &newHeader, nil } // CalcGasLimit computes the gas limit of the next block after parent. It aims diff --git a/core/block_validator_test.go b/core/block_validator_test.go index fcc99effd0..4a12c6b24a 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -210,7 +210,10 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { t.Fatalf("post-block %d: unexpected result returned: %v", i, result) case <-time.After(25 * time.Millisecond): } - chain.InsertBlockWithoutSetHead(postBlocks[i], false) + _, _, err := chain.InsertBlockWithoutSetHead(postBlocks[i], false) + if err != nil { + t.Errorf("Failed to insert block: %v", err) + } } // Verify the blocks with pre-merge blocks and post-merge blocks diff --git a/core/blockchain.go b/core/blockchain.go index 2290b6d3cd..56fb22df1f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2047,12 +2047,16 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s ptime := time.Since(pstart) vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, res, false); err != nil { + newHeader, err := bc.validator.ValidateState(block, statedb, res, false) + if err != nil { bc.reportBlock(block, res, err) return nil, err } vtime := time.Since(vstart) + // Create a new block with the updated header + newBlock := types.NewBlockWithHeader(newHeader).WithBody(*block.Body()) + // If witnesses was generated and stateless self-validation requested, do // that now. Self validation should *never* run in production, it's more of // a tight integration to enable running *all* consensus tests through the @@ -2060,25 +2064,25 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s // various invalid chain states/behaviors being contained in those tests. xvstart := time.Now() if witness := statedb.Witness(); witness != nil && bc.cfg.VmConfig.StatelessSelfValidation { - log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash()) + log.Warn("Running stateless self-validation", "block", newBlock.Number(), "hash", newBlock.Hash()) // Remove critical computed fields from the block to force true recalculation - context := block.Header() + context := newBlock.Header() context.Root = common.Hash{} context.ReceiptHash = common.Hash{} - task := types.NewBlockWithHeader(context).WithBody(*block.Body()) + task := types.NewBlockWithHeader(context).WithBody(*newBlock.Body()) // Run the stateless self-cross-validation crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, bc.cfg.VmConfig, task, witness) if err != nil { return nil, fmt.Errorf("stateless self-validation failed: %v", err) } - if crossStateRoot != block.Root() { - return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root()) + if crossStateRoot != newBlock.Root() { + return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, newBlock.Root()) } - if crossReceiptRoot != block.ReceiptHash() { - return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash()) + if crossReceiptRoot != newBlock.ReceiptHash() { + return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, newBlock.ReceiptHash()) } } xvtime := time.Since(xvstart) @@ -2109,9 +2113,9 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s ) if !setHead { // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, res.Receipts, statedb) + err = bc.writeBlockWithState(newBlock, res.Receipts, statedb) } else { - status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false) + status, err = bc.writeBlockAndSetHead(newBlock, res.Receipts, res.Logs, statedb, false) } if err != nil { return nil, err @@ -2509,14 +2513,50 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error // The key difference between the InsertChain is it won't do the canonical chain // updating. It relies on the additional SetCanonical call to finalize the entire // procedure. -func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) { +// Returns the new header with actual state root and witness. +func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*types.Header, *stateless.Witness, error) { if !bc.chainmu.TryLock() { - return nil, errChainStopped + return nil, nil, errChainStopped } defer bc.chainmu.Unlock() - witness, _, err := bc.insertChain(types.Blocks{block}, false, makeWitness) - return witness, err + // Process the block to get the new header with actual state root + parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1) + if parent == nil { + return nil, nil, consensus.ErrUnknownAncestor + } + + statedb, err := state.New(parent.Root, bc.statedb) + if err != nil { + return nil, nil, err + } + + res, err := bc.processor.Process(block, statedb, bc.cfg.VmConfig) + if err != nil { + return nil, nil, err + } + + newHeader, err := bc.validator.ValidateState(block, statedb, res, false) + if err != nil { + return nil, nil, err + } + + // Write the block with state + err = bc.writeBlockWithState(block, res.Receipts, statedb) + if err != nil { + return nil, nil, err + } + + // Generate witness if requested + var witness *stateless.Witness + if makeWitness && bc.chainConfig.IsByzantium(block.Number()) { + witness, err = stateless.NewWitness(block.Header(), bc) + if err != nil { + return nil, nil, err + } + } + + return newHeader, witness, nil } // SetCanonical rewinds the chain to set the new head block as the specified diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 5e768fccdf..fc6c0cfc6c 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -165,7 +165,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.reportBlock(block, res, err) return err } - err = blockchain.validator.ValidateState(block, statedb, res, false) + _, err = blockchain.validator.ValidateState(block, statedb, res, false) if err != nil { blockchain.reportBlock(block, res, err) return err @@ -3456,7 +3456,7 @@ func testSetCanonical(t *testing.T, scheme string) { gen.AddTx(tx) }) for _, block := range side { - _, err := chain.InsertBlockWithoutSetHead(block, false) + _, _, err := chain.InsertBlockWithoutSetHead(block, false) if err != nil { t.Fatalf("Failed to insert into chain: %v", err) } diff --git a/core/stateless.go b/core/stateless.go index d21a62b4a5..f59996769e 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -70,11 +70,12 @@ func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *typ if err != nil { return common.Hash{}, common.Hash{}, err } - if err = validator.ValidateState(block, db, res, true); err != nil { + newHeader, err := validator.ValidateState(block, db, res, true) + if err != nil { return common.Hash{}, common.Hash{}, err } // Almost everything validated, but receipt and state root needs to be returned receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) - stateRoot := db.IntermediateRoot(config.IsEIP158(block.Number())) + stateRoot := newHeader.Root return stateRoot, receiptRoot, nil } diff --git a/core/types.go b/core/types.go index bed20802ab..2596168425 100644 --- a/core/types.go +++ b/core/types.go @@ -32,7 +32,8 @@ type Validator interface { ValidateBody(block *types.Block) error // ValidateState validates the given statedb and optionally the process result. - ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) error + // Returns a new header with the actual state root instead of comparing with the original header. + ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) (*types.Header, error) } // Prefetcher is an interface for pre-caching transaction signatures and state. diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 409899d582..428089d905 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -748,7 +748,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe return engine.PayloadStatusV1{Status: engine.ACCEPTED}, nil } log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number()) - proofs, err := api.eth.BlockChain().InsertBlockWithoutSetHead(block, witness) + newHeader, proofs, err := api.eth.BlockChain().InsertBlockWithoutSetHead(block, witness) if err != nil { log.Warn("NewPayload: inserting block failed", "error", err) @@ -759,7 +759,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe return api.invalid(err, parent.Header()), nil } - hash := block.Hash() + hash := newHeader.Hash() // If witness collection was requested, inject that into the result too var ow *hexutil.Bytes