Several fixes (#425)

* params: fix chainconfig rules

* core, core/state: init accessEvent for each transactin

* core/state: reuse point cache between blocks
This commit is contained in:
rjl493456442 2024-05-02 15:25:42 +08:00 committed by GitHub
parent 026ebc93b4
commit aa96a9c7d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 70 additions and 84 deletions

View file

@ -360,12 +360,6 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
amount := new(uint256.Int).SetUint64(w.Amount) amount := new(uint256.Int).SetUint64(w.Amount)
amount = amount.Mul(amount, uint256.NewInt(params.GWei)) amount = amount.Mul(amount, uint256.NewInt(params.GWei))
state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal)
// Add the balance of each withdrawal to the witness, no gas will
// be charged.
if chain.Config().IsEIP4762(header.Number, header.Time) {
state.AccessEvents().BalanceGas(w.Address[:], true)
}
} }
// No block reward which is issued by consensus layer instead. // No block reward which is issued by consensus layer instead.
} }

View file

@ -66,7 +66,7 @@ func (aw *AccessEvents) Merge(other *AccessEvents) {
} }
} }
// Key returns, predictably, the list of keys that were touched during the // Keys returns, predictably, the list of keys that were touched during the
// buildup of the access witness. // buildup of the access witness.
func (aw *AccessEvents) Keys() [][]byte { func (aw *AccessEvents) Keys() [][]byte {
// TODO: consider if parallelizing this is worth it, probably depending on len(aw.chunks). // TODO: consider if parallelizing this is worth it, probably depending on len(aw.chunks).
@ -173,7 +173,6 @@ func (aw *AccessEvents) touchAddressAndChargeGas(addr []byte, treeIndex uint256.
if selectorFill { if selectorFill {
gas += params.WitnessChunkFillCost gas += params.WitnessChunkFillCost
} }
return gas return gas
} }
@ -206,10 +205,8 @@ func (aw *AccessEvents) touchAddress(addr []byte, treeIndex uint256.Int, subInde
chunkWrite = true chunkWrite = true
aw.chunks[chunkKey] |= AccessWitnessWriteFlag aw.chunks[chunkKey] |= AccessWitnessWriteFlag
} }
// TODO: charge chunk filling costs if the leaf was previously empty in the state // TODO: charge chunk filling costs if the leaf was previously empty in the state
} }
return branchRead, chunkRead, branchWrite, chunkWrite, chunkFill return branchRead, chunkRead, branchWrite, chunkWrite, chunkFill
} }
@ -268,7 +265,6 @@ func (aw *AccessEvents) CodeChunksRangeGas(contractAddr []byte, startPC, size ui
panic("overflow when adding gas") panic("overflow when adding gas")
} }
} }
return statelessGasCharged return statelessGasCharged
} }

View file

@ -38,6 +38,9 @@ const (
// Cache size granted for caching clean code. // Cache size granted for caching clean code.
codeCacheSize = 64 * 1024 * 1024 codeCacheSize = 64 * 1024 * 1024
// Number of address->curve point associations to keep.
pointCacheSize = 4096
) )
// Database wraps access to tries and contract code. // Database wraps access to tries and contract code.
@ -62,6 +65,9 @@ type Database interface {
// TrieDB returns the underlying trie database for managing trie nodes. // TrieDB returns the underlying trie database for managing trie nodes.
TrieDB() *triedb.Database TrieDB() *triedb.Database
// PointCache returns the cache of evaluated curve points.
PointCache() *utils.PointCache
} }
// Trie is a Ethereum Merkle Patricia trie. // Trie is a Ethereum Merkle Patricia trie.
@ -153,6 +159,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: triedb.NewDatabase(db, config), triedb: triedb.NewDatabase(db, config),
pointCache: utils.NewPointCache(pointCacheSize),
} }
} }
@ -163,6 +170,7 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: triedb, triedb: triedb,
pointCache: utils.NewPointCache(pointCacheSize),
} }
} }
@ -171,12 +179,13 @@ type cachingDB struct {
codeSizeCache *lru.Cache[common.Hash, int] codeSizeCache *lru.Cache[common.Hash, int]
codeCache *lru.SizeConstrainedCache[common.Hash, []byte] codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
triedb *triedb.Database triedb *triedb.Database
pointCache *utils.PointCache
} }
// OpenTrie opens the main account trie at a specific root hash. // OpenTrie opens the main account trie at a specific root hash.
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.triedb.IsVerkle() { if db.triedb.IsVerkle() {
return trie.NewVerkleTrie(root, db.triedb, utils.NewPointCache(100)) return trie.NewVerkleTrie(root, db.triedb, db.pointCache)
} }
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
if err != nil { if err != nil {
@ -262,3 +271,8 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
func (db *cachingDB) TrieDB() *triedb.Database { func (db *cachingDB) TrieDB() *triedb.Database {
return db.triedb return db.triedb
} }
// PointCache returns the cache of evaluated curve points.
func (db *cachingDB) PointCache() *utils.PointCache {
return db.pointCache
}

View file

@ -36,7 +36,6 @@ import (
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -140,8 +139,8 @@ type StateDB struct {
// Transient storage // Transient storage
transientStorage transientStorage transientStorage transientStorage
// State access events, used for Verkle tries/EIP4762 // State access events, used for EIP4762
accessEvents *AccessEvents accessEvents *AccessEvents // reset for each transaction
// Journal of state modifications. This is the backbone of // Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot. // Snapshot and RevertToSnapshot.
@ -197,30 +196,16 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
transientStorage: newTransientStorage(), transientStorage: newTransientStorage(),
hasher: crypto.NewKeccakState(), hasher: crypto.NewKeccakState(),
} }
if tr.IsVerkle() {
sdb.accessEvents = sdb.NewAccessEvents()
}
if sdb.snaps != nil { if sdb.snaps != nil {
sdb.snap = sdb.snaps.Snapshot(root) sdb.snap = sdb.snaps.Snapshot(root)
} }
return sdb, nil return sdb, nil
} }
func (s *StateDB) NewAccessEvents() *AccessEvents {
return NewAccessEvents(utils.NewPointCache(100))
}
func (s *StateDB) AccessEvents() *AccessEvents { func (s *StateDB) AccessEvents() *AccessEvents {
if s.accessEvents == nil {
s.accessEvents = s.NewAccessEvents()
}
return s.accessEvents return s.accessEvents
} }
func (s *StateDB) SetAccessEvents(ae *AccessEvents) {
s.accessEvents = ae
}
// SetLogger sets the logger for account update hooks. // SetLogger sets the logger for account update hooks.
func (s *StateDB) SetLogger(l *tracing.Hooks) { func (s *StateDB) SetLogger(l *tracing.Hooks) {
s.logger = l s.logger = l
@ -767,6 +752,9 @@ func (s *StateDB) Copy() *StateDB {
if s.prefetcher != nil { if s.prefetcher != nil {
state.prefetcher = s.prefetcher.copy() state.prefetcher = s.prefetcher.copy()
} }
if s.accessEvents != nil {
state.accessEvents = s.accessEvents.Copy()
}
return state return state
} }
@ -1297,6 +1285,9 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
// - Add coinbase to access list (EIP-3651) // - Add coinbase to access list (EIP-3651)
// - Reset transient storage (EIP-1153) // - Reset transient storage (EIP-1153)
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
if rules.IsEIP2929 && rules.IsEIP4762 {
panic("eip2929 and eip4762 are both activated")
}
if rules.IsEIP2929 { if rules.IsEIP2929 {
// Clear out any leftover from previous executions // Clear out any leftover from previous executions
al := newAccessList() al := newAccessList()
@ -1320,6 +1311,9 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d
al.AddAddress(coinbase) al.AddAddress(coinbase)
} }
} }
if rules.IsEIP4762 {
s.accessEvents = NewAccessEvents(s.db.PointCache())
}
// Reset transient storage at the beginning of transaction execution // Reset transient storage at the beginning of transaction execution
s.transientStorage = newTransientStorage() s.transientStorage = newTransientStorage()
} }

View file

@ -120,7 +120,6 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
} }
// Create a new context to be used in the EVM environment. // Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg) txContext := NewEVMTxContext(msg)
txContext.AccessEvents = statedb.NewAccessEvents()
evm.Reset(txContext, statedb) evm.Reset(txContext, statedb)
// Apply the transaction to the current state (included in the env). // Apply the transaction to the current state (included in the env).
@ -158,11 +157,6 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
if msg.To == nil { if msg.To == nil {
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
} }
if statedb.AccessEvents() != nil {
statedb.AccessEvents().Merge(txContext.AccessEvents)
}
// Set the receipt logs and create the bloom filter. // Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
@ -208,8 +202,5 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
statedb.AddAddressToAccessList(params.BeaconRootsAddress) statedb.AddAddressToAccessList(params.BeaconRootsAddress)
} }
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
if vmenv.ChainConfig().Rules(vmenv.Context.BlockNumber, true, vmenv.Context.Time).IsEIP4762 {
statedb.AccessEvents().Merge(txctx.AccessEvents)
}
statedb.Finalise(true) statedb.Finalise(true)
} }

View file

@ -406,10 +406,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
st.gasRemaining -= gas st.gasRemaining -= gas
if rules.IsEIP4762 { if rules.IsEIP4762 {
st.evm.AccessEvents.AddTxOrigin(msg.From.Bytes()) st.evm.StateDB.AccessEvents().AddTxOrigin(msg.From.Bytes())
if targetAddr := msg.To; targetAddr != nil { if targetAddr := msg.To; targetAddr != nil {
st.evm.AccessEvents.AddTxDestination(targetAddr.Bytes(), msg.Value.Sign() != 0) st.evm.StateDB.AccessEvents().AddTxDestination(targetAddr.Bytes(), msg.Value.Sign() != 0)
// ensure the code size ends up in the access witness // ensure the code size ends up in the access witness
st.evm.StateDB.GetCodeSize(*targetAddr) st.evm.StateDB.GetCodeSize(*targetAddr)
@ -472,7 +472,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// add the coinbase to the witness iff the fee is greater than 0 // add the coinbase to the witness iff the fee is greater than 0
if rules.IsEIP4762 && fee.Sign() != 0 { if rules.IsEIP4762 && fee.Sign() != 0 {
st.evm.AccessEvents.BalanceGas(st.evm.Context.Coinbase[:], true) st.evm.StateDB.AccessEvents().BalanceGas(st.evm.Context.Coinbase[:], true)
} }
} }

View file

@ -331,7 +331,7 @@ func opCreateEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContex
var endowment = scope.Stack.peek() var endowment = scope.Stack.peek()
contractAddress := crypto.CreateAddress(scope.Contract.Address(), interpreter.evm.StateDB.GetNonce(scope.Contract.Address())) contractAddress := crypto.CreateAddress(scope.Contract.Address(), interpreter.evm.StateDB.GetNonce(scope.Contract.Address()))
statelessGas := interpreter.evm.AccessEvents.ContractCreateInitGas(contractAddress.Bytes()[:], endowment.Sign() != 0) statelessGas := interpreter.evm.StateDB.AccessEvents().ContractCreateInitGas(contractAddress.Bytes()[:], endowment.Sign() != 0)
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
return nil, ErrExecutionReverted return nil, ErrExecutionReverted
} }
@ -352,7 +352,7 @@ func opCreate2EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
codeAndHash := &codeAndHash{code: input} codeAndHash := &codeAndHash{code: input}
contractAddress := crypto.CreateAddress2(scope.Contract.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes()) contractAddress := crypto.CreateAddress2(scope.Contract.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
statelessGas := interpreter.evm.AccessEvents.ContractCreateInitGas(contractAddress.Bytes()[:], endowment.Sign() != 0) statelessGas := interpreter.evm.StateDB.AccessEvents().ContractCreateInitGas(contractAddress.Bytes()[:], endowment.Sign() != 0)
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
return nil, ErrExecutionReverted return nil, ErrExecutionReverted
} }
@ -379,7 +379,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
self: AccountRef(addr), self: AccountRef(addr),
} }
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr[:], copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) statelessGas := interpreter.evm.StateDB.AccessEvents().CodeChunksRangeGas(addr[:], copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
scope.Contract.Gas = 0 scope.Contract.Gas = 0
return nil, ErrOutOfGas return nil, ErrOutOfGas
@ -405,7 +405,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
// touch next chunk if PUSH1 is at the boundary. if so, *pc has // touch next chunk if PUSH1 is at the boundary. if so, *pc has
// advanced past this boundary. // advanced past this boundary.
contractAddr := scope.Contract.Address() contractAddr := scope.Contract.Address()
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr[:], *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false) statelessGas := interpreter.evm.StateDB.AccessEvents().CodeChunksRangeGas(contractAddr[:], *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false)
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
scope.Contract.Gas = 0 scope.Contract.Gas = 0
return nil, ErrOutOfGas return nil, ErrOutOfGas
@ -433,7 +433,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
if !scope.Contract.IsDeployment { if !scope.Contract.IsDeployment {
contractAddr := scope.Contract.Address() contractAddr := scope.Contract.Address()
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr[:], uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false) statelessGas := interpreter.evm.StateDB.AccessEvents().CodeChunksRangeGas(contractAddr[:], uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false)
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) { if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
scope.Contract.Gas = 0 scope.Contract.Gas = 0
return nil, ErrOutOfGas return nil, ErrOutOfGas

View file

@ -22,7 +22,6 @@ import (
"sync/atomic" "sync/atomic"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -88,11 +87,10 @@ type BlockContext struct {
// All fields can change between transactions. // All fields can change between transactions.
type TxContext struct { type TxContext struct {
// Message information // Message information
Origin common.Address // Provides information for ORIGIN Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set) GasPrice *big.Int // Provides information for GASPRICE (and is used to zero the basefee if NoBaseFee is set)
BlobHashes []common.Hash // Provides information for BLOBHASH BlobHashes []common.Hash // Provides information for BLOBHASH
BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set BlobFeeCap *big.Int // Is used to zero the blobbasefee if NoBaseFee is set
AccessEvents *state.AccessEvents // Capture all state accesses for this tx
} }
// EVM is the Ethereum Virtual Machine base object and provides // EVM is the Ethereum Virtual Machine base object and provides
@ -153,9 +151,6 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
chainConfig: chainConfig, chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
} }
if txCtx.AccessEvents == nil && chainConfig.IsPrague(blockCtx.BlockNumber, blockCtx.Time) {
evm.AccessEvents = evm.StateDB.(*state.StateDB).NewAccessEvents()
}
evm.interpreter = NewEVMInterpreter(evm) evm.interpreter = NewEVMInterpreter(evm)
return evm return evm
} }
@ -163,9 +158,6 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
// Reset resets the EVM with a new transaction context.Reset // Reset resets the EVM with a new transaction context.Reset
// This is not threadsafe and should only be done very cautiously. // This is not threadsafe and should only be done very cautiously.
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {
if txCtx.AccessEvents == nil && evm.chainRules.IsPrague {
txCtx.AccessEvents = evm.StateDB.(*state.StateDB).NewAccessEvents()
}
evm.TxContext = txCtx evm.TxContext = txCtx
evm.StateDB = statedb evm.StateDB = statedb
} }
@ -212,7 +204,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP4762 { if !isPrecompile && evm.chainRules.IsEIP4762 {
// add proof of absence to witness // add proof of absence to witness
wgas := evm.AccessEvents.AddAccount(addr.Bytes(), false) wgas := evm.StateDB.AccessEvents().AddAccount(addr.Bytes(), false)
if gas < wgas { if gas < wgas {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
return nil, 0, ErrOutOfGas return nil, 0, ErrOutOfGas
@ -503,7 +495,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// Charge the contract creation init gas in verkle mode // Charge the contract creation init gas in verkle mode
if evm.chainRules.IsEIP4762 { if evm.chainRules.IsEIP4762 {
if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address.Bytes(), value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { if !contract.UseGas(evm.StateDB.AccessEvents().ContractCreateInitGas(address.Bytes(), value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) {
err = ErrOutOfGas err = ErrOutOfGas
} }
} }
@ -534,11 +526,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
} }
} else { } else {
// Contract creation completed, touch the missing fields in the contract // Contract creation completed, touch the missing fields in the contract
if !contract.UseGas(evm.AccessEvents.AddAccount(address.Bytes()[:], true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { if !contract.UseGas(evm.StateDB.AccessEvents().AddAccount(address.Bytes()[:], true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) {
err = ErrCodeStoreOutOfGas err = ErrCodeStoreOutOfGas
} }
if err == nil && len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address.Bytes(), 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { if err == nil && len(ret) > 0 && !contract.UseGas(evm.StateDB.AccessEvents().CodeChunksRangeGas(address.Bytes(), 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) {
err = ErrCodeStoreOutOfGas err = ErrCodeStoreOutOfGas
} }
} }

View file

@ -404,7 +404,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
} }
if evm.chainRules.IsEIP4762 { if evm.chainRules.IsEIP4762 {
if transfersValue { if transfersValue {
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address().Bytes()[:], address.Bytes()[:])) gas, overflow = math.SafeAdd(gas, evm.StateDB.AccessEvents().ValueTransferGas(contract.Address().Bytes()[:], address.Bytes()[:]))
if overflow { if overflow {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
@ -440,7 +440,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
address := common.Address(stack.Back(1).Bytes20()) address := common.Address(stack.Back(1).Bytes20())
transfersValue := !stack.Back(2).IsZero() transfersValue := !stack.Back(2).IsZero()
if transfersValue { if transfersValue {
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address().Bytes()[:], address.Bytes()[:])) gas, overflow = math.SafeAdd(gas, evm.StateDB.AccessEvents().ValueTransferGas(contract.Address().Bytes()[:], address.Bytes()[:]))
if overflow { if overflow {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }

View file

@ -20,6 +20,7 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -75,6 +76,9 @@ type StateDB interface {
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet // even if the feature/fork is not active yet
AddSlotToAccessList(addr common.Address, slot common.Hash) AddSlotToAccessList(addr common.Address, slot common.Hash)
AccessEvents() *state.AccessEvents
Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
RevertToSnapshot(int) RevertToSnapshot(int)

View file

@ -227,7 +227,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// if the PC ends up in a new "chunk" of verkleized code, charge the // if the PC ends up in a new "chunk" of verkleized code, charge the
// associated costs. // associated costs.
contractAddr := contract.Address() contractAddr := contract.Address()
contract.Gas -= in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr[:], pc, 1, uint64(len(contract.Code)), false) contract.Gas -= in.evm.StateDB.AccessEvents().CodeChunksRangeGas(contractAddr[:], pc, 1, uint64(len(contract.Code)), false)
} }
// Get the operation from the jump table and validate the stack to ensure there are // Get the operation from the jump table and validate the stack to ensure there are

View file

@ -23,7 +23,7 @@ import (
) )
func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas := evm.AccessEvents.SlotGas(contract.Address().Bytes(), common.Hash(stack.peek().Bytes32()), true) gas := evm.StateDB.AccessEvents().SlotGas(contract.Address().Bytes(), common.Hash(stack.peek().Bytes32()), true)
if gas == 0 { if gas == 0 {
gas = params.WarmStorageReadCostEIP2929 gas = params.WarmStorageReadCostEIP2929
} }
@ -31,7 +31,7 @@ func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
} }
func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas := evm.AccessEvents.SlotGas(contract.Address().Bytes(), common.Hash(stack.peek().Bytes32()), false) gas := evm.StateDB.AccessEvents().SlotGas(contract.Address().Bytes(), common.Hash(stack.peek().Bytes32()), false)
if gas == 0 { if gas == 0 {
gas = params.WarmStorageReadCostEIP2929 gas = params.WarmStorageReadCostEIP2929
} }
@ -40,7 +40,7 @@ func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
address := stack.peek().Bytes20() address := stack.peek().Bytes20()
gas := evm.AccessEvents.BalanceGas(address[:], false) gas := evm.StateDB.AccessEvents().BalanceGas(address[:], false)
if gas == 0 { if gas == 0 {
gas = params.WarmStorageReadCostEIP2929 gas = params.WarmStorageReadCostEIP2929
} }
@ -52,8 +52,8 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
if _, isPrecompile := evm.precompile(address); isPrecompile { if _, isPrecompile := evm.precompile(address); isPrecompile {
return 0, nil return 0, nil
} }
wgas := evm.AccessEvents.VersionGas(address[:], false) wgas := evm.StateDB.AccessEvents().VersionGas(address[:], false)
wgas += evm.AccessEvents.CodeSizeGas(address[:], false) wgas += evm.StateDB.AccessEvents().CodeSizeGas(address[:], false)
if wgas == 0 { if wgas == 0 {
wgas = params.WarmStorageReadCostEIP2929 wgas = params.WarmStorageReadCostEIP2929
} }
@ -65,7 +65,7 @@ func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
if _, isPrecompile := evm.precompile(address); isPrecompile { if _, isPrecompile := evm.precompile(address); isPrecompile {
return 0, nil return 0, nil
} }
codehashgas := evm.AccessEvents.CodeHashGas(address[:], false) codehashgas := evm.StateDB.AccessEvents().CodeHashGas(address[:], false)
if codehashgas == 0 { if codehashgas == 0 {
codehashgas = params.WarmStorageReadCostEIP2929 codehashgas = params.WarmStorageReadCostEIP2929
} }
@ -81,7 +81,7 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile { if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile {
return gas, nil return gas, nil
} }
wgas := evm.AccessEvents.MessageCallGas(contract.Address().Bytes()) wgas := evm.StateDB.AccessEvents().MessageCallGas(contract.Address().Bytes())
if wgas == 0 { if wgas == 0 {
wgas = params.WarmStorageReadCostEIP2929 wgas = params.WarmStorageReadCostEIP2929
} }
@ -102,17 +102,17 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem
return 0, nil return 0, nil
} }
contractAddr := contract.Address() contractAddr := contract.Address()
statelessGas := evm.AccessEvents.VersionGas(contractAddr[:], false) statelessGas := evm.StateDB.AccessEvents().VersionGas(contractAddr[:], false)
statelessGas += evm.AccessEvents.CodeSizeGas(contractAddr[:], false) statelessGas += evm.StateDB.AccessEvents().CodeSizeGas(contractAddr[:], false)
statelessGas += evm.AccessEvents.BalanceGas(contractAddr[:], false) statelessGas += evm.StateDB.AccessEvents().BalanceGas(contractAddr[:], false)
if contractAddr != beneficiaryAddr { if contractAddr != beneficiaryAddr {
statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr[:], false) statelessGas += evm.StateDB.AccessEvents().BalanceGas(beneficiaryAddr[:], false)
} }
// Charge write costs if it transfers value // Charge write costs if it transfers value
if evm.StateDB.GetBalance(contractAddr).Sign() != 0 { if evm.StateDB.GetBalance(contractAddr).Sign() != 0 {
statelessGas += evm.AccessEvents.BalanceGas(contractAddr[:], true) statelessGas += evm.StateDB.AccessEvents().BalanceGas(contractAddr[:], true)
if contractAddr != beneficiaryAddr { if contractAddr != beneficiaryAddr {
statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr[:], true) statelessGas += evm.StateDB.AccessEvents().BalanceGas(beneficiaryAddr[:], true)
} }
} }
return statelessGas, nil return statelessGas, nil
@ -133,7 +133,7 @@ func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
} }
_, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64()) _, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64())
if !contract.IsDeployment { if !contract.IsDeployment {
gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address().Bytes(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false) gas += evm.StateDB.AccessEvents().CodeChunksRangeGas(contract.Address().Bytes(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
} }
return gas, nil return gas, nil
} }
@ -145,8 +145,8 @@ func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memo
return 0, err return 0, err
} }
addr := common.Address(stack.peek().Bytes20()) addr := common.Address(stack.peek().Bytes20())
wgas := evm.AccessEvents.VersionGas(addr[:], false) wgas := evm.StateDB.AccessEvents().VersionGas(addr[:], false)
wgas += evm.AccessEvents.CodeSizeGas(addr[:], false) wgas += evm.StateDB.AccessEvents().CodeSizeGas(addr[:], false)
if wgas == 0 { if wgas == 0 {
wgas = params.WarmStorageReadCostEIP2929 wgas = params.WarmStorageReadCostEIP2929
} }

View file

@ -921,6 +921,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
} }
// disallow setting Merge out of order // disallow setting Merge out of order
isMerge = isMerge && c.IsLondon(num) isMerge = isMerge && c.IsLondon(num)
isVerkle := isMerge && c.IsVerkle(num, timestamp)
return Rules{ return Rules{
ChainID: new(big.Int).Set(chainID), ChainID: new(big.Int).Set(chainID),
IsHomestead: c.IsHomestead(num), IsHomestead: c.IsHomestead(num),
@ -932,13 +933,13 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
IsPetersburg: c.IsPetersburg(num), IsPetersburg: c.IsPetersburg(num),
IsIstanbul: c.IsIstanbul(num), IsIstanbul: c.IsIstanbul(num),
IsBerlin: c.IsBerlin(num), IsBerlin: c.IsBerlin(num),
IsEIP2929: c.IsBerlin(num) && !c.IsVerkle(num, timestamp), IsEIP2929: c.IsBerlin(num) && !isVerkle,
IsEIP4762: c.IsVerkle(num, timestamp),
IsLondon: c.IsLondon(num), IsLondon: c.IsLondon(num),
IsMerge: isMerge, IsMerge: isMerge,
IsShanghai: isMerge && c.IsShanghai(num, timestamp), IsShanghai: isMerge && c.IsShanghai(num, timestamp),
IsCancun: isMerge && c.IsCancun(num, timestamp), IsCancun: isMerge && c.IsCancun(num, timestamp),
IsPrague: isMerge && c.IsPrague(num, timestamp), IsPrague: isMerge && c.IsPrague(num, timestamp),
IsVerkle: isMerge && c.IsVerkle(num, timestamp), IsVerkle: isVerkle,
IsEIP4762: isVerkle,
} }
} }