mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
more review feedback
This commit is contained in:
parent
d5699fbb2e
commit
04a4fe14d9
3 changed files with 246 additions and 67 deletions
|
|
@ -57,44 +57,44 @@ func NewAccessEvents(pointCache *utils.PointCache) *AccessEvents {
|
|||
// Merge is used to merge the access events that were generated during the
|
||||
// execution of a tx, with the accumulation of all access events that were
|
||||
// generated during the execution of all txs preceding this one in a block.
|
||||
func (aw *AccessEvents) Merge(other *AccessEvents) {
|
||||
func (ae *AccessEvents) Merge(other *AccessEvents) {
|
||||
for k := range other.branches {
|
||||
aw.branches[k] |= other.branches[k]
|
||||
ae.branches[k] |= other.branches[k]
|
||||
}
|
||||
for k, chunk := range other.chunks {
|
||||
aw.chunks[k] |= chunk
|
||||
ae.chunks[k] |= chunk
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns, predictably, the list of keys that were touched during the
|
||||
// buildup of the access witness.
|
||||
func (aw *AccessEvents) Keys() [][]byte {
|
||||
// TODO: consider if parallelizing this is worth it, probably depending on len(aw.chunks).
|
||||
keys := make([][]byte, 0, len(aw.chunks))
|
||||
for chunk := range aw.chunks {
|
||||
basePoint := aw.pointCache.Get(chunk.addr[:])
|
||||
func (ae *AccessEvents) Keys() [][]byte {
|
||||
// TODO: consider if parallelizing this is worth it, probably depending on len(ae.chunks).
|
||||
keys := make([][]byte, 0, len(ae.chunks))
|
||||
for chunk := range ae.chunks {
|
||||
basePoint := ae.pointCache.Get(chunk.addr[:])
|
||||
key := utils.GetTreeKeyWithEvaluatedAddress(basePoint, &chunk.treeIndex, chunk.leafKey)
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (aw *AccessEvents) Copy() *AccessEvents {
|
||||
naw := &AccessEvents{
|
||||
func (ae *AccessEvents) Copy() *AccessEvents {
|
||||
cpy := &AccessEvents{
|
||||
branches: make(map[branchAccessKey]mode),
|
||||
chunks: make(map[chunkAccessKey]mode),
|
||||
pointCache: aw.pointCache,
|
||||
pointCache: ae.pointCache,
|
||||
}
|
||||
naw.Merge(aw)
|
||||
return naw
|
||||
cpy.Merge(ae)
|
||||
return cpy
|
||||
}
|
||||
|
||||
// AddAccount returns the gas to be charged for each of the currently cold
|
||||
// member fields of an account.
|
||||
func (aw *AccessEvents) AddAccount(addr []byte, isWrite bool) uint64 {
|
||||
func (ae *AccessEvents) AddAccount(addr []byte, isWrite bool) uint64 {
|
||||
var gas uint64
|
||||
for i := utils.VersionLeafKey; i <= utils.CodeSizeLeafKey; i++ {
|
||||
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, byte(i), isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, byte(i), isWrite)
|
||||
}
|
||||
return gas
|
||||
}
|
||||
|
|
@ -102,60 +102,60 @@ func (aw *AccessEvents) AddAccount(addr []byte, isWrite bool) uint64 {
|
|||
// MessageCallGas returns the gas to be charged for each of the currently
|
||||
// cold member fields of an account, that need to be touched when making a message
|
||||
// call to that account.
|
||||
func (aw *AccessEvents) MessageCallGas(destination []byte) uint64 {
|
||||
func (ae *AccessEvents) MessageCallGas(destination []byte) uint64 {
|
||||
var gas uint64
|
||||
gas += aw.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
gas += aw.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, 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 (aw *AccessEvents) ValueTransferGas(callerAddr, targetAddr []byte) uint64 {
|
||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr []byte) uint64 {
|
||||
var gas uint64
|
||||
gas += aw.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||
// a contract creation.
|
||||
func (aw *AccessEvents) ContractCreateInitGas(addr []byte, createSendsValue bool) uint64 {
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr []byte, createSendsValue bool) uint64 {
|
||||
var gas uint64
|
||||
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
||||
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
if createSendsValue {
|
||||
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
}
|
||||
return gas
|
||||
}
|
||||
|
||||
// AddTxOrigin adds the member fields of the sender account to the witness,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (aw *AccessEvents) AddTxOrigin(originAddr []byte) {
|
||||
func (ae *AccessEvents) AddTxOrigin(originAddr []byte) {
|
||||
for i := utils.VersionLeafKey; i <= utils.CodeSizeLeafKey; i++ {
|
||||
aw.touchAddressAndChargeGas(originAddr, zeroTreeIndex, byte(i), i == utils.BalanceLeafKey || i == utils.NonceLeafKey)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, byte(i), i == utils.BalanceLeafKey || i == utils.NonceLeafKey)
|
||||
}
|
||||
}
|
||||
|
||||
// AddTxDestination adds the member fields of the sender account to the witness,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (aw *AccessEvents) AddTxDestination(targetAddr []byte, sendsValue bool) {
|
||||
func (ae *AccessEvents) AddTxDestination(targetAddr []byte, sendsValue bool) {
|
||||
for i := utils.VersionLeafKey; i <= utils.CodeSizeLeafKey; i++ {
|
||||
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, byte(i), i == utils.VersionLeafKey && sendsValue)
|
||||
ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, byte(i), i == utils.VersionLeafKey && sendsValue)
|
||||
}
|
||||
}
|
||||
|
||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
||||
func (aw *AccessEvents) SlotGas(addr []byte, slot common.Hash, isWrite bool) uint64 {
|
||||
func (ae *AccessEvents) SlotGas(addr []byte, slot common.Hash, isWrite bool) uint64 {
|
||||
treeIndex, subIndex := utils.StorageIndex(slot.Bytes())
|
||||
return aw.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite)
|
||||
return ae.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite)
|
||||
}
|
||||
|
||||
// touchAddressAndChargeGas adds any missing access event to the witness, and returns the cold
|
||||
// access cost to be charged, if need be.
|
||||
func (aw *AccessEvents) touchAddressAndChargeGas(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
||||
stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := aw.touchAddress(addr, treeIndex, subIndex, isWrite)
|
||||
func (ae *AccessEvents) touchAddressAndChargeGas(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
||||
stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := ae.touchAddress(addr, treeIndex, subIndex, isWrite)
|
||||
|
||||
var gas uint64
|
||||
if stemRead {
|
||||
|
|
@ -178,33 +178,33 @@ func (aw *AccessEvents) touchAddressAndChargeGas(addr []byte, treeIndex uint256.
|
|||
}
|
||||
|
||||
// touchAddress adds any missing access event to the witness.
|
||||
func (aw *AccessEvents) touchAddress(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) (bool, bool, bool, bool, bool) {
|
||||
func (ae *AccessEvents) touchAddress(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) (bool, bool, bool, bool, bool) {
|
||||
branchKey := newBranchAccessKey(addr, treeIndex)
|
||||
chunkKey := newChunkAccessKey(branchKey, subIndex)
|
||||
|
||||
// Read access.
|
||||
var branchRead, chunkRead bool
|
||||
if _, hasStem := aw.branches[branchKey]; !hasStem {
|
||||
if _, hasStem := ae.branches[branchKey]; !hasStem {
|
||||
branchRead = true
|
||||
aw.branches[branchKey] = AccessWitnessReadFlag
|
||||
ae.branches[branchKey] = AccessWitnessReadFlag
|
||||
}
|
||||
if _, hasSelector := aw.chunks[chunkKey]; !hasSelector {
|
||||
if _, hasSelector := ae.chunks[chunkKey]; !hasSelector {
|
||||
chunkRead = true
|
||||
aw.chunks[chunkKey] = AccessWitnessReadFlag
|
||||
ae.chunks[chunkKey] = AccessWitnessReadFlag
|
||||
}
|
||||
|
||||
// Write access.
|
||||
var branchWrite, chunkWrite, chunkFill bool
|
||||
if isWrite {
|
||||
if (aw.branches[branchKey] & AccessWitnessWriteFlag) == 0 {
|
||||
if (ae.branches[branchKey] & AccessWitnessWriteFlag) == 0 {
|
||||
branchWrite = true
|
||||
aw.branches[branchKey] |= AccessWitnessWriteFlag
|
||||
ae.branches[branchKey] |= AccessWitnessWriteFlag
|
||||
}
|
||||
|
||||
chunkValue := aw.chunks[chunkKey]
|
||||
chunkValue := ae.chunks[chunkKey]
|
||||
if (chunkValue & AccessWitnessWriteFlag) == 0 {
|
||||
chunkWrite = true
|
||||
aw.chunks[chunkKey] |= AccessWitnessWriteFlag
|
||||
ae.chunks[chunkKey] |= AccessWitnessWriteFlag
|
||||
}
|
||||
|
||||
// TODO: charge chunk filling costs if the leaf was previously empty in the state
|
||||
|
|
@ -238,7 +238,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 (aw *AccessEvents) CodeChunksRangeGas(contractAddr []byte, startPC, size uint64, codeLen uint64, isWrite bool) uint64 {
|
||||
func (ae *AccessEvents) CodeChunksRangeGas(contractAddr []byte, startPC, size uint64, codeLen uint64, isWrite 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
|
||||
|
|
@ -261,7 +261,7 @@ func (aw *AccessEvents) CodeChunksRangeGas(contractAddr []byte, startPC, size ui
|
|||
for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ {
|
||||
treeIndex := *uint256.NewInt((chunkNumber + 128) / 256)
|
||||
subIndex := byte((chunkNumber + 128) % 256)
|
||||
gas := aw.touchAddressAndChargeGas(contractAddr, treeIndex, subIndex, isWrite)
|
||||
gas := ae.touchAddressAndChargeGas(contractAddr, treeIndex, subIndex, isWrite)
|
||||
var overflow bool
|
||||
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
||||
if overflow {
|
||||
|
|
@ -272,22 +272,47 @@ func (aw *AccessEvents) CodeChunksRangeGas(contractAddr []byte, startPC, size ui
|
|||
return statelessGasCharged
|
||||
}
|
||||
|
||||
func (aw *AccessEvents) VersionGas(addr []byte, isWrite bool) uint64 {
|
||||
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
// VersionGas returns the amount of gas to be charged if the account's version hasn't been
|
||||
// touched in the proper mode. If `isWrite` is `true` then the charged gas is for an access
|
||||
// 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) VersionGas(addr []byte, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
}
|
||||
|
||||
func (aw *AccessEvents) BalanceGas(addr []byte, isWrite bool) uint64 {
|
||||
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
// BalanceGas returns the amount of gas to be charged if the account's balance hasn't been
|
||||
// touched in the proper mode. If `isWrite` is `true` then the charged gas is for an access
|
||||
// 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) BalanceGas(addr []byte, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
func (aw *AccessEvents) NonceGas(addr []byte, isWrite bool) uint64 {
|
||||
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
// NonceGas returns the amount of gas to be charged if the account's nonce hasn't been
|
||||
// touched in the proper mode. If `isWrite` is `true` then the charged gas is for an access
|
||||
// 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) NonceGas(addr []byte, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
func (aw *AccessEvents) CodeSizeGas(addr []byte, isWrite bool) uint64 {
|
||||
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
// CodeSizeGas returns the amount of gas to be charged if the account's code size hasn't been
|
||||
// touched in the proper mode. If `isWrite` is `true` then the charged gas is for an access
|
||||
// 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) CodeSizeGas(addr []byte, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
}
|
||||
|
||||
func (aw *AccessEvents) CodeHashGas(addr []byte, isWrite bool) uint64 {
|
||||
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
// CodeHashGas returns the amount of gas to be charged if the account's code hash hasn't been
|
||||
// touched in the proper mode. If `isWrite` is `true` then the charged gas is for an access
|
||||
// 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 []byte, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
}
|
||||
|
|
|
|||
154
core/state/access_events_test.go
Normal file
154
core/state/access_events_test.go
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright 2021 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 (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
testAddr [20]byte
|
||||
testAddr2 [20]byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := byte(0); i < 20; i++ {
|
||||
testAddr[i] = i
|
||||
testAddr[2] = 2 * i
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountHeaderGas(t *testing.T) {
|
||||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost
|
||||
gas := ae.VersionGas(testAddr[:], false)
|
||||
if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.VersionGas(testAddr[:], 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.BalanceGas(testAddr[:], false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.NonceGas(testAddr[:], false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr[:], false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeHashGas(testAddr[:], false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
|
||||
// Check cold write cost
|
||||
gas = ae.VersionGas(testAddr[:], true)
|
||||
if gas != params.WitnessBranchWriteCost+params.WitnessChunkWriteCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost)
|
||||
}
|
||||
|
||||
// Check warm write cost
|
||||
gas = ae.VersionGas(testAddr[:], true)
|
||||
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.BalanceGas(testAddr2[:], true)
|
||||
if gas != params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost)
|
||||
|
||||
}
|
||||
|
||||
// Check that a write followed by a read charges nothing
|
||||
gas = ae.BalanceGas(testAddr2[:], 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)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
}
|
||||
|
||||
// TestContractCreateInitGas checks that the gas cost of contract creation is correctly
|
||||
// calculated.
|
||||
func TestContractCreateInitGas(t *testing.T) {
|
||||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
var testAddr [20]byte
|
||||
for i := byte(0); i < 20; i++ {
|
||||
testAddr[i] = i
|
||||
}
|
||||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.ContractCreateInitGas(testAddr[:], false)
|
||||
if gas != params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*2+params.WitnessChunkReadCost*2 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*3)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.ContractCreateInitGas(testAddr[:], false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMessageCallGas checks that the gas cost of message calls is correctly
|
||||
// calculated.
|
||||
func TestMessageCallGas(t *testing.T) {
|
||||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.MessageCallGas(testAddr[:])
|
||||
if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost*2 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost*2)
|
||||
}
|
||||
|
||||
// Check that reading the version and code size of the same account does not incur the branch read cost
|
||||
gas = ae.VersionGas(testAddr[:], false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr[:], false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.MessageCallGas(testAddr[:])
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
}
|
||||
|
|
@ -52,12 +52,12 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
|||
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||
return 0, nil
|
||||
}
|
||||
wgas := evm.AccessEvents.VersionGas(address[:], false)
|
||||
wgas += evm.AccessEvents.CodeSizeGas(address[:], false)
|
||||
if wgas == 0 {
|
||||
wgas = params.WarmStorageReadCostEIP2929
|
||||
gas := evm.AccessEvents.VersionGas(address[:], false)
|
||||
gas += evm.AccessEvents.CodeSizeGas(address[:], false)
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
return wgas, nil
|
||||
return gas, nil
|
||||
}
|
||||
|
||||
func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
|
|
@ -65,11 +65,11 @@ func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
|||
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||
return 0, nil
|
||||
}
|
||||
codehashgas := evm.AccessEvents.CodeHashGas(address[:], false)
|
||||
if codehashgas == 0 {
|
||||
codehashgas = params.WarmStorageReadCostEIP2929
|
||||
gas := evm.AccessEvents.CodeHashGas(address[:], false)
|
||||
if gas == 0 {
|
||||
gas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
return codehashgas, nil
|
||||
return gas, nil
|
||||
}
|
||||
|
||||
func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
|
||||
|
|
@ -81,11 +81,11 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
|
|||
if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile {
|
||||
return gas, nil
|
||||
}
|
||||
wgas := evm.AccessEvents.MessageCallGas(contract.Address().Bytes())
|
||||
if wgas == 0 {
|
||||
wgas = params.WarmStorageReadCostEIP2929
|
||||
witnessGas := evm.AccessEvents.MessageCallGas(contract.Address().Bytes())
|
||||
if witnessGas == 0 {
|
||||
witnessGas = params.WarmStorageReadCostEIP2929
|
||||
}
|
||||
return wgas + gas, nil
|
||||
return witnessGas + gas, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue