mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
implement FILL_COST
This commit is contained in:
parent
944718bf16
commit
5f9e1a1e11
5 changed files with 81 additions and 52 deletions
|
|
@ -44,14 +44,16 @@ var zeroTreeIndex uint256.Int
|
||||||
type AccessEvents struct {
|
type AccessEvents struct {
|
||||||
branches map[branchAccessKey]mode
|
branches map[branchAccessKey]mode
|
||||||
chunks map[chunkAccessKey]mode
|
chunks map[chunkAccessKey]mode
|
||||||
|
fills map[chunkAccessKey]struct{}
|
||||||
|
|
||||||
pointCache *utils.PointCache
|
pointCache *utils.PointCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAccessEvents(pointCache *utils.PointCache) *AccessEvents {
|
func NewAccessEvents(pointCache *utils.PointCache, fills map[chunkAccessKey]struct{}) *AccessEvents {
|
||||||
return &AccessEvents{
|
return &AccessEvents{
|
||||||
branches: make(map[branchAccessKey]mode),
|
branches: make(map[branchAccessKey]mode),
|
||||||
chunks: make(map[chunkAccessKey]mode),
|
chunks: make(map[chunkAccessKey]mode),
|
||||||
|
fills: fills,
|
||||||
pointCache: pointCache,
|
pointCache: pointCache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +68,9 @@ func (ae *AccessEvents) Merge(other *AccessEvents) {
|
||||||
for k, chunk := range other.chunks {
|
for k, chunk := range other.chunks {
|
||||||
ae.chunks[k] |= chunk
|
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
|
// Keys returns, predictably, the list of keys that were touched during the
|
||||||
|
|
@ -85,6 +90,7 @@ func (ae *AccessEvents) Copy() *AccessEvents {
|
||||||
cpy := &AccessEvents{
|
cpy := &AccessEvents{
|
||||||
branches: maps.Clone(ae.branches),
|
branches: maps.Clone(ae.branches),
|
||||||
chunks: maps.Clone(ae.chunks),
|
chunks: maps.Clone(ae.chunks),
|
||||||
|
fills: maps.Clone(ae.fills),
|
||||||
pointCache: ae.pointCache,
|
pointCache: ae.pointCache,
|
||||||
}
|
}
|
||||||
return cpy
|
return cpy
|
||||||
|
|
@ -92,13 +98,13 @@ func (ae *AccessEvents) Copy() *AccessEvents {
|
||||||
|
|
||||||
// AddAccount returns the gas to be charged for each of the currently cold
|
// AddAccount returns the gas to be charged for each of the currently cold
|
||||||
// member fields of an account.
|
// 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
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite, isFill)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite, isFill)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite, isFill)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite, isFill)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite, isFill)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,28 +113,28 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||||
// call to that account.
|
// call to that account.
|
||||||
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false, false)
|
||||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false, false)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValueTransferGas returns the gas to be charged for each of the currently
|
// ValueTransferGas returns the gas to be charged for each of the currently
|
||||||
// cold balance member fields of the caller and the callee accounts.
|
// 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
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true, false)
|
||||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true, isFill)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||||
// a contract creation.
|
// a contract creation.
|
||||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue, isFill bool) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true, true)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true, true)
|
||||||
if createSendsValue {
|
if createSendsValue {
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true, isFill)
|
||||||
}
|
}
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
@ -136,33 +142,33 @@ func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsVa
|
||||||
// AddTxOrigin adds the member fields of the sender account to the access event list,
|
// 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.
|
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||||
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false, false)
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true, false)
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true, false)
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false, false)
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTxDestination adds the member fields of the sender account to the access event list,
|
// 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.
|
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||||
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue, isFill bool) {
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false, false)
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue, isFill)
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false, false)
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false, false)
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
// 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())
|
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
|
// touchAddressAndChargeGas adds any missing access event to the access event list, and returns the cold
|
||||||
// access cost to be charged, if need be.
|
// access cost to be charged, if need be.
|
||||||
func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
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)
|
stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := ae.touchAddress(addr, treeIndex, subIndex, isWrite, isFill)
|
||||||
|
|
||||||
var gas uint64
|
var gas uint64
|
||||||
if stemRead {
|
if stemRead {
|
||||||
|
|
@ -184,7 +190,7 @@ func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// touchAddress adds any missing access event to the access event list.
|
// 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)
|
branchKey := newBranchAccessKey(addr, treeIndex)
|
||||||
chunkKey := newChunkAccessKey(branchKey, subIndex)
|
chunkKey := newChunkAccessKey(branchKey, subIndex)
|
||||||
|
|
||||||
|
|
@ -212,7 +218,12 @@ func (ae *AccessEvents) touchAddress(addr common.Address, treeIndex uint256.Int,
|
||||||
chunkWrite = true
|
chunkWrite = true
|
||||||
ae.chunks[chunkKey] |= AccessWitnessWriteFlag
|
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
|
return branchRead, chunkRead, branchWrite, chunkWrite, chunkFill
|
||||||
}
|
}
|
||||||
|
|
@ -242,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
|
// 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
|
// 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,
|
// 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
|
// we don't include the last leaf of code in the AccessWitness. The
|
||||||
|
|
@ -265,7 +276,7 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
|
||||||
for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ {
|
for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ {
|
||||||
treeIndex := *uint256.NewInt((chunkNumber + 128) / 256)
|
treeIndex := *uint256.NewInt((chunkNumber + 128) / 256)
|
||||||
subIndex := byte((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
|
var overflow bool
|
||||||
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
||||||
if overflow {
|
if overflow {
|
||||||
|
|
@ -280,7 +291,7 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
|
||||||
// Note that an access in write mode implies an access in read mode, whereas an
|
// 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.
|
// access in read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
||||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BalanceGas adds the account's balance to the accessed data, and returns the
|
// BalanceGas adds the account's balance to the accessed data, and returns the
|
||||||
|
|
@ -288,8 +299,8 @@ func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
||||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
// 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
|
// 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.
|
// read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite, isFill bool) uint64 {
|
||||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite, isFill)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NonceGas adds the account's nonce to the accessed data, and returns the
|
// NonceGas adds the account's nonce to the accessed data, and returns the
|
||||||
|
|
@ -298,7 +309,7 @@ func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 {
|
||||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
// 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.
|
// read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
|
||||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeSizeGas adds the account's code size to the accessed data, and returns the
|
// CodeSizeGas adds the account's code size to the accessed data, and returns the
|
||||||
|
|
@ -307,7 +318,7 @@ func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
|
||||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
// 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.
|
// read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
||||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
||||||
|
|
@ -316,5 +327,5 @@ func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
||||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
// 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.
|
// read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
||||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite, false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cockroachdb/pebble"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
|
|
@ -35,6 +36,7 @@ import (
|
||||||
"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"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
@ -1484,3 +1486,13 @@ func (s *StateDB) PointCache() *utils.PointCache {
|
||||||
func (s *StateDB) Witness() *stateless.Witness {
|
func (s *StateDB) Witness() *stateless.Witness {
|
||||||
return s.witness
|
return s.witness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) IsSlotFilled(addr common.Address, slot common.Hash) bool {
|
||||||
|
// The snapshot can not be used, because it uses the old encoding where
|
||||||
|
// no difference is made between 0 and no data.
|
||||||
|
_, err := s.db.DiskDB().Get(utils.StorageSlotKeyWithEvaluatedAddress(s.accessList.pointCache.GetTreeKeyHeader(addr[:]), slot[:]))
|
||||||
|
// The error needs to be checked because we want to be future-proof
|
||||||
|
// and not rely on the length of the encoding, in case 0-values are
|
||||||
|
// somehow compressed later.
|
||||||
|
return errors.Is(pebble.ErrNotFound, err) || errors.Is(memorydb.ErrMemorydbNotFound, err)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,8 @@ type StateDB interface {
|
||||||
AddPreimage(common.Hash, []byte)
|
AddPreimage(common.Hash, []byte)
|
||||||
|
|
||||||
Witness() *stateless.Witness
|
Witness() *stateless.Witness
|
||||||
|
|
||||||
|
IsSlotFilled(common.Address, common.Hash) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,11 @@ 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(), stack.peek().Bytes32(), true)
|
var (
|
||||||
|
addr = contract.Address()
|
||||||
|
slot = common.Hash(stack.peek().Bytes32())
|
||||||
|
)
|
||||||
|
gas := evm.AccessEvents.SlotGas(addr, slot, true, evm.StateDB.IsSlotFilled(addr, slot))
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
gas = params.WarmStorageReadCostEIP2929
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +35,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(), stack.peek().Bytes32(), false)
|
gas := evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false, false)
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
gas = params.WarmStorageReadCostEIP2929
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
}
|
}
|
||||||
|
|
@ -40,7 +44,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.AccessEvents.BalanceGas(address, false, false)
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
gas = params.WarmStorageReadCostEIP2929
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
}
|
}
|
||||||
|
|
@ -104,15 +108,15 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem
|
||||||
contractAddr := contract.Address()
|
contractAddr := contract.Address()
|
||||||
statelessGas := evm.AccessEvents.VersionGas(contractAddr, false)
|
statelessGas := evm.AccessEvents.VersionGas(contractAddr, false)
|
||||||
statelessGas += evm.AccessEvents.CodeSizeGas(contractAddr, false)
|
statelessGas += evm.AccessEvents.CodeSizeGas(contractAddr, false)
|
||||||
statelessGas += evm.AccessEvents.BalanceGas(contractAddr, false)
|
statelessGas += evm.AccessEvents.BalanceGas(contractAddr, false, false)
|
||||||
if contractAddr != beneficiaryAddr {
|
if contractAddr != beneficiaryAddr {
|
||||||
statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, false)
|
statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, false, 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.AccessEvents.BalanceGas(contractAddr, true, false)
|
||||||
if contractAddr != beneficiaryAddr {
|
if contractAddr != beneficiaryAddr {
|
||||||
statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, true)
|
statelessGas += evm.AccessEvents.BalanceGas(beneficiaryAddr, true, !evm.StateDB.Exist(beneficiaryAddr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return statelessGas, nil
|
return statelessGas, nil
|
||||||
|
|
@ -133,7 +137,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(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
|
gas += evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false, false)
|
||||||
}
|
}
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ var (
|
||||||
// invocation of a data access operation.
|
// invocation of a data access operation.
|
||||||
errMemorydbClosed = errors.New("database closed")
|
errMemorydbClosed = errors.New("database closed")
|
||||||
|
|
||||||
// errMemorydbNotFound is returned if a key is requested that is not found in
|
// ErrMemorydbNotFound is returned if a key is requested that is not found in
|
||||||
// the provided memory database.
|
// the provided memory database.
|
||||||
errMemorydbNotFound = errors.New("not found")
|
ErrMemorydbNotFound = errors.New("not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Database is an ephemeral key-value store. Apart from basic data storage
|
// Database is an ephemeral key-value store. Apart from basic data storage
|
||||||
|
|
@ -94,7 +94,7 @@ func (db *Database) Get(key []byte) ([]byte, error) {
|
||||||
if entry, ok := db.db[string(key)]; ok {
|
if entry, ok := db.db[string(key)]; ok {
|
||||||
return common.CopyBytes(entry), nil
|
return common.CopyBytes(entry), nil
|
||||||
}
|
}
|
||||||
return nil, errMemorydbNotFound
|
return nil, ErrMemorydbNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put inserts the given value into the key-value store.
|
// Put inserts the given value into the key-value store.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue