mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
core/{state,vm}: FILL_COSTS using StateExists
This commit is contained in:
parent
8c42044252
commit
839a258547
9 changed files with 83 additions and 55 deletions
|
|
@ -44,6 +44,7 @@ var zeroTreeIndex uint256.Int
|
|||
type AccessEvents struct {
|
||||
branches map[branchAccessKey]mode
|
||||
chunks map[chunkAccessKey]mode
|
||||
fills map[chunkAccessKey]struct{}
|
||||
|
||||
pointCache *utils.PointCache
|
||||
}
|
||||
|
|
@ -52,6 +53,7 @@ func NewAccessEvents(pointCache *utils.PointCache) *AccessEvents {
|
|||
return &AccessEvents{
|
||||
branches: make(map[branchAccessKey]mode),
|
||||
chunks: make(map[chunkAccessKey]mode),
|
||||
fills: make(map[chunkAccessKey]struct{}),
|
||||
pointCache: pointCache,
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +68,9 @@ func (ae *AccessEvents) Merge(other *AccessEvents) {
|
|||
for k, chunk := range other.chunks {
|
||||
ae.chunks[k] |= chunk
|
||||
}
|
||||
for k := range other.fills {
|
||||
ae.fills[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Keys returns, predictably, the list of keys that were touched during the
|
||||
|
|
@ -85,17 +90,24 @@ func (ae *AccessEvents) Copy() *AccessEvents {
|
|||
cpy := &AccessEvents{
|
||||
branches: maps.Clone(ae.branches),
|
||||
chunks: maps.Clone(ae.chunks),
|
||||
fills: maps.Clone(ae.fills),
|
||||
pointCache: ae.pointCache,
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
// Reset resets all values of an access event, except its `fills` and point cache fields
|
||||
func (ae *AccessEvents) Reset() {
|
||||
ae.branches = make(map[branchAccessKey]mode)
|
||||
ae.chunks = make(map[chunkAccessKey]mode)
|
||||
}
|
||||
|
||||
// AddAccount returns the gas to be charged for each of the currently cold
|
||||
// member fields of an account.
|
||||
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite, isFill bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite, isFill)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite, isFill)
|
||||
return gas
|
||||
}
|
||||
|
||||
|
|
@ -104,16 +116,18 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
|||
// call to that account.
|
||||
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false, false)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ValueTransferGas returns the gas to be charged for each of the currently
|
||||
// cold balance member fields of the caller and the callee accounts.
|
||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
|
||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address, isFill bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
// TODO have a test to see what happens what happens when a tx from a non-existing
|
||||
// account to another account (existing or not).
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, false)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, isFill)
|
||||
return gas
|
||||
}
|
||||
|
||||
|
|
@ -121,34 +135,41 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address)
|
|||
// a contract creation.
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// AddTxOrigin adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false, false)
|
||||
}
|
||||
|
||||
// AddTxDestination adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
// For the balance, isFill is always set to true, as it will be covered by
|
||||
// the intrinsic tx gas if needed. If the destination is written to during
|
||||
// the contract execution, before the state db layer has saved it to disk,
|
||||
// the fill cost will already have been covered by the intrinsic gas.
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue, true)
|
||||
// This is set to false, because the hash leaf key isn't going to be written
|
||||
// to by the contract execution, and the potential creation is covered by the
|
||||
// intrinsic gas.
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false, false)
|
||||
}
|
||||
|
||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
||||
func (ae *AccessEvents) SlotGas(addr common.Address, slot common.Hash, isWrite bool) uint64 {
|
||||
func (ae *AccessEvents) SlotGas(addr common.Address, slot common.Hash, isWrite, isFill bool) uint64 {
|
||||
treeIndex, subIndex := utils.StorageIndex(slot.Bytes())
|
||||
return ae.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite)
|
||||
return ae.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite, isFill)
|
||||
}
|
||||
|
||||
// touchAddressAndChargeGas adds any missing access event to the access event list, and returns the cold
|
||||
// access cost to be charged, if need be.
|
||||
func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
||||
stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := ae.touchAddress(addr, treeIndex, subIndex, isWrite)
|
||||
func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite, isFill bool) uint64 {
|
||||
stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := ae.touchAddress(addr, treeIndex, subIndex, isWrite, isFill)
|
||||
|
||||
var gas uint64
|
||||
if stemRead {
|
||||
|
|
@ -170,7 +191,7 @@ func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex
|
|||
}
|
||||
|
||||
// touchAddress adds any missing access event to the access event list.
|
||||
func (ae *AccessEvents) touchAddress(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) (bool, bool, bool, bool, bool) {
|
||||
func (ae *AccessEvents) touchAddress(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite, isFill bool) (bool, bool, bool, bool, bool) {
|
||||
branchKey := newBranchAccessKey(addr, treeIndex)
|
||||
chunkKey := newChunkAccessKey(branchKey, subIndex)
|
||||
|
||||
|
|
@ -198,7 +219,11 @@ func (ae *AccessEvents) touchAddress(addr common.Address, treeIndex uint256.Int,
|
|||
chunkWrite = true
|
||||
ae.chunks[chunkKey] |= AccessWitnessWriteFlag
|
||||
}
|
||||
// TODO: charge chunk filling costs if the leaf was previously empty in the state
|
||||
_, ok := ae.fills[chunkKey]
|
||||
if isFill && !ok {
|
||||
chunkFill = true
|
||||
ae.fills[chunkKey] = struct{}{}
|
||||
}
|
||||
}
|
||||
return branchRead, chunkRead, branchWrite, chunkWrite, chunkFill
|
||||
}
|
||||
|
|
@ -228,7 +253,7 @@ func newChunkAccessKey(branchKey branchAccessKey, leafKey byte) chunkAccessKey {
|
|||
}
|
||||
|
||||
// CodeChunksRangeGas is a helper function to touch every chunk in a code range and charge witness gas costs
|
||||
func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC, size uint64, codeLen uint64, isWrite bool) uint64 {
|
||||
func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC, size uint64, codeLen uint64, isWrite, isFill bool) uint64 {
|
||||
// note that in the case where the copied code is outside the range of the
|
||||
// contract code but touches the last leaf with contract code in it,
|
||||
// we don't include the last leaf of code in the AccessWitness. The
|
||||
|
|
@ -251,7 +276,7 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
|
|||
for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ {
|
||||
treeIndex := *uint256.NewInt((chunkNumber + 128) / 256)
|
||||
subIndex := byte((chunkNumber + 128) % 256)
|
||||
gas := ae.touchAddressAndChargeGas(contractAddr, treeIndex, subIndex, isWrite)
|
||||
gas := ae.touchAddressAndChargeGas(contractAddr, treeIndex, subIndex, isWrite, isFill)
|
||||
var overflow bool
|
||||
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
||||
if overflow {
|
||||
|
|
@ -265,8 +290,8 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
|
|||
// amount of gas that it costs.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an
|
||||
// access in read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||
func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite, isFill bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite, isFill)
|
||||
}
|
||||
|
||||
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
||||
|
|
@ -274,6 +299,6 @@ func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 {
|
|||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite, isFill bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite, isFill)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,50 +40,50 @@ func TestAccountHeaderGas(t *testing.T) {
|
|||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost
|
||||
gas := ae.BasicDataGas(testAddr, false)
|
||||
gas := ae.BasicDataGas(testAddr, false, false)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.BasicDataGas(testAddr, false)
|
||||
gas = ae.BasicDataGas(testAddr, false, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check cold read costs in the same group no longer incur the branch read cost
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
gas = ae.CodeHashGas(testAddr, false, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
|
||||
// Check cold write cost
|
||||
gas = ae.BasicDataGas(testAddr, true)
|
||||
gas = ae.BasicDataGas(testAddr, true, false)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm write cost
|
||||
gas = ae.BasicDataGas(testAddr, true)
|
||||
gas = ae.BasicDataGas(testAddr, true, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check a write without a read charges both read and write costs
|
||||
gas = ae.BasicDataGas(testAddr2, true)
|
||||
gas = ae.BasicDataGas(testAddr2, true, false)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that a write followed by a read charges nothing
|
||||
gas = ae.BasicDataGas(testAddr2, false)
|
||||
gas = ae.BasicDataGas(testAddr2, false, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check that reading a slot from the account header only charges the
|
||||
// chunk read cost.
|
||||
gas = ae.SlotGas(testAddr, common.Hash{}, false)
|
||||
gas = ae.SlotGas(testAddr, common.Hash{}, false, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
|
|
@ -124,11 +124,11 @@ func TestMessageCallGas(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check that reading the basic data and code hash of the same account does not incur the branch read cost
|
||||
gas = ae.BasicDataGas(testAddr, false)
|
||||
gas = ae.BasicDataGas(testAddr, false, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
gas = ae.CodeHashGas(testAddr, false, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||
|
||||
// add the coinbase to the witness iff the fee is greater than 0
|
||||
if rules.IsEIP4762 && fee.Sign() != 0 {
|
||||
st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true)
|
||||
st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
|
|||
self: AccountRef(addr),
|
||||
}
|
||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
||||
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
|
||||
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false, false)
|
||||
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
|
||||
scope.Contract.Gas = 0
|
||||
return nil, ErrOutOfGas
|
||||
|
|
@ -368,7 +368,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
|||
// touch next chunk if PUSH1 is at the boundary. if so, *pc has
|
||||
// advanced past this boundary.
|
||||
contractAddr := scope.Contract.Address()
|
||||
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false)
|
||||
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, false)
|
||||
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
|
||||
scope.Contract.Gas = 0
|
||||
return nil, ErrOutOfGas
|
||||
|
|
@ -396,7 +396,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
|
|||
|
||||
if !scope.Contract.IsDeployment {
|
||||
contractAddr := scope.Contract.Address()
|
||||
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false)
|
||||
statelessGas := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, false)
|
||||
if !scope.Contract.UseGas(statelessGas, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) {
|
||||
scope.Contract.Gas = 0
|
||||
return nil, ErrOutOfGas
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
if !evm.StateDB.Exist(addr) {
|
||||
if !isPrecompile && evm.chainRules.IsEIP4762 {
|
||||
// add proof of absence to witness
|
||||
wgas := evm.AccessEvents.AddAccount(addr, false)
|
||||
wgas := evm.AccessEvents.AddAccount(addr, false, false)
|
||||
if gas < wgas {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
return nil, 0, ErrOutOfGas
|
||||
|
|
@ -552,11 +552,11 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu
|
|||
}
|
||||
} else {
|
||||
// Contract creation completed, touch the missing fields in the contract
|
||||
if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) {
|
||||
if !contract.UseGas(evm.AccessEvents.AddAccount(address, true, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
|
||||
if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) {
|
||||
if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
|||
}
|
||||
if evm.chainRules.IsEIP4762 {
|
||||
if transfersValue {
|
||||
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address))
|
||||
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address, !evm.StateDB.Exist(address)))
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
|
|
@ -432,7 +432,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
|
|||
address := common.Address(stack.Back(1).Bytes20())
|
||||
transfersValue := !stack.Back(2).IsZero()
|
||||
if transfersValue {
|
||||
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address))
|
||||
gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address, !evm.StateDB.Exist(address)))
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ type StateDB interface {
|
|||
AddPreimage(common.Hash, []byte)
|
||||
|
||||
Witness() *stateless.Witness
|
||||
|
||||
StateExists(common.Address, common.Hash) bool
|
||||
}
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
|
|
|
|||
|
|
@ -229,7 +229,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
|
||||
// associated costs.
|
||||
contractAddr := contract.Address()
|
||||
contract.Gas -= in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false)
|
||||
contract.Gas -= in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, false)
|
||||
}
|
||||
|
||||
// Get the operation from the jump table and validate the stack to ensure there are
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ import (
|
|||
)
|
||||
|
||||
func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true)
|
||||
slotnr := stack.peek().Bytes32()
|
||||
gas := evm.AccessEvents.SlotGas(contract.Address(), slotnr, true, !evm.StateDB.StateExists(contract.Address(), slotnr))
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
|
|
@ -31,7 +32,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) {
|
||||
gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false)
|
||||
gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false, false)
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
|
|
@ -40,7 +41,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) {
|
||||
address := stack.peek().Bytes20()
|
||||
gas := evm.AccessEvents.BasicDataGas(address, false)
|
||||
gas := evm.AccessEvents.BasicDataGas(address, false, false)
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
|
|
@ -52,7 +53,7 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
|||
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||
return 0, nil
|
||||
}
|
||||
gas := evm.AccessEvents.BasicDataGas(address, false)
|
||||
gas := evm.AccessEvents.BasicDataGas(address, false, false)
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
|
|
@ -64,7 +65,7 @@ func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
|||
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||
return 0, nil
|
||||
}
|
||||
gas := evm.AccessEvents.CodeHashGas(address, false)
|
||||
gas := evm.AccessEvents.CodeHashGas(address, false, false)
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
|
|
@ -101,15 +102,15 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem
|
|||
return 0, nil
|
||||
}
|
||||
contractAddr := contract.Address()
|
||||
statelessGas := evm.AccessEvents.BasicDataGas(contractAddr, false)
|
||||
statelessGas := evm.AccessEvents.BasicDataGas(contractAddr, false, false)
|
||||
if contractAddr != beneficiaryAddr {
|
||||
statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, false)
|
||||
statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, false, false)
|
||||
}
|
||||
// Charge write costs if it transfers value
|
||||
if evm.StateDB.GetBalance(contractAddr).Sign() != 0 {
|
||||
statelessGas += evm.AccessEvents.BasicDataGas(contractAddr, true)
|
||||
statelessGas += evm.AccessEvents.BasicDataGas(contractAddr, true, false)
|
||||
if contractAddr != beneficiaryAddr {
|
||||
statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, true)
|
||||
statelessGas += evm.AccessEvents.BasicDataGas(beneficiaryAddr, true, !evm.StateDB.Exist(beneficiaryAddr))
|
||||
}
|
||||
}
|
||||
return statelessGas, nil
|
||||
|
|
@ -130,7 +131,7 @@ func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
|||
}
|
||||
_, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64())
|
||||
if !contract.IsDeployment {
|
||||
gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
|
||||
gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false, false)
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
|
|
@ -142,7 +143,7 @@ func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memo
|
|||
return 0, err
|
||||
}
|
||||
addr := common.Address(stack.peek().Bytes20())
|
||||
wgas := evm.AccessEvents.BasicDataGas(addr, false)
|
||||
wgas := evm.AccessEvents.BasicDataGas(addr, false, false)
|
||||
if wgas == 0 {
|
||||
wgas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue