diff --git a/core/parallel_state_processor.go b/core/parallel_state_processor.go index bdc95d19ac..0f021bdff0 100644 --- a/core/parallel_state_processor.go +++ b/core/parallel_state_processor.go @@ -24,10 +24,8 @@ type ProcessResultWithMetrics struct { ExecTime time.Duration PostProcessTime time.Duration - // Preimages holds the SHA3 preimages seen by the VM across the whole block - // (the pre/post-transaction system executions and every transaction). They - // are gathered here so the caller can install them into the state - // transition without the execution helpers needing a reference to it. + // Preimages holds the SHA3 preimages recorded during the execution of + // the block. Preimages map[common.Hash][]byte } @@ -119,12 +117,8 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar p.chain.Engine().Finalize(p.chain, block.Header(), evm.StateDB, block.Body(), uint32(lastBALIdx), postBAL) - // Gather the SHA3 preimages seen across the block. postTxState is a copy of - // the block statedb taken after pre-transaction processing, so its set - // already covers both the pre-tx system execution and the post-tx execution - // (PostExecution + Finalize) performed above; the per-transaction sets are - // carried on each result. The merged set is returned to the caller, which - // owns the state transition and installs them there. + // Gather preimages from block execution. postTxState contains + // preimages from pre/post tx system contract execution. preimages := make(map[common.Hash][]byte) for hash, preimage := range postTxState.Preimages() { preimages[hash] = preimage @@ -177,8 +171,7 @@ type txExecResult struct { blockAccessList *bal.ConstructionBlockAccessList - // preimages holds the SHA3 preimages recorded while executing this - // transaction against its own statedb copy. + // holds preimages recorded during execution of the tx preimages map[common.Hash][]byte } @@ -288,6 +281,7 @@ func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transactio execGas: receipt.GasUsed, txRegular: gp.cumulativeRegular, txState: gp.cumulativeState, + preimages: db.Preimages(), blockAccessList: txBAL, } } @@ -334,9 +328,6 @@ func (p *ParallelStateProcessor) Process(block *types.Block, stateTransition *st workers.Go(func() error { prestate = prestate.WithReader(state.NewReaderWithAccessList(statedb.Reader(), prepared, balIdx)) res := p.execTx(block, tx, balIdx, prestate, signer) - // Carry this transaction's preimages on the result; they're merged - // into the block-level set in prepareExecResult. - res.preimages = prestate.Preimages() txResCh <- *res return nil }) @@ -348,10 +339,8 @@ func (p *ParallelStateProcessor) Process(block *types.Block, stateTransition *st if res.ProcessResult.Error != nil { return nil, res.ProcessResult.Error } - // Install the block's preimages into the state transition so they're - // persisted when the block is committed. Process is the sole owner of the - // state transition, keeping the execution helpers free of it. - stateTransition.AddPreimages(res.Preimages) + + stateTransition.SetPreimages(res.Preimages) // TODO: remove preprocess metric ? res.PreProcessTime = tPreprocess return res, nil diff --git a/core/state/bal_state_transition.go b/core/state/bal_state_transition.go index 07b62258c9..0c775bdbee 100644 --- a/core/state/bal_state_transition.go +++ b/core/state/bal_state_transition.go @@ -49,8 +49,7 @@ type BALStateTransition struct { // preimages holds the SHA3 preimages seen by the VM across the whole block: // the pre/post-transaction system executions and every individual - // transaction execution. It is populated once via AddPreimages after the - // parallel execution has been collected. + // transaction execution. It is populated once via SetPreimages. preimages map[common.Hash][]byte metrics BALStateTransitionMetrics @@ -540,23 +539,13 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash { return s.rootHash } -// AddPreimages merges a set of SHA3 preimages into the block-level preimage -// set, leaving any hash already present untouched (mirroring the -// first-write-wins behaviour of StateDB.AddPreimage). The parallel processor -// collects the preimages from the per-transaction and pre/post-transaction -// executions and installs them here once execution has completed. -func (s *BALStateTransition) AddPreimages(preimages map[common.Hash][]byte) { - for hash, preimage := range preimages { - if _, ok := s.preimages[hash]; !ok { - s.preimages[hash] = preimage - } - } +// SetPreimages sets the preimages. +func (s *BALStateTransition) SetPreimages(preimages map[common.Hash][]byte) { + s.preimages = preimages } // Preimages returns the SHA3 preimages seen by the VM over the course of the -// block. Unlike the sequential processor, which reads them from a single -// statedb, the BAL processor executes the block across several statedbs and -// installs the combined set via AddPreimages. +// block. func (s *BALStateTransition) Preimages() map[common.Hash][]byte { return s.preimages } diff --git a/core/state/bal_state_transition_test.go b/core/state/bal_state_transition_test.go deleted file mode 100644 index 5ec6ad6e56..0000000000 --- a/core/state/bal_state_transition_test.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2026 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package state - -import ( - "bytes" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -// newPreimageTransition returns a BALStateTransition with only the preimage -// accumulator initialised, which is all that AddPreimages/Preimages touch. -func newPreimageTransition() *BALStateTransition { - return &BALStateTransition{preimages: make(map[common.Hash][]byte)} -} - -// TestBALStateTransitionPreimagesUnion verifies that AddPreimages folds the -// preimages contributed by the various block executions (the per-transaction -// copies plus the pre/post-tx execution) into a single set returned by -// Preimages. -func TestBALStateTransitionPreimagesUnion(t *testing.T) { - s := newPreimageTransition() - - // Empty/nil inputs are no-ops. - s.AddPreimages(nil) - s.AddPreimages(map[common.Hash][]byte{}) - if got := len(s.Preimages()); got != 0 { - t.Fatalf("expected empty set, got %d entries", got) - } - - s.AddPreimages(map[common.Hash][]byte{ - {0x01}: []byte("pre"), - {0x02}: []byte("tx1"), - {0x03}: []byte("tx2"), - {0x04}: []byte("post"), - }) - - want := map[common.Hash][]byte{ - {0x01}: []byte("pre"), - {0x02}: []byte("tx1"), - {0x03}: []byte("tx2"), - {0x04}: []byte("post"), - } - got := s.Preimages() - if len(got) != len(want) { - t.Fatalf("preimage count: got %d, want %d", len(got), len(want)) - } - for h, v := range want { - if !bytes.Equal(got[h], v) { - t.Errorf("preimage %x: got %q, want %q", h, got[h], v) - } - } -} - -// TestBALStateTransitionPreimagesFirstWriteWins verifies that a preimage for a -// hash already present is not overwritten across successive AddPreimages calls, -// matching StateDB.AddPreimage. -func TestBALStateTransitionPreimagesFirstWriteWins(t *testing.T) { - s := newPreimageTransition() - key := common.Hash{0xaa} - - s.AddPreimages(map[common.Hash][]byte{key: []byte("first")}) - s.AddPreimages(map[common.Hash][]byte{key: []byte("second")}) - - if got := s.Preimages()[key]; !bytes.Equal(got, []byte("first")) { - t.Fatalf("expected first write to win, got %q", got) - } -}