mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 11:20:45 +00:00
ai implementation for preimages
This commit is contained in:
parent
861890877a
commit
d9f607e867
3 changed files with 148 additions and 4 deletions
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/types/bal"
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
|
|
@ -22,6 +23,12 @@ type ProcessResultWithMetrics struct {
|
||||||
StateTransitionMetrics *state.BALStateTransitionMetrics
|
StateTransitionMetrics *state.BALStateTransitionMetrics
|
||||||
ExecTime time.Duration
|
ExecTime time.Duration
|
||||||
PostProcessTime 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 map[common.Hash][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// errResult wraps an error into a new ProcessResultWithMetrics instance
|
// errResult wraps an error into a new ProcessResultWithMetrics instance
|
||||||
|
|
@ -112,6 +119,24 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar
|
||||||
|
|
||||||
p.chain.Engine().Finalize(p.chain, block.Header(), evm.StateDB, block.Body(), uint32(lastBALIdx), postBAL)
|
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.
|
||||||
|
preimages := make(map[common.Hash][]byte)
|
||||||
|
for hash, preimage := range postTxState.Preimages() {
|
||||||
|
preimages[hash] = preimage
|
||||||
|
}
|
||||||
|
for i := range results {
|
||||||
|
for hash, preimage := range results[i].preimages {
|
||||||
|
if _, ok := preimages[hash]; !ok {
|
||||||
|
preimages[hash] = preimage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
blockAccessList := bal.NewConstructionBlockAccessList()
|
blockAccessList := bal.NewConstructionBlockAccessList()
|
||||||
blockAccessList.Merge(preTxBAL)
|
blockAccessList.Merge(preTxBAL)
|
||||||
blockAccessList.Merge(postBAL)
|
blockAccessList.Merge(postBAL)
|
||||||
|
|
@ -137,6 +162,7 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar
|
||||||
},
|
},
|
||||||
PostProcessTime: tPostprocess,
|
PostProcessTime: tPostprocess,
|
||||||
ExecTime: tExec,
|
ExecTime: tExec,
|
||||||
|
Preimages: preimages,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,6 +176,10 @@ type txExecResult struct {
|
||||||
txState uint64
|
txState uint64
|
||||||
|
|
||||||
blockAccessList *bal.ConstructionBlockAccessList
|
blockAccessList *bal.ConstructionBlockAccessList
|
||||||
|
|
||||||
|
// preimages holds the SHA3 preimages recorded while executing this
|
||||||
|
// transaction against its own statedb copy.
|
||||||
|
preimages map[common.Hash][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// resultHandler polls until all transactions have finished executing and the
|
// resultHandler polls until all transactions have finished executing and the
|
||||||
|
|
@ -303,7 +333,11 @@ func (p *ParallelStateProcessor) Process(block *types.Block, stateTransition *st
|
||||||
prestate := startingState.Copy()
|
prestate := startingState.Copy()
|
||||||
workers.Go(func() error {
|
workers.Go(func() error {
|
||||||
prestate = prestate.WithReader(state.NewReaderWithAccessList(statedb.Reader(), prepared, balIdx))
|
prestate = prestate.WithReader(state.NewReaderWithAccessList(statedb.Reader(), prepared, balIdx))
|
||||||
txResCh <- *p.execTx(block, tx, balIdx, prestate, signer)
|
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
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -314,6 +348,10 @@ func (p *ParallelStateProcessor) Process(block *types.Block, stateTransition *st
|
||||||
if res.ProcessResult.Error != nil {
|
if res.ProcessResult.Error != nil {
|
||||||
return nil, res.ProcessResult.Error
|
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)
|
||||||
// TODO: remove preprocess metric ?
|
// TODO: remove preprocess metric ?
|
||||||
res.PreProcessTime = tPreprocess
|
res.PreProcessTime = tPreprocess
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ type BALStateTransition struct {
|
||||||
|
|
||||||
stateUpdate *StateUpdate
|
stateUpdate *StateUpdate
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
preimages map[common.Hash][]byte
|
||||||
|
|
||||||
metrics BALStateTransitionMetrics
|
metrics BALStateTransitionMetrics
|
||||||
maxBALIdx int
|
maxBALIdx int
|
||||||
|
|
||||||
|
|
@ -108,6 +114,7 @@ func NewBALStateTransition(block *types.Block, prefetchReader Reader, db Databas
|
||||||
tries: sync.Map{},
|
tries: sync.Map{},
|
||||||
deletions: make(map[common.Address]struct{}),
|
deletions: make(map[common.Address]struct{}),
|
||||||
stateUpdate: nil,
|
stateUpdate: nil,
|
||||||
|
preimages: make(map[common.Hash][]byte),
|
||||||
maxBALIdx: len(block.Transactions()) + 1,
|
maxBALIdx: len(block.Transactions()) + 1,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -533,7 +540,23 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash {
|
||||||
return s.rootHash
|
return s.rootHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BALStateTransition) Preimages() map[common.Hash][]byte {
|
// AddPreimages merges a set of SHA3 preimages into the block-level preimage
|
||||||
// TODO: implement this
|
// set, leaving any hash already present untouched (mirroring the
|
||||||
return make(map[common.Hash][]byte)
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (s *BALStateTransition) Preimages() map[common.Hash][]byte {
|
||||||
|
return s.preimages
|
||||||
}
|
}
|
||||||
|
|
|
||||||
83
core/state/bal_state_transition_test.go
Normal file
83
core/state/bal_state_transition_test.go
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue