mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
simplified gas accounting layer (#405)
* simplified gas accounting layer * integrate some review feedback * Apply suggestions from code review Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> * more suggestions from code review * don't charge creation gas + charge code chunks in create * A couple more fixes * make linter happy * fix create init gas consumption issue * fix: in gas funcs, use tx witness instead of global witness * fix linter issue * Apply suggestions from code review Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix: EXTCODECOPY gas consumption * fix warm gas costs * fix the order gas is charged in during contract creation epilogue * fix selfdestruct * fix #365 in eip rewrite (#407) * fix: OOG type in code creation OOG (#408) * core/vm: charge BLOCKHASH witness cost (#409) * core/vm: charge BLOCKHASH witness cost Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * remove gas optimization for now Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * remove redundant logic for contract creation (#413) Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix precompile address check for charging witness costs & fix missing value-bearing rule (#412) Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * core/vm: fix wrong check (#416) Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * charge for account creation if selfdestruct creates a new account (#417) * add key comparison test (#418) * core/vm: charge contract init before execution logic (#419) * core/vm: charge contract init before execution logic Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> * fix CREATE2 as well --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> * quell linter --------- Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com>
This commit is contained in:
parent
0d70489104
commit
1930b97b65
20 changed files with 424 additions and 283 deletions
|
|
@ -32,7 +32,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
"github.com/ethereum/go-ethereum/trie/utils"
|
||||||
"github.com/ethereum/go-verkle"
|
"github.com/ethereum/go-verkle"
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Proof-of-stake protocol constants.
|
// Proof-of-stake protocol constants.
|
||||||
|
|
@ -357,11 +356,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
|
||||||
state.AddBalance(w.Address, amount)
|
state.AddBalance(w.Address, amount)
|
||||||
|
|
||||||
// The returned gas is not charged
|
// The returned gas is not charged
|
||||||
state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.VersionLeafKey)
|
state.Witness().TouchFullAccount(w.Address[:], true)
|
||||||
state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.BalanceLeafKey)
|
|
||||||
state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.NonceLeafKey)
|
|
||||||
state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.CodeKeccakLeafKey)
|
|
||||||
state.Witness().TouchAddressOnWriteAndComputeGas(w.Address[:], uint256.Int{}, utils.CodeSizeLeafKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -568,19 +566,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
|
||||||
r.Div(r, big8)
|
r.Div(r, big8)
|
||||||
|
|
||||||
// This should not happen, but it's useful for replay tests
|
// This should not happen, but it's useful for replay tests
|
||||||
if config.IsPrague(header.Number, header.Time) {
|
|
||||||
state.Witness().TouchAddressOnReadAndComputeGas(uncle.Coinbase.Bytes(), uint256.Int{}, utils.BalanceLeafKey)
|
|
||||||
}
|
|
||||||
state.AddBalance(uncle.Coinbase, r)
|
state.AddBalance(uncle.Coinbase, r)
|
||||||
|
|
||||||
r.Div(blockReward, big32)
|
r.Div(blockReward, big32)
|
||||||
reward.Add(reward, r)
|
reward.Add(reward, r)
|
||||||
}
|
}
|
||||||
if config.IsPrague(header.Number, header.Time) {
|
|
||||||
state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.BalanceLeafKey)
|
|
||||||
state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.VersionLeafKey)
|
|
||||||
state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.NonceLeafKey)
|
|
||||||
state.Witness().TouchAddressOnReadAndComputeGas(header.Coinbase.Bytes(), uint256.Int{}, utils.CodeKeccakLeafKey)
|
|
||||||
}
|
|
||||||
state.AddBalance(header.Coinbase, reward)
|
state.AddBalance(header.Coinbase, reward)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
"github.com/ethereum/go-ethereum/trie/utils"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -88,27 +89,25 @@ func (aw *AccessWitness) Copy() *AccessWitness {
|
||||||
return naw
|
return naw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchAndChargeProofOfAbsence(addr []byte) uint64 {
|
func (aw *AccessWitness) TouchFullAccount(addr []byte, isWrite bool) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.VersionLeafKey)
|
for i := utils.VersionLeafKey; i <= utils.CodeSizeLeafKey; i++ {
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.BalanceLeafKey)
|
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, byte(i), isWrite)
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey)
|
}
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey)
|
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.NonceLeafKey)
|
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchAndChargeMessageCall(addr []byte) uint64 {
|
func (aw *AccessWitness) TouchAndChargeMessageCall(addr []byte) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.VersionLeafKey)
|
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||||
gas += aw.TouchAddressOnReadAndComputeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey)
|
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchAndChargeValueTransfer(callerAddr, targetAddr []byte) uint64 {
|
func (aw *AccessWitness) TouchAndChargeValueTransfer(callerAddr, targetAddr []byte) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey)
|
gas += aw.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey)
|
gas += aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,33 +115,18 @@ func (aw *AccessWitness) TouchAndChargeValueTransfer(callerAddr, targetAddr []by
|
||||||
// a contract creation
|
// a contract creation
|
||||||
func (aw *AccessWitness) TouchAndChargeContractCreateInit(addr []byte, createSendsValue bool) uint64 {
|
func (aw *AccessWitness) TouchAndChargeContractCreateInit(addr []byte, createSendsValue bool) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.VersionLeafKey)
|
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.NonceLeafKey)
|
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||||
if createSendsValue {
|
if createSendsValue {
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.BalanceLeafKey)
|
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||||
}
|
}
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// TouchAndChargeContractCreateCompleted charges access access costs after
|
|
||||||
// the completion of a contract creation to populate the created account in
|
|
||||||
// the tree
|
|
||||||
func (aw *AccessWitness) TouchAndChargeContractCreateCompleted(addr []byte) uint64 {
|
|
||||||
var gas uint64
|
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.VersionLeafKey)
|
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.BalanceLeafKey)
|
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey)
|
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey)
|
|
||||||
gas += aw.TouchAddressOnWriteAndComputeGas(addr, zeroTreeIndex, utils.NonceLeafKey)
|
|
||||||
return gas
|
|
||||||
}
|
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchTxOriginAndComputeGas(originAddr []byte) uint64 {
|
func (aw *AccessWitness) TouchTxOriginAndComputeGas(originAddr []byte) uint64 {
|
||||||
aw.TouchAddressOnReadAndComputeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey)
|
for i := utils.VersionLeafKey; i <= utils.CodeSizeLeafKey; i++ {
|
||||||
aw.TouchAddressOnReadAndComputeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey)
|
aw.touchAddressAndChargeGas(originAddr, zeroTreeIndex, byte(i), i == utils.BalanceLeafKey || i == utils.NonceLeafKey)
|
||||||
aw.TouchAddressOnReadAndComputeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey)
|
}
|
||||||
aw.TouchAddressOnWriteAndComputeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey)
|
|
||||||
aw.TouchAddressOnWriteAndComputeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey)
|
|
||||||
|
|
||||||
// Kaustinen note: we're currently experimenting with stop chargin gas for the origin address
|
// Kaustinen note: we're currently experimenting with stop chargin gas for the origin address
|
||||||
// so simple transfer still take 21000 gas. This is to potentially avoid breaking existing tooling.
|
// so simple transfer still take 21000 gas. This is to potentially avoid breaking existing tooling.
|
||||||
|
|
@ -152,14 +136,14 @@ func (aw *AccessWitness) TouchTxOriginAndComputeGas(originAddr []byte) uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchTxExistingAndComputeGas(targetAddr []byte, sendsValue bool) uint64 {
|
func (aw *AccessWitness) TouchTxExistingAndComputeGas(targetAddr []byte, sendsValue bool) uint64 {
|
||||||
aw.TouchAddressOnReadAndComputeGas(targetAddr, zeroTreeIndex, utils.VersionLeafKey)
|
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||||
aw.TouchAddressOnReadAndComputeGas(targetAddr, zeroTreeIndex, utils.CodeSizeLeafKey)
|
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||||
aw.TouchAddressOnReadAndComputeGas(targetAddr, zeroTreeIndex, utils.CodeKeccakLeafKey)
|
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||||
aw.TouchAddressOnReadAndComputeGas(targetAddr, zeroTreeIndex, utils.NonceLeafKey)
|
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.NonceLeafKey, false)
|
||||||
if sendsValue {
|
if sendsValue {
|
||||||
aw.TouchAddressOnWriteAndComputeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey)
|
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||||
} else {
|
} else {
|
||||||
aw.TouchAddressOnReadAndComputeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey)
|
aw.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kaustinen note: we're currently experimenting with stop chargin gas for the origin address
|
// Kaustinen note: we're currently experimenting with stop chargin gas for the origin address
|
||||||
|
|
@ -169,12 +153,9 @@ func (aw *AccessWitness) TouchTxExistingAndComputeGas(targetAddr []byte, sendsVa
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchAddressOnWriteAndComputeGas(addr []byte, treeIndex uint256.Int, subIndex byte) uint64 {
|
func (aw *AccessWitness) TouchSlotAndChargeGas(addr []byte, slot common.Hash, isWrite bool) uint64 {
|
||||||
return aw.touchAddressAndChargeGas(addr, treeIndex, subIndex, true)
|
treeIndex, subIndex := utils.GetTreeKeyStorageSlotTreeIndexes(slot.Bytes())
|
||||||
}
|
return aw.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite)
|
||||||
|
|
||||||
func (aw *AccessWitness) TouchAddressOnReadAndComputeGas(addr []byte, treeIndex uint256.Int, subIndex byte) uint64 {
|
|
||||||
return aw.touchAddressAndChargeGas(addr, treeIndex, subIndex, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AccessWitness) touchAddressAndChargeGas(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
func (aw *AccessWitness) touchAddressAndChargeGas(addr []byte, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
||||||
|
|
@ -259,3 +240,58 @@ func newChunkAccessKey(branchKey branchAccessKey, leafKey byte) chunkAccessKey {
|
||||||
lk.leafKey = leafKey
|
lk.leafKey = leafKey
|
||||||
return lk
|
return lk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// touchCodeChunksRangeOnReadAndChargeGas is a helper function to touch every chunk in a code range and charge witness gas costs
|
||||||
|
func (aw *AccessWitness) TouchCodeChunksRangeAndChargeGas(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
|
||||||
|
// reason that we do not need the last leaf is the account's code size
|
||||||
|
// is already in the AccessWitness so a stateless verifier can see that
|
||||||
|
// the code from the last leaf is not needed.
|
||||||
|
if (codeLen == 0 && size == 0) || startPC > codeLen {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
endPC := startPC + size
|
||||||
|
if endPC > codeLen {
|
||||||
|
endPC = codeLen
|
||||||
|
}
|
||||||
|
if endPC > 0 {
|
||||||
|
endPC -= 1 // endPC is the last bytecode that will be touched.
|
||||||
|
}
|
||||||
|
|
||||||
|
var statelessGasCharged uint64
|
||||||
|
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)
|
||||||
|
var overflow bool
|
||||||
|
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
||||||
|
if overflow {
|
||||||
|
panic("overflow when adding gas")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return statelessGasCharged
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *AccessWitness) TouchVersion(addr []byte, isWrite bool) uint64 {
|
||||||
|
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *AccessWitness) TouchBalance(addr []byte, isWrite bool) uint64 {
|
||||||
|
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *AccessWitness) TouchNonce(addr []byte, isWrite bool) uint64 {
|
||||||
|
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *AccessWitness) TouchCodeSize(addr []byte, isWrite bool) uint64 {
|
||||||
|
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *AccessWitness) TouchCodeHash(addr []byte, isWrite bool) uint64 {
|
||||||
|
return aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1367,7 +1367,7 @@ 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.IsBerlin {
|
if rules.IsEIP2929 {
|
||||||
// Clear out any leftover from previous executions
|
// Clear out any leftover from previous executions
|
||||||
al := newAccessList()
|
al := newAccessList()
|
||||||
s.accessList = al
|
s.accessList = al
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import (
|
||||||
"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"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
|
||||||
tutils "github.com/ethereum/go-ethereum/trie/utils"
|
tutils "github.com/ethereum/go-ethereum/trie/utils"
|
||||||
"github.com/ethereum/go-verkle"
|
"github.com/ethereum/go-verkle"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -261,7 +260,7 @@ func (kvm *keyValueMigrator) addAccount(addr []byte, acc *types.StateAccount) {
|
||||||
binary.LittleEndian.PutUint64(nonce[:8], acc.Nonce)
|
binary.LittleEndian.PutUint64(nonce[:8], acc.Nonce)
|
||||||
leafNodeData.Values[tutils.NonceLeafKey] = nonce[:]
|
leafNodeData.Values[tutils.NonceLeafKey] = nonce[:]
|
||||||
|
|
||||||
leafNodeData.Values[tutils.CodeKeccakLeafKey] = acc.CodeHash[:]
|
leafNodeData.Values[tutils.CodeHashLeafKey] = acc.CodeHash[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kvm *keyValueMigrator) addAccountCode(addr []byte, codeSize uint64, chunks []byte) {
|
func (kvm *keyValueMigrator) addAccountCode(addr []byte, codeSize uint64, chunks []byte) {
|
||||||
|
|
@ -369,7 +368,13 @@ func (kvm *keyValueMigrator) migrateCollectedKeyValues(tree *trie.VerkleTrie) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertBlockHashHistoryAtEip2935Fork handles the insertion of all previous 256
|
||||||
|
// blocks on the eip2935 activation block. It also adds the account header of the
|
||||||
|
// history contract to the witness.
|
||||||
func InsertBlockHashHistoryAtEip2935Fork(statedb *state.StateDB, prevNumber uint64, prevHash common.Hash, chain consensus.ChainHeaderReader) {
|
func InsertBlockHashHistoryAtEip2935Fork(statedb *state.StateDB, prevNumber uint64, prevHash common.Hash, chain consensus.ChainHeaderReader) {
|
||||||
|
// Make sure that the historical contract is added to the witness
|
||||||
|
statedb.Witness().TouchFullAccount(params.HistoryStorageAddress[:], true)
|
||||||
|
|
||||||
ancestor := chain.GetHeader(prevHash, prevNumber)
|
ancestor := chain.GetHeader(prevHash, prevNumber)
|
||||||
for i := prevNumber; i > 0 && i >= prevNumber-params.Eip2935BlockHashHistorySize; i-- {
|
for i := prevNumber; i > 0 && i >= prevNumber-params.Eip2935BlockHashHistorySize; i-- {
|
||||||
ProcessParentBlockHash(statedb, i, ancestor.Hash())
|
ProcessParentBlockHash(statedb, i, ancestor.Hash())
|
||||||
|
|
@ -382,6 +387,5 @@ func ProcessParentBlockHash(statedb *state.StateDB, prevNumber uint64, prevHash
|
||||||
var key common.Hash
|
var key common.Hash
|
||||||
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
||||||
statedb.SetState(params.HistoryStorageAddress, key, prevHash)
|
statedb.SetState(params.HistoryStorageAddress, key, prevHash)
|
||||||
index, suffix := utils.GetTreeKeyStorageSlotTreeIndexes(key[:])
|
statedb.Witness().TouchSlotAndChargeGas(params.HistoryStorageAddress[:], key, true)
|
||||||
statedb.Witness().TouchAddressOnWriteAndComputeGas(params.HistoryStorageAddress[:], *index, suffix)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
//"fmt"
|
//"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -37,7 +40,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
"github.com/ethereum/go-ethereum/trie/utils"
|
||||||
|
|
||||||
//"github.com/ethereum/go-ethereum/rlp"
|
//"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -472,11 +477,19 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
loggerCfg = &logger.Config{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
os.MkdirAll("output", 0755)
|
||||||
|
traceFile, err := os.Create("./output/traces.jsonl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Verkle trees use the snapshot, which must be enabled before the
|
// Verkle trees use the snapshot, which must be enabled before the
|
||||||
// data is saved into the tree+database.
|
// data is saved into the tree+database.
|
||||||
genesis := gspec.MustCommit(bcdb)
|
genesis := gspec.MustCommit(bcdb)
|
||||||
blockchain, _ := NewBlockChain(bcdb, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(bcdb, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{Tracer: logger.NewJSONLogger(loggerCfg, traceFile)}, nil, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
// Commit the genesis block to the block-generation database as it
|
// Commit the genesis block to the block-generation database as it
|
||||||
|
|
@ -485,8 +498,8 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
|
|
||||||
txCost1 := params.TxGas
|
txCost1 := params.TxGas
|
||||||
txCost2 := params.TxGas
|
txCost2 := params.TxGas
|
||||||
contractCreationCost := intrinsicContractCreationGas + uint64(5600+700+700+700 /* creation with value */ +2739 /* execution costs */)
|
contractCreationCost := intrinsicContractCreationGas + uint64(5600+700+700+700 /* creation with value */ +1439 /* execution costs */)
|
||||||
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(5600+700 /* creation */ +302044 /* execution costs */)
|
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(5600+700 /* creation */ +44044 /* execution costs */)
|
||||||
blockGasUsagesExpected := []uint64{
|
blockGasUsagesExpected := []uint64{
|
||||||
txCost1*2 + txCost2,
|
txCost1*2 + txCost2,
|
||||||
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
||||||
|
|
@ -513,6 +526,33 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
kvjson, err := json.Marshal(keyvals)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile("./output/statediffs.json", kvjson, 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
blockrlp, err := rlp.EncodeToBytes(genesis)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(fmt.Sprintf("./output/block%d.rlp.hex", 0), []byte(fmt.Sprintf("%x", blockrlp)), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, block := range chain {
|
||||||
|
blockrlp, err := rlp.EncodeToBytes(block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(fmt.Sprintf("./output/block%d.rlp.hex", block.NumberU64()), []byte(fmt.Sprintf("%x", blockrlp)), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Uncomment to extract block #2
|
// Uncomment to extract block #2
|
||||||
//f, _ := os.Create("block2.rlp")
|
//f, _ := os.Create("block2.rlp")
|
||||||
//defer f.Close()
|
//defer f.Close()
|
||||||
|
|
@ -521,7 +561,7 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
//f.Write(buf.Bytes())
|
//f.Write(buf.Bytes())
|
||||||
//fmt.Printf("root= %x\n", chain[0].Root())
|
//fmt.Printf("root= %x\n", chain[0].Root())
|
||||||
// check the proof for the last block
|
// check the proof for the last block
|
||||||
err := trie.DeserializeAndVerifyVerkleProof(proofs[1], chain[0].Root().Bytes(), chain[1].Root().Bytes(), keyvals[1])
|
err = trie.DeserializeAndVerifyVerkleProof(proofs[1], chain[0].Root().Bytes(), chain[1].Root().Bytes(), keyvals[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -913,7 +953,7 @@ func TestProcessVerklExtCodeHashOpcode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
codeHashStateDiff := statediff[1][stateDiffIdx].SuffixDiffs[0]
|
codeHashStateDiff := statediff[1][stateDiffIdx].SuffixDiffs[0]
|
||||||
if codeHashStateDiff.Suffix != utils.CodeKeccakLeafKey {
|
if codeHashStateDiff.Suffix != utils.CodeHashLeafKey {
|
||||||
t.Fatalf("code hash invalid suffix")
|
t.Fatalf("code hash invalid suffix")
|
||||||
}
|
}
|
||||||
if codeHashStateDiff.CurrentValue == nil {
|
if codeHashStateDiff.CurrentValue == nil {
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
|
|
@ -405,7 +402,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
st.gasRemaining -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
if rules.IsPrague {
|
if rules.IsEIP4762 {
|
||||||
targetAddr := msg.To
|
targetAddr := msg.To
|
||||||
originAddr := msg.From
|
originAddr := msg.From
|
||||||
|
|
||||||
|
|
@ -413,7 +410,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
if !tryConsumeGas(&st.gasRemaining, statelessGasOrigin) {
|
if !tryConsumeGas(&st.gasRemaining, statelessGasOrigin) {
|
||||||
return nil, fmt.Errorf("%w: Insufficient funds to cover witness access costs for transaction: have %d, want %d", ErrInsufficientBalanceWitness, st.gasRemaining, gas)
|
return nil, fmt.Errorf("%w: Insufficient funds to cover witness access costs for transaction: have %d, want %d", ErrInsufficientBalanceWitness, st.gasRemaining, gas)
|
||||||
}
|
}
|
||||||
originNonce := st.evm.StateDB.GetNonce(originAddr)
|
|
||||||
|
|
||||||
if msg.To != nil {
|
if msg.To != nil {
|
||||||
statelessGasDest := st.evm.Accesses.TouchTxExistingAndComputeGas(targetAddr.Bytes(), msg.Value.Sign() != 0)
|
statelessGasDest := st.evm.Accesses.TouchTxExistingAndComputeGas(targetAddr.Bytes(), msg.Value.Sign() != 0)
|
||||||
|
|
@ -423,11 +419,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
|
|
||||||
// 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)
|
||||||
} else {
|
|
||||||
contractAddr := crypto.CreateAddress(originAddr, originNonce)
|
|
||||||
if !tryConsumeGas(&st.gasRemaining, st.evm.Accesses.TouchAndChargeContractCreateInit(contractAddr.Bytes(), msg.Value.Sign() != 0)) {
|
|
||||||
return nil, fmt.Errorf("%w: Insufficient funds to cover witness access costs for transaction: have %d, want %d", ErrInsufficientBalanceWitness, st.gasRemaining, gas)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,12 +471,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
st.state.AddBalance(st.evm.Context.Coinbase, fee)
|
st.state.AddBalance(st.evm.Context.Coinbase, fee)
|
||||||
|
|
||||||
// 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.IsPrague && fee.Sign() != 0 {
|
if rules.IsEIP4762 && fee.Sign() != 0 {
|
||||||
st.evm.Accesses.TouchAddressOnWriteAndComputeGas(st.evm.Context.Coinbase[:], uint256.Int{}, utils.VersionLeafKey)
|
st.evm.Accesses.TouchFullAccount(st.evm.Context.Coinbase[:], true)
|
||||||
st.evm.Accesses.TouchAddressOnWriteAndComputeGas(st.evm.Context.Coinbase[:], uint256.Int{}, utils.BalanceLeafKey)
|
|
||||||
st.evm.Accesses.TouchAddressOnWriteAndComputeGas(st.evm.Context.Coinbase[:], uint256.Int{}, utils.NonceLeafKey)
|
|
||||||
st.evm.Accesses.TouchAddressOnWriteAndComputeGas(st.evm.Context.Coinbase[:], uint256.Int{}, utils.CodeKeccakLeafKey)
|
|
||||||
st.evm.Accesses.TouchAddressOnWriteAndComputeGas(st.evm.Context.Coinbase[:], uint256.Int{}, utils.CodeSizeLeafKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ var activators = map[int]func(*JumpTable){
|
||||||
1884: enable1884,
|
1884: enable1884,
|
||||||
1344: enable1344,
|
1344: enable1344,
|
||||||
1153: enable1153,
|
1153: enable1153,
|
||||||
|
4762: enable4762,
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableEIP enables the given EIP on the config.
|
// EnableEIP enables the given EIP on the config.
|
||||||
|
|
@ -303,3 +304,29 @@ func enable6780(jt *JumpTable) {
|
||||||
maxStack: maxStack(1, 0),
|
maxStack: maxStack(1, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enable4762(jt *JumpTable) {
|
||||||
|
jt[SSTORE].constantGas = 0
|
||||||
|
jt[SSTORE].dynamicGas = gasSStore4762
|
||||||
|
jt[SLOAD].constantGas = 0
|
||||||
|
jt[SLOAD].dynamicGas = gasSLoad4762
|
||||||
|
jt[BALANCE].dynamicGas = gasBalance4762
|
||||||
|
jt[BALANCE].constantGas = 0
|
||||||
|
jt[EXTCODESIZE].constantGas = 0
|
||||||
|
jt[EXTCODESIZE].dynamicGas = gasExtCodeSize4762
|
||||||
|
jt[EXTCODEHASH].constantGas = 0
|
||||||
|
jt[EXTCODEHASH].dynamicGas = gasExtCodeHash4762
|
||||||
|
jt[EXTCODECOPY].constantGas = 0
|
||||||
|
jt[EXTCODECOPY].dynamicGas = gasExtCodeCopyEIP4762
|
||||||
|
jt[SELFDESTRUCT].dynamicGas = gasSelfdestructEIP4762
|
||||||
|
jt[CREATE].constantGas = params.CreateNGasEip4762
|
||||||
|
jt[CREATE2].constantGas = params.CreateNGasEip4762
|
||||||
|
jt[CALL].constantGas = 0
|
||||||
|
jt[CALL].dynamicGas = gasCallEIP4762
|
||||||
|
jt[CALLCODE].constantGas = 0
|
||||||
|
jt[CALLCODE].dynamicGas = gasCallCodeEIP4762
|
||||||
|
jt[STATICCALL].constantGas = 0
|
||||||
|
jt[STATICCALL].dynamicGas = gasStaticCallEIP4762
|
||||||
|
jt[DELEGATECALL].constantGas = 0
|
||||||
|
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP4762
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,20 +178,6 @@ func (evm *EVM) SetBlockContext(blockCtx BlockContext) {
|
||||||
evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil, timestamp)
|
evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tryConsumeGas tries to subtract gas from gasPool, setting the result in gasPool
|
|
||||||
// if subtracting more gas than remains in gasPool, set gasPool = 0 and return false
|
|
||||||
// otherwise, do the subtraction setting the result in gasPool and return true
|
|
||||||
func tryConsumeGas(gasPool *uint64, gas uint64) bool {
|
|
||||||
// XXX check this is still needed as a func
|
|
||||||
if *gasPool < gas {
|
|
||||||
*gasPool = 0
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
*gasPool -= gas
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call executes the contract associated with the addr with the given input as
|
// Call executes the contract associated with the addr with the given input as
|
||||||
// parameters. It also handles any necessary value transfer required and takes
|
// parameters. It also handles any necessary value transfer required and takes
|
||||||
// the necessary steps to create accounts and reverses the state in case of an
|
// the necessary steps to create accounts and reverses the state in case of an
|
||||||
|
|
@ -211,11 +197,17 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
|
|
||||||
var creation bool
|
var creation bool
|
||||||
if !evm.StateDB.Exist(addr) {
|
if !evm.StateDB.Exist(addr) {
|
||||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
if !isPrecompile && evm.chainRules.IsEIP4762 {
|
||||||
if evm.chainRules.IsPrague {
|
// add proof of absence to witness
|
||||||
// proof of absence
|
wgas := evm.Accesses.TouchFullAccount(addr.Bytes(), false)
|
||||||
tryConsumeGas(&gas, evm.Accesses.TouchAndChargeProofOfAbsence(addr.Bytes()))
|
if gas < wgas {
|
||||||
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
return nil, 0, ErrOutOfGas
|
||||||
}
|
}
|
||||||
|
gas -= wgas
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||||
// Calling a non existing account, don't do anything, but ping the tracer
|
// Calling a non existing account, don't do anything, but ping the tracer
|
||||||
if debug {
|
if debug {
|
||||||
if evm.depth == 0 {
|
if evm.depth == 0 {
|
||||||
|
|
@ -463,7 +455,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
|
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
|
||||||
// the access-list change should not be rolled back
|
// the access-list change should not be rolled back
|
||||||
if evm.chainRules.IsBerlin {
|
if evm.chainRules.IsEIP2929 {
|
||||||
evm.StateDB.AddAddressToAccessList(address)
|
evm.StateDB.AddAddressToAccessList(address)
|
||||||
}
|
}
|
||||||
// Ensure there's no existing contract already at the designated address
|
// Ensure there's no existing contract already at the designated address
|
||||||
|
|
@ -486,6 +478,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
contract.SetCodeOptionalHash(&address, codeAndHash)
|
contract.SetCodeOptionalHash(&address, codeAndHash)
|
||||||
contract.IsDeployment = true
|
contract.IsDeployment = true
|
||||||
|
|
||||||
|
// Charge the contract creation init gas in verkle mode
|
||||||
|
var err error
|
||||||
|
if evm.chainRules.IsEIP4762 {
|
||||||
|
if !contract.UseGas(evm.Accesses.TouchAndChargeContractCreateInit(address.Bytes(), value.Sign() != 0)) {
|
||||||
|
err = ErrOutOfGas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if evm.Config.Tracer != nil {
|
if evm.Config.Tracer != nil {
|
||||||
if evm.depth == 0 {
|
if evm.depth == 0 {
|
||||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
|
evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
|
||||||
|
|
@ -494,7 +494,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := evm.interpreter.Run(contract, nil, false)
|
var ret []byte
|
||||||
|
if err == nil {
|
||||||
|
ret, err = evm.interpreter.Run(contract, nil, false)
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether the max code size has been exceeded, assign err if the case.
|
// Check whether the max code size has been exceeded, assign err if the case.
|
||||||
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
||||||
|
|
@ -511,20 +514,24 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
// be stored due to not enough gas set an error and let it be handled
|
// be stored due to not enough gas set an error and let it be handled
|
||||||
// by the error checking condition below.
|
// by the error checking condition below.
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
if !evm.chainRules.IsEIP4762 {
|
||||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||||
if contract.UseGas(createDataGas) {
|
if !contract.UseGas(createDataGas) {
|
||||||
evm.StateDB.SetCode(address, ret)
|
err = ErrCodeStoreOutOfGas
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Contract creation completed, touch the missing fields in the contract
|
||||||
|
if !contract.UseGas(evm.Accesses.TouchFullAccount(address.Bytes()[:], true)) {
|
||||||
|
err = ErrCodeStoreOutOfGas
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && len(ret) > 0 && !contract.UseGas(evm.Accesses.TouchCodeChunksRangeAndChargeGas(address.Bytes(), 0, uint64(len(ret)), uint64(len(ret)), true)) {
|
||||||
err = ErrCodeStoreOutOfGas
|
err = ErrCodeStoreOutOfGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && evm.chainRules.IsPrague {
|
if err == nil {
|
||||||
if len(ret) > 0 {
|
evm.StateDB.SetCode(address, ret)
|
||||||
touchCodeChunksRangeOnReadAndChargeGas(address.Bytes(), 0, uint64(len(ret)), uint64(len(ret)), evm.Accesses)
|
|
||||||
}
|
|
||||||
if !contract.UseGas(evm.Accesses.TouchAndChargeContractCreateCompleted(address.Bytes()[:])) {
|
|
||||||
err = ErrOutOfGas
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
trieUtils "github.com/ethereum/go-ethereum/trie/utils"
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
|
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
|
||||||
|
|
@ -100,24 +98,12 @@ var (
|
||||||
|
|
||||||
func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
usedGas := uint64(0)
|
usedGas := uint64(0)
|
||||||
slot := stack.Back(0)
|
|
||||||
address := slot.Bytes20()
|
|
||||||
if evm.chainRules.IsPrague {
|
|
||||||
usedGas += evm.TxContext.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, trieUtils.CodeSizeLeafKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return usedGas, nil
|
return usedGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gasSLoad(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSLoad(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
usedGas := uint64(0)
|
usedGas := uint64(0)
|
||||||
|
|
||||||
if evm.chainRules.IsPrague {
|
|
||||||
where := stack.Back(0)
|
|
||||||
treeIndex, subIndex := trieUtils.GetTreeKeyStorageSlotTreeIndexes(where.Bytes())
|
|
||||||
usedGas += evm.Accesses.TouchAddressOnReadAndComputeGas(contract.Address().Bytes(), *treeIndex, subIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
return usedGas, nil
|
return usedGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -405,7 +391,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
} else if !evm.StateDB.Exist(address) {
|
} else if !evm.StateDB.Exist(address) {
|
||||||
gas += params.CallNewAccountGas
|
gas += params.CallNewAccountGas
|
||||||
}
|
}
|
||||||
if transfersValue {
|
if transfersValue && !evm.chainRules.IsEIP4762 {
|
||||||
gas += params.CallValueTransferGas
|
gas += params.CallValueTransferGas
|
||||||
}
|
}
|
||||||
memoryGas, err := memoryGasCost(mem, memorySize)
|
memoryGas, err := memoryGasCost(mem, memorySize)
|
||||||
|
|
@ -424,13 +410,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if evm.chainRules.IsPrague {
|
if evm.chainRules.IsEIP4762 {
|
||||||
if _, isPrecompile := evm.precompile(address); !isPrecompile {
|
|
||||||
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes()[:]))
|
|
||||||
if overflow {
|
|
||||||
return 0, ErrGasUintOverflow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if transfersValue {
|
if transfersValue {
|
||||||
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeValueTransfer(contract.Address().Bytes()[:], address.Bytes()[:]))
|
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeValueTransfer(contract.Address().Bytes()[:], address.Bytes()[:]))
|
||||||
if overflow {
|
if overflow {
|
||||||
|
|
@ -451,7 +431,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
|
||||||
gas uint64
|
gas uint64
|
||||||
overflow bool
|
overflow bool
|
||||||
)
|
)
|
||||||
if stack.Back(2).Sign() != 0 {
|
if stack.Back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 {
|
||||||
gas += params.CallValueTransferGas
|
gas += params.CallValueTransferGas
|
||||||
}
|
}
|
||||||
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
||||||
|
|
@ -464,10 +444,11 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
|
||||||
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if evm.chainRules.IsPrague {
|
if evm.chainRules.IsEIP4762 {
|
||||||
address := common.Address(stack.Back(1).Bytes20())
|
address := common.Address(stack.Back(1).Bytes20())
|
||||||
if _, isPrecompile := evm.precompile(address); !isPrecompile {
|
transfersValue := !stack.Back(2).IsZero()
|
||||||
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes()))
|
if transfersValue {
|
||||||
|
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeValueTransfer(contract.Address().Bytes()[:], address.Bytes()[:]))
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
@ -489,15 +470,6 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if evm.chainRules.IsPrague {
|
|
||||||
address := common.Address(stack.Back(1).Bytes20())
|
|
||||||
if _, isPrecompile := evm.precompile(address); !isPrecompile {
|
|
||||||
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes()))
|
|
||||||
if overflow {
|
|
||||||
return 0, ErrGasUintOverflow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,15 +486,6 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
||||||
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if evm.chainRules.IsPrague {
|
|
||||||
address := common.Address(stack.Back(1).Bytes20())
|
|
||||||
if _, isPrecompile := evm.precompile(address); !isPrecompile {
|
|
||||||
gas, overflow = math.SafeAdd(gas, evm.Accesses.TouchAndChargeMessageCall(address.Bytes()))
|
|
||||||
if overflow {
|
|
||||||
return 0, ErrGasUintOverflow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,10 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"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/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -264,13 +262,6 @@ func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
slot := scope.Stack.peek()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
|
||||||
statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, utils.BalanceLeafKey)
|
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
|
||||||
scope.Contract.Gas = 0
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -355,13 +346,6 @@ func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
slot := scope.Stack.peek()
|
slot := scope.Stack.peek()
|
||||||
address := slot.Bytes20()
|
address := slot.Bytes20()
|
||||||
cs := uint64(interpreter.evm.StateDB.GetCodeSize(address))
|
cs := uint64(interpreter.evm.StateDB.GetCodeSize(address))
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
|
||||||
statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, utils.CodeSizeLeafKey)
|
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
|
||||||
scope.Contract.Gas = 0
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slot.SetUint64(cs)
|
slot.SetUint64(cs)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -386,8 +370,8 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
|
|
||||||
contractAddr := scope.Contract.Address()
|
contractAddr := scope.Contract.Address()
|
||||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||||
if interpreter.evm.chainRules.IsPrague && !scope.Contract.IsDeployment {
|
if interpreter.evm.chainRules.IsEIP4762 && !scope.Contract.IsDeployment {
|
||||||
statelessGas := touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], copyOffset, nonPaddedCopyLength, uint64(len(scope.Contract.Code)), interpreter.evm.Accesses)
|
statelessGas := interpreter.evm.Accesses.TouchCodeChunksRangeAndChargeGas(contractAddr[:], copyOffset, nonPaddedCopyLength, uint64(len(scope.Contract.Code)), false)
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
scope.Contract.Gas = 0
|
scope.Contract.Gas = 0
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
|
|
@ -397,41 +381,6 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// touchCodeChunksRangeOnReadAndChargeGas is a helper function to touch every chunk in a code range and charge witness gas costs
|
|
||||||
func touchCodeChunksRangeOnReadAndChargeGas(contractAddr []byte, startPC, size uint64, codeLen uint64, accesses *state.AccessWitness) 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
|
|
||||||
// reason that we do not need the last leaf is the account's code size
|
|
||||||
// is already in the AccessWitness so a stateless verifier can see that
|
|
||||||
// the code from the last leaf is not needed.
|
|
||||||
if (codeLen == 0 && size == 0) || startPC > codeLen {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
endPC := startPC + size
|
|
||||||
if endPC > codeLen {
|
|
||||||
endPC = codeLen
|
|
||||||
}
|
|
||||||
if endPC > 0 {
|
|
||||||
endPC -= 1 // endPC is the last bytecode that will be touched.
|
|
||||||
}
|
|
||||||
|
|
||||||
var statelessGasCharged uint64
|
|
||||||
for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ {
|
|
||||||
treeIndex := *uint256.NewInt((chunkNumber + 128) / 256)
|
|
||||||
subIndex := byte((chunkNumber + 128) % 256)
|
|
||||||
gas := accesses.TouchAddressOnReadAndComputeGas(contractAddr, treeIndex, subIndex)
|
|
||||||
var overflow bool
|
|
||||||
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
|
||||||
if overflow {
|
|
||||||
panic("overflow when adding gas")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return statelessGasCharged
|
|
||||||
}
|
|
||||||
|
|
||||||
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
stack = scope.Stack
|
stack = scope.Stack
|
||||||
|
|
@ -445,14 +394,14 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
uint64CodeOffset = 0xffffffffffffffff
|
uint64CodeOffset = 0xffffffffffffffff
|
||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
if interpreter.evm.chainRules.IsEIP4762 {
|
||||||
code := interpreter.evm.StateDB.GetCode(addr)
|
code := interpreter.evm.StateDB.GetCode(addr)
|
||||||
contract := &Contract{
|
contract := &Contract{
|
||||||
Code: code,
|
Code: code,
|
||||||
self: AccountRef(addr),
|
self: AccountRef(addr),
|
||||||
}
|
}
|
||||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
||||||
statelessGas := touchCodeChunksRangeOnReadAndChargeGas(addr[:], copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), interpreter.evm.Accesses)
|
statelessGas := interpreter.evm.Accesses.TouchCodeChunksRangeAndChargeGas(addr[:], copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false)
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
scope.Contract.Gas = 0
|
scope.Contract.Gas = 0
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
|
|
@ -495,13 +444,6 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
slot := scope.Stack.peek()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
|
||||||
statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, utils.CodeKeccakLeafKey)
|
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
|
||||||
scope.Contract.Gas = 0
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if interpreter.evm.StateDB.Empty(address) {
|
if interpreter.evm.StateDB.Empty(address) {
|
||||||
slot.Clear()
|
slot.Clear()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -516,13 +458,12 @@ func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockHashFromContract(number uint64, statedb StateDB, witness *state.AccessWitness) common.Hash {
|
func getBlockHashFromContract(number uint64, statedb StateDB, witness *state.AccessWitness) (common.Hash, uint64) {
|
||||||
ringIndex := number % params.Eip2935BlockHashHistorySize
|
ringIndex := number % params.Eip2935BlockHashHistorySize
|
||||||
var pnum common.Hash
|
var pnum common.Hash
|
||||||
binary.BigEndian.PutUint64(pnum[24:], ringIndex)
|
binary.BigEndian.PutUint64(pnum[24:], ringIndex)
|
||||||
treeIndex, suffix := utils.GetTreeKeyStorageSlotTreeIndexes(pnum.Bytes())
|
statelessGas := witness.TouchSlotAndChargeGas(params.HistoryStorageAddress[:], pnum, false)
|
||||||
witness.TouchAddressOnReadAndComputeGas(params.HistoryStorageAddress[:], *treeIndex, suffix)
|
return statedb.GetState(params.HistoryStorageAddress, pnum), statelessGas
|
||||||
return statedb.GetState(params.HistoryStorageAddress, pnum)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
|
@ -545,7 +486,13 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
||||||
if num64 >= lower && num64 < upper {
|
if num64 >= lower && num64 < upper {
|
||||||
// if Prague is active, read it from the history contract (EIP 2935).
|
// if Prague is active, read it from the history contract (EIP 2935).
|
||||||
if evm.chainRules.IsPrague {
|
if evm.chainRules.IsPrague {
|
||||||
num.SetBytes(getBlockHashFromContract(num64, evm.StateDB, evm.Accesses).Bytes())
|
blockHash, statelessGas := getBlockHashFromContract(num64, evm.StateDB, evm.Accesses)
|
||||||
|
if interpreter.evm.chainRules.IsEIP4762 {
|
||||||
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
|
return nil, ErrExecutionReverted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num.SetBytes(blockHash.Bytes())
|
||||||
} else {
|
} else {
|
||||||
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
||||||
}
|
}
|
||||||
|
|
@ -681,22 +628,25 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
if interpreter.readOnly {
|
if interpreter.readOnly {
|
||||||
return nil, ErrWriteProtection
|
return nil, ErrWriteProtection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value := scope.Stack.pop()
|
||||||
|
if interpreter.evm.chainRules.IsEIP4762 {
|
||||||
|
contractAddress := crypto.CreateAddress(scope.Contract.Address(), interpreter.evm.StateDB.GetNonce(scope.Contract.Address()))
|
||||||
|
statelessGas := interpreter.evm.Accesses.TouchAndChargeContractCreateInit(contractAddress.Bytes()[:], value.Sign() != 0)
|
||||||
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
|
return nil, ErrExecutionReverted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
value = scope.Stack.pop()
|
|
||||||
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
gas = scope.Contract.Gas
|
gas = scope.Contract.Gas
|
||||||
)
|
)
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
|
||||||
contractAddress := crypto.CreateAddress(scope.Contract.Address(), interpreter.evm.StateDB.GetNonce(scope.Contract.Address()))
|
|
||||||
statelessGas := interpreter.evm.Accesses.TouchAndChargeContractCreateInit(contractAddress.Bytes()[:], value.Sign() != 0)
|
|
||||||
if !tryConsumeGas(&gas, statelessGas) {
|
|
||||||
return nil, ErrExecutionReverted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if interpreter.evm.chainRules.IsEIP150 {
|
if interpreter.evm.chainRules.IsEIP150 {
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
|
|
||||||
|
|
@ -739,17 +689,17 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
salt = scope.Stack.pop()
|
salt = scope.Stack.pop()
|
||||||
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
gas = scope.Contract.Gas
|
|
||||||
)
|
)
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
if interpreter.evm.chainRules.IsEIP4762 {
|
||||||
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.Accesses.TouchAndChargeContractCreateInit(contractAddress.Bytes()[:], endowment.Sign() != 0)
|
statelessGas := interpreter.evm.Accesses.TouchAndChargeContractCreateInit(contractAddress.Bytes()[:], endowment.Sign() != 0)
|
||||||
if !tryConsumeGas(&gas, statelessGas) {
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
return nil, ErrExecutionReverted
|
return nil, ErrExecutionReverted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gas = scope.Contract.Gas
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
scope.Contract.UseGas(gas)
|
scope.Contract.UseGas(gas)
|
||||||
|
|
@ -962,22 +912,6 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
||||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
||||||
tracer.CaptureExit([]byte{}, 0, nil)
|
tracer.CaptureExit([]byte{}, 0, nil)
|
||||||
}
|
}
|
||||||
if interpreter.evm.chainRules.IsPrague {
|
|
||||||
contractAddr := scope.Contract.Address()
|
|
||||||
beneficiaryAddr := beneficiary.Bytes20()
|
|
||||||
// If the beneficiary isn't the contract, we need to touch the beneficiary's balance.
|
|
||||||
// If the beneficiary is the contract itself, there're two possibilities:
|
|
||||||
// 1. The contract was created in the same transaction: the balance is already touched (no need to touch again)
|
|
||||||
// 2. The contract wasn't created in the same transaction: there's no net change in balance,
|
|
||||||
// and SELFDESTRUCT will perform no action on the account header. (we touch since we did SubBalance+AddBalance above)
|
|
||||||
if contractAddr != beneficiaryAddr || interpreter.evm.StateDB.WasCreatedInCurrentTx(contractAddr) {
|
|
||||||
statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(beneficiaryAddr[:], uint256.Int{}, utils.BalanceLeafKey)
|
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
|
||||||
scope.Contract.Gas = 0
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1025,7 +959,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
|
||||||
// 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 := touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], *pc+1, uint64(1), uint64(len(scope.Contract.Code)), interpreter.evm.Accesses)
|
statelessGas := interpreter.evm.Accesses.TouchCodeChunksRangeAndChargeGas(contractAddr[:], *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false)
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
scope.Contract.Gas = 0
|
scope.Contract.Gas = 0
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
|
|
@ -1054,7 +988,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
||||||
|
|
||||||
if !scope.Contract.IsDeployment && interpreter.evm.chainRules.IsPrague {
|
if !scope.Contract.IsDeployment && interpreter.evm.chainRules.IsPrague {
|
||||||
contractAddr := scope.Contract.Address()
|
contractAddr := scope.Contract.Address()
|
||||||
statelessGas := touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], uint64(startMin), uint64(pushByteSize), uint64(len(scope.Contract.Code)), interpreter.evm.Accesses)
|
statelessGas := interpreter.evm.Accesses.TouchCodeChunksRangeAndChargeGas(contractAddr[:], uint64(startMin), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false)
|
||||||
if !scope.Contract.UseGas(statelessGas) {
|
if !scope.Contract.UseGas(statelessGas) {
|
||||||
scope.Contract.Gas = 0
|
scope.Contract.Gas = 0
|
||||||
return nil, ErrOutOfGas
|
return nil, ErrOutOfGas
|
||||||
|
|
|
||||||
|
|
@ -179,11 +179,11 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||||
}
|
}
|
||||||
|
|
||||||
if in.evm.chainRules.IsPrague && !contract.IsDeployment {
|
if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment {
|
||||||
// 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 -= touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], pc, 1, uint64(len(contract.Code)), in.evm.TxContext.Accesses)
|
contract.Gas -= in.evm.TxContext.Accesses.TouchCodeChunksRangeAndChargeGas(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
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ func validate(jt JumpTable) JumpTable {
|
||||||
func newPragueInstructionSet() JumpTable {
|
func newPragueInstructionSet() JumpTable {
|
||||||
instructionSet := newShanghaiInstructionSet()
|
instructionSet := newShanghaiInstructionSet()
|
||||||
enable6780(&instructionSet)
|
enable6780(&instructionSet)
|
||||||
|
enable4762(&instructionSet)
|
||||||
return validate(instructionSet)
|
return validate(instructionSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
||||||
|
|
@ -52,11 +51,6 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
||||||
}
|
}
|
||||||
value := common.Hash(y.Bytes32())
|
value := common.Hash(y.Bytes32())
|
||||||
|
|
||||||
if evm.chainRules.IsPrague {
|
|
||||||
treeIndex, subIndex := utils.GetTreeKeyStorageSlotTreeIndexes(x.Bytes())
|
|
||||||
cost += evm.Accesses.TouchAddressOnWriteAndComputeGas(contract.Address().Bytes(), *treeIndex, subIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
// EIP 2200 original clause:
|
// EIP 2200 original clause:
|
||||||
// return params.SloadGasEIP2200, nil
|
// return params.SloadGasEIP2200, nil
|
||||||
|
|
@ -111,13 +105,6 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
slot := common.Hash(loc.Bytes32())
|
slot := common.Hash(loc.Bytes32())
|
||||||
var gasUsed uint64
|
var gasUsed uint64
|
||||||
|
|
||||||
if evm.chainRules.IsPrague {
|
|
||||||
where := stack.Back(0)
|
|
||||||
treeIndex, subIndex := utils.GetTreeKeyStorageSlotTreeIndexes(where.Bytes())
|
|
||||||
addr := contract.Address()
|
|
||||||
gasUsed += evm.Accesses.TouchAddressOnReadAndComputeGas(addr.Bytes(), *treeIndex, subIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check slot presence in the access list
|
// Check slot presence in the access list
|
||||||
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
|
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
|
||||||
// If the caller cannot afford the cost, this change will be rolled back
|
// If the caller cannot afford the cost, this change will be rolled back
|
||||||
|
|
|
||||||
147
core/vm/operations_verkle.go
Normal file
147
core/vm/operations_verkle.go
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
gas := evm.Accesses.TouchSlotAndChargeGas(contract.Address().Bytes(), common.Hash(stack.peek().Bytes32()), true)
|
||||||
|
if gas == 0 {
|
||||||
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
gas := evm.Accesses.TouchSlotAndChargeGas(contract.Address().Bytes(), common.Hash(stack.peek().Bytes32()), false)
|
||||||
|
if gas == 0 {
|
||||||
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
address := stack.peek().Bytes20()
|
||||||
|
gas := evm.Accesses.TouchBalance(address[:], false)
|
||||||
|
if gas == 0 {
|
||||||
|
gas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
address := stack.peek().Bytes20()
|
||||||
|
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
wgas := evm.Accesses.TouchVersion(address[:], false)
|
||||||
|
wgas += evm.Accesses.TouchCodeSize(address[:], false)
|
||||||
|
if wgas == 0 {
|
||||||
|
wgas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
return wgas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
address := stack.peek().Bytes20()
|
||||||
|
if _, isPrecompile := evm.precompile(address); isPrecompile {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
codehashgas := evm.Accesses.TouchCodeHash(address[:], false)
|
||||||
|
if codehashgas == 0 {
|
||||||
|
codehashgas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
return codehashgas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc {
|
||||||
|
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile {
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
wgas := evm.Accesses.TouchAndChargeMessageCall(contract.Address().Bytes())
|
||||||
|
if wgas == 0 {
|
||||||
|
wgas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
return wgas + gas, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
gasCallEIP4762 = makeCallVariantGasEIP4762(gasCall)
|
||||||
|
gasCallCodeEIP4762 = makeCallVariantGasEIP4762(gasCallCode)
|
||||||
|
gasStaticCallEIP4762 = makeCallVariantGasEIP4762(gasStaticCall)
|
||||||
|
gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall)
|
||||||
|
)
|
||||||
|
|
||||||
|
func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
beneficiaryAddr := common.Address(stack.peek().Bytes20())
|
||||||
|
if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
contractAddr := contract.Address()
|
||||||
|
statelessGas := evm.Accesses.TouchVersion(contractAddr[:], false)
|
||||||
|
statelessGas += evm.Accesses.TouchCodeSize(contractAddr[:], false)
|
||||||
|
statelessGas += evm.Accesses.TouchBalance(contractAddr[:], false)
|
||||||
|
if contractAddr != beneficiaryAddr {
|
||||||
|
statelessGas += evm.Accesses.TouchBalance(beneficiaryAddr[:], false)
|
||||||
|
}
|
||||||
|
// Charge write costs if it transfers value
|
||||||
|
if evm.StateDB.GetBalance(contractAddr).Sign() != 0 {
|
||||||
|
statelessGas += evm.Accesses.TouchBalance(contractAddr[:], true)
|
||||||
|
if contractAddr != beneficiaryAddr {
|
||||||
|
statelessGas += evm.Accesses.TouchBalance(beneficiaryAddr[:], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case when the beneficiary does not exist: touch the account
|
||||||
|
// but leave code hash and size alone.
|
||||||
|
if evm.StateDB.Empty(beneficiaryAddr) {
|
||||||
|
statelessGas += evm.Accesses.TouchVersion(beneficiaryAddr[:], true)
|
||||||
|
statelessGas += evm.Accesses.TouchNonce(beneficiaryAddr[:], true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return statelessGas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
// memory expansion first (dynamic part of pre-2929 implementation)
|
||||||
|
gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
addr := common.Address(stack.peek().Bytes20())
|
||||||
|
wgas := evm.Accesses.TouchVersion(addr[:], false)
|
||||||
|
wgas += evm.Accesses.TouchCodeSize(addr[:], false)
|
||||||
|
if wgas == 0 {
|
||||||
|
wgas = params.WarmStorageReadCostEIP2929
|
||||||
|
}
|
||||||
|
var overflow bool
|
||||||
|
// We charge (cold-warm), since 'warm' is already charged as constantGas
|
||||||
|
if gas, overflow = math.SafeAdd(gas, wgas); overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
@ -806,6 +806,7 @@ func (err *ConfigCompatError) Error() string {
|
||||||
type Rules struct {
|
type Rules struct {
|
||||||
ChainID *big.Int
|
ChainID *big.Int
|
||||||
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
||||||
|
IsEIP2929, IsEIP4762 bool
|
||||||
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
|
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
|
||||||
IsBerlin, IsLondon bool
|
IsBerlin, IsLondon bool
|
||||||
IsMerge, IsShanghai, IsCancun, IsPrague bool
|
IsMerge, IsShanghai, IsCancun, IsPrague bool
|
||||||
|
|
@ -828,6 +829,8 @@ 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.IsPrague(num, timestamp),
|
||||||
|
IsEIP4762: c.IsPrague(num, timestamp),
|
||||||
IsLondon: c.IsLondon(num),
|
IsLondon: c.IsLondon(num),
|
||||||
IsMerge: isMerge,
|
IsMerge: isMerge,
|
||||||
IsShanghai: c.IsShanghai(num, timestamp),
|
IsShanghai: c.IsShanghai(num, timestamp),
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ const (
|
||||||
LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
|
LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
|
||||||
CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
|
CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
|
||||||
Create2Gas uint64 = 32000 // Once per CREATE2 operation
|
Create2Gas uint64 = 32000 // Once per CREATE2 operation
|
||||||
|
CreateNGasEip4762 uint64 = 1000 // Once per CREATEn operations post-verkle
|
||||||
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
|
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
|
||||||
MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
|
MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const (
|
||||||
VersionLeafKey = 0
|
VersionLeafKey = 0
|
||||||
BalanceLeafKey = 1
|
BalanceLeafKey = 1
|
||||||
NonceLeafKey = 2
|
NonceLeafKey = 2
|
||||||
CodeKeccakLeafKey = 3
|
CodeHashLeafKey = 3
|
||||||
CodeSizeLeafKey = 4
|
CodeSizeLeafKey = 4
|
||||||
|
|
||||||
maxPointCacheByteSize = 100 << 20
|
maxPointCacheByteSize = 100 << 20
|
||||||
|
|
@ -152,7 +152,7 @@ func GetTreeKeyNonce(address []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTreeKeyCodeKeccak(address []byte) []byte {
|
func GetTreeKeyCodeKeccak(address []byte) []byte {
|
||||||
return GetTreeKey(address, zero, CodeKeccakLeafKey)
|
return GetTreeKey(address, zero, CodeHashLeafKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTreeKeyCodeSize(address []byte) []byte {
|
func GetTreeKeyCodeSize(address []byte) []byte {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,11 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-verkle"
|
"github.com/ethereum/go-verkle"
|
||||||
|
|
@ -77,7 +78,7 @@ func sha256GetTreeKeyCodeSize(addr []byte) []byte {
|
||||||
copy(payload[:len(treeIndexBytes)], treeIndexBytes)
|
copy(payload[:len(treeIndexBytes)], treeIndexBytes)
|
||||||
digest.Write(payload[:])
|
digest.Write(payload[:])
|
||||||
h := digest.Sum(nil)
|
h := digest.Sum(nil)
|
||||||
h[31] = CodeKeccakLeafKey
|
h[31] = CodeHashLeafKey
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,3 +94,22 @@ func BenchmarkSha256Hash(b *testing.B) {
|
||||||
sha256GetTreeKeyCodeSize(addr[:])
|
sha256GetTreeKeyCodeSize(addr[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompareGetTreeKeyWithEvaluated(t *testing.T) {
|
||||||
|
var addr [32]byte
|
||||||
|
rand.Read(addr[:])
|
||||||
|
addrpoint := EvaluateAddressPoint(addr[:])
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
var val [32]byte
|
||||||
|
rand.Read(val[:])
|
||||||
|
n := uint256.NewInt(0).SetBytes(val[:])
|
||||||
|
n.Lsh(n, 8)
|
||||||
|
subindex := val[0]
|
||||||
|
tk1 := GetTreeKey(addr[:], n, subindex)
|
||||||
|
tk2 := GetTreeKeyWithEvaluatedAddess(addrpoint, n, subindex)
|
||||||
|
|
||||||
|
if !bytes.Equal(tk1, tk2) {
|
||||||
|
t.Fatalf("differing key: slot=%x, addr=%x", val, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error
|
||||||
// been recreated after that, then its code keccak will NOT be 0. So return `nil` if
|
// been recreated after that, then its code keccak will NOT be 0. So return `nil` if
|
||||||
// the nonce, and values[10], and code keccak is 0.
|
// the nonce, and values[10], and code keccak is 0.
|
||||||
|
|
||||||
if acc.Nonce == 0 && len(values) > 10 && len(values[10]) > 0 && bytes.Equal(values[utils.CodeKeccakLeafKey], zero[:]) {
|
if acc.Nonce == 0 && len(values) > 10 && len(values[10]) > 0 && bytes.Equal(values[utils.CodeHashLeafKey], zero[:]) {
|
||||||
if !t.ended {
|
if !t.ended {
|
||||||
return nil, errDeletedAccount
|
return nil, errDeletedAccount
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -144,7 +144,7 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
acc.Balance = new(big.Int).SetBytes(balance[:])
|
acc.Balance = new(big.Int).SetBytes(balance[:])
|
||||||
acc.CodeHash = values[utils.CodeKeccakLeafKey]
|
acc.CodeHash = values[utils.CodeHashLeafKey]
|
||||||
// TODO fix the code size as well
|
// TODO fix the code size as well
|
||||||
|
|
||||||
return acc, nil
|
return acc, nil
|
||||||
|
|
@ -164,7 +164,7 @@ func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount)
|
||||||
values[utils.VersionLeafKey] = zero[:]
|
values[utils.VersionLeafKey] = zero[:]
|
||||||
values[utils.NonceLeafKey] = nonce[:]
|
values[utils.NonceLeafKey] = nonce[:]
|
||||||
values[utils.BalanceLeafKey] = balance[:]
|
values[utils.BalanceLeafKey] = balance[:]
|
||||||
values[utils.CodeKeccakLeafKey] = acc.CodeHash[:]
|
values[utils.CodeHashLeafKey] = acc.CodeHash[:]
|
||||||
|
|
||||||
binary.LittleEndian.PutUint64(nonce[:], acc.Nonce)
|
binary.LittleEndian.PutUint64(nonce[:], acc.Nonce)
|
||||||
bbytes := acc.Balance.Bytes()
|
bbytes := acc.Balance.Bytes()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue