mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-30 08:33:45 +00:00
Blocks heavy in precompile calls (e.g. Aztec's proof settlement txs) spend most of their processing time on operations (ECMUL, pairings, KZG point evaluation, MODEXP) that the state prefetcher has already computed and thrown away. This PR adds a precompile result cache shared between the prefetcher and block processing (and the miner), following the JumpDestCache pattern. Note that cached precompiles are keyed by address and input, with entries partitioned by the active precompile set, so a fork that changes the behavior behind an address can never be served results from before it. --------- Co-authored-by: Gary Rong <garyrong0905@gmail.com>
82 lines
3.7 KiB
Go
82 lines
3.7 KiB
Go
// Copyright 2024 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 core
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/lru"
|
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
"github.com/ethereum/go-ethereum/core/stateless"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
"github.com/ethereum/go-ethereum/trie"
|
|
"github.com/ethereum/go-ethereum/triedb"
|
|
)
|
|
|
|
// ExecuteStateless runs a stateless execution based on a witness, verifies
|
|
// everything it can locally and returns the state root and receipt root, that
|
|
// need the other side to explicitly check.
|
|
//
|
|
// This method is a bit of a sore thumb here, but:
|
|
// - It cannot be placed in core/stateless, because state.New produces a circular dep
|
|
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
|
//
|
|
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
|
func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
|
// Sanity check if the supplied block accidentally contains a set root or
|
|
// receipt hash. If so, be very loud, but still continue.
|
|
if block.Root() != (common.Hash{}) {
|
|
log.Error("stateless runner received state root it's expected to calculate (faulty consensus client)", "block", block.Number())
|
|
}
|
|
if block.ReceiptHash() != (common.Hash{}) {
|
|
log.Error("stateless runner received receipt root it's expected to calculate (faulty consensus client)", "block", block.Number())
|
|
}
|
|
// Create and populate the state database to serve as the stateless backend
|
|
memdb := witness.MakeHashDB()
|
|
db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), state.NewCodeDB(memdb)))
|
|
if err != nil {
|
|
return common.Hash{}, common.Hash{}, err
|
|
}
|
|
// Create a blockchain that is idle, but can be used to access headers through
|
|
chain := &HeaderChain{
|
|
config: config,
|
|
chainDb: memdb,
|
|
headerCache: lru.NewCache[common.Hash, *types.Header](256),
|
|
engine: beacon.New(ethash.NewFaker()),
|
|
}
|
|
processor := NewStateProcessor(chain)
|
|
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
|
|
|
// Run the stateless blocks processing and self-validate certain fields
|
|
res, err := processor.Process(ctx, block, db, nil, nil, vmconfig, nil)
|
|
if err != nil {
|
|
return common.Hash{}, common.Hash{}, err
|
|
}
|
|
if err = validator.ValidateState(block, db, res, true); 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()))
|
|
return stateRoot, receiptRoot, nil
|
|
}
|