diff --git a/core/vm/eips.go b/core/vm/eips.go
index ccb099c5e1..caa73e4391 100644
--- a/core/vm/eips.go
+++ b/core/vm/eips.go
@@ -84,15 +84,12 @@ func enable1884(jt *JumpTable) {
jt[SELFBALANCE] = &operation{
execute: opSelfBalance,
constantGas: GasFastStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
}
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
- scope.Stack.push(balance)
- return nil, nil
+ return nil, scope.Stack.push(balance)
}
// enable1344 applies EIP-1344 (ChainID Opcode)
@@ -102,16 +99,13 @@ func enable1344(jt *JumpTable) {
jt[CHAINID] = &operation{
execute: opChainID,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
}
// opChainID implements CHAINID opcode
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
- scope.Stack.push(chainId)
- return nil, nil
+ return nil, scope.Stack.push(chainId)
}
// enable2200 applies EIP-2200 (Rebalance net-metered SSTORE)
@@ -174,8 +168,6 @@ func enable3198(jt *JumpTable) {
jt[BASEFEE] = &operation{
execute: opBaseFee,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
}
@@ -186,21 +178,21 @@ func enable1153(jt *JumpTable) {
jt[TLOAD] = &operation{
execute: opTload,
constantGas: params.WarmStorageReadCostEIP2929,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
}
jt[TSTORE] = &operation{
execute: opTstore,
constantGas: params.WarmStorageReadCostEIP2929,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
}
}
// opTload implements TLOAD opcode
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- loc := scope.Stack.peek()
+ loc, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+
hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
@@ -212,8 +204,11 @@ func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
if interpreter.readOnly {
return nil, ErrWriteProtection
}
- loc := scope.Stack.pop()
- val := scope.Stack.pop()
+ loc, val, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
+
interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
return nil, nil
}
@@ -221,8 +216,7 @@ func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// opBaseFee implements BASEFEE opcode
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
baseFee, _ := uint256.FromBig(interpreter.evm.Context.BaseFee)
- scope.Stack.push(baseFee)
- return nil, nil
+ return nil, scope.Stack.push(baseFee)
}
// enable3855 applies EIP-3855 (PUSH0 opcode)
@@ -231,15 +225,12 @@ func enable3855(jt *JumpTable) {
jt[PUSH0] = &operation{
execute: opPush0,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
}
// opPush0 implements the PUSH0 opcode
func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int))
}
// enable3860 enables "EIP-3860: Limit and meter initcode"
@@ -255,18 +246,25 @@ func enable5656(jt *JumpTable) {
jt[MCOPY] = &operation{
execute: opMcopy,
constantGas: GasFastestStep,
- minStack: minStack(3, 0),
- maxStack: maxStack(3, 0),
}
}
// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryMcopy, scope.Stack, scope.Memory)
+ dst, src, length, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasMcopy(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+
+ mStart := dst
+ if src.Gt(mStart) {
+ mStart = src
+ }
+ memorySize, err := calculateMemorySize(mStart, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryCopierGas(scope.Memory, memorySize, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -275,11 +273,6 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
}
scope.Memory.Resize(memorySize)
- var (
- dst = scope.Stack.pop()
- src = scope.Stack.pop()
- length = scope.Stack.pop()
- )
// These values are checked for overflow during memory expansion calculation
// (the memorySize function on the opcode).
scope.Memory.Copy(dst.Uint64(), src.Uint64(), length.Uint64())
@@ -288,7 +281,11 @@ func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
// opBlobHash implements the BLOBHASH opcode
func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- index := scope.Stack.peek()
+ index, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+
if index.LtUint64(uint64(len(interpreter.evm.TxContext.BlobHashes))) {
blobHash := interpreter.evm.TxContext.BlobHashes[index.Uint64()]
index.SetBytes32(blobHash[:])
@@ -301,13 +298,16 @@ func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
// opBlobBaseFee implements BLOBBASEFEE opcode
func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
blobBaseFee, _ := uint256.FromBig(interpreter.evm.Context.BlobBaseFee)
- scope.Stack.push(blobBaseFee)
- return nil, nil
+ return nil, scope.Stack.push(blobBaseFee)
}
// opCLZ implements the CLZ opcode (count leading zero bytes)
func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x := scope.Stack.peek()
+ x, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+
x.SetUint64(256 - uint64(x.BitLen()))
return nil, nil
}
@@ -317,8 +317,6 @@ func enable4844(jt *JumpTable) {
jt[BLOBHASH] = &operation{
execute: opBlobHash,
constantGas: GasFastestStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
}
}
@@ -327,8 +325,6 @@ func enable7939(jt *JumpTable) {
jt[CLZ] = &operation{
execute: opCLZ,
constantGas: GasFastStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
}
}
@@ -337,8 +333,6 @@ func enable7516(jt *JumpTable) {
jt[BLOBBASEFEE] = &operation{
execute: opBlobBaseFee,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
}
@@ -347,17 +341,20 @@ func enable6780(jt *JumpTable) {
jt[SELFDESTRUCT] = &operation{
execute: opSelfdestructEIP6780,
constantGas: params.SelfdestructGasEIP150,
- minStack: minStack(1, 0),
- maxStack: maxStack(1, 0),
}
}
func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryExtCodeCopy, scope.Stack, scope.Memory)
+ a, memOffset, codeOffset, length, err := scope.Stack.pop4(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasExtCodeCopyEIP4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasExtCodeCopyEIP4762(interpreter.evm, scope.Contract, scope.Memory, memorySize, a, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -366,13 +363,6 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
}
scope.Memory.Resize(memorySize)
- var (
- stack = scope.Stack
- a = stack.pop()
- memOffset = stack.pop()
- codeOffset = stack.pop()
- length = stack.pop()
- )
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = math.MaxUint64
@@ -400,7 +390,9 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
)
*pc += 1
if *pc < codeLen {
- scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc])))
+ if err := scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc]))); err != nil {
+ return nil, err
+ }
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall && *pc%31 == 0 {
// touch next chunk if PUSH1 is at the boundary. if so, *pc has
@@ -412,10 +404,9 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
return nil, ErrOutOfGas
}
}
- } else {
- scope.Stack.push(integer.Clear())
+ return nil, nil
}
- return nil, nil
+ return nil, scope.Stack.push(integer.Clear())
}
func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
@@ -425,12 +416,14 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
start = min(codeLen, int(*pc+1))
end = min(codeLen, start+pushByteSize)
)
- scope.Stack.push(new(uint256.Int).SetBytes(
+ if err := scope.Stack.push(new(uint256.Int).SetBytes(
common.RightPadBytes(
scope.Contract.Code[start:end],
pushByteSize,
)),
- )
+ ); err != nil {
+ return nil, err
+ }
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
contractAddr := scope.Contract.Address()
@@ -448,104 +441,72 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
func enable4762(jt *JumpTable) {
jt[SSTORE] = &operation{
- execute: opSstoreEIP4762,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
+ execute: opSstoreEIP4762,
}
jt[SLOAD] = &operation{
- execute: opSLoadEIP4762,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
+ execute: opSLoadEIP4762,
}
jt[BALANCE] = &operation{
- execute: opBalanceEIP4762,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
+ execute: opBalanceEIP4762,
}
jt[EXTCODESIZE] = &operation{
- execute: opExtCodeSizeEIP4762,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
+ execute: opExtCodeSizeEIP4762,
}
jt[EXTCODEHASH] = &operation{
- execute: opExtCodeHashEIP4762,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
+ execute: opExtCodeHashEIP4762,
}
jt[EXTCODECOPY] = &operation{
- execute: opExtCodeCopyEIP4762,
- minStack: minStack(4, 0),
- maxStack: maxStack(4, 0),
+ execute: opExtCodeCopyEIP4762,
}
jt[CODECOPY] = &operation{
execute: opCodeCopyEIP4762,
constantGas: GasFastestStep,
- minStack: minStack(3, 0),
- maxStack: maxStack(3, 0),
}
jt[SELFDESTRUCT] = &operation{
execute: opSelfdestructEIP4762,
constantGas: params.SelfdestructGasEIP150,
- minStack: minStack(1, 0),
- maxStack: maxStack(1, 0),
}
jt[CREATE] = &operation{
execute: opCreateEIP3860,
constantGas: params.CreateNGasEip4762,
- minStack: minStack(3, 1),
- maxStack: maxStack(3, 1),
}
jt[CREATE2] = &operation{
execute: opCreate2EIP3860,
constantGas: params.CreateNGasEip4762,
- minStack: minStack(4, 1),
- maxStack: maxStack(4, 1),
}
jt[CALL] = &operation{
- execute: opCallEIP4762,
- minStack: minStack(7, 1),
- maxStack: maxStack(7, 1),
+ execute: opCallEIP4762,
}
jt[CALLCODE] = &operation{
- execute: opCallCodeEIP4762,
- minStack: minStack(7, 1),
- maxStack: maxStack(7, 1),
+ execute: opCallCodeEIP4762,
}
jt[STATICCALL] = &operation{
- execute: opStaticCallEIP4762,
- minStack: minStack(6, 1),
- maxStack: maxStack(6, 1),
+ execute: opStaticCallEIP4762,
}
jt[DELEGATECALL] = &operation{
- execute: opDelegateCallEIP4762,
- minStack: minStack(6, 1),
- maxStack: maxStack(6, 1),
+ execute: opDelegateCallEIP4762,
}
jt[PUSH1] = &operation{
execute: opPush1EIP4762,
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
for i := 1; i < 32; i++ {
jt[PUSH1+OpCode(i)] = &operation{
execute: makePushEIP4762(uint64(i+1), i+1),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
}
}
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 2702ef9c5d..514849d96f 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -378,7 +378,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
// but is the correct thing to do and matters on other networks, in tests, and potential
// future scenarios
- evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount)
+ evm.StateDB.AddBalance(addr, common.U2560, tracing.BalanceChangeTouchAccount)
if p, isPrecompile := evm.precompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange)
diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go
index c7c1274bf2..8282167f5c 100644
--- a/core/vm/gas_table.go
+++ b/core/vm/gas_table.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
)
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
@@ -56,50 +57,32 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
return 0, nil
}
-// memoryCopierGas creates the gas functions for the following opcodes, and takes
-// the stack position of the operand which determines the size of the data to copy
-// as argument:
-// CALLDATACOPY (stack position 2)
-// CODECOPY (stack position 2)
-// MCOPY (stack position 2)
-// EXTCODECOPY (stack position 3)
-// RETURNDATACOPY (stack position 2)
-func memoryCopierGas(stackpos int) gasFunc {
- return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- // Gas for expanding the memory
- gas, err := memoryGasCost(mem, memorySize)
- if err != nil {
- return 0, err
- }
- // And gas for copying data, charged per word at param.CopyGas
- words, overflow := stack.Back(stackpos).Uint64WithOverflow()
- if overflow {
- return 0, ErrGasUintOverflow
- }
-
- if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
- return 0, ErrGasUintOverflow
- }
-
- if gas, overflow = math.SafeAdd(gas, words); overflow {
- return 0, ErrGasUintOverflow
- }
- return gas, nil
+// memoryCopierGas
+func memoryCopierGas(mem *Memory, memorySize uint64, words256 *uint256.Int) (uint64, error) {
+ // Gas for expanding the memory
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
}
+ // And gas for copying data, charged per word at param.CopyGas
+ words, overflow := words256.Uint64WithOverflow()
+ if overflow {
+ return 0, ErrGasUintOverflow
+ }
+
+ if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+
+ if gas, overflow = math.SafeAdd(gas, words); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
}
-var (
- gasCallDataCopy = memoryCopierGas(2)
- gasCodeCopy = memoryCopierGas(2)
- gasMcopy = memoryCopierGas(2)
- gasExtCodeCopy = memoryCopierGas(3)
- gasReturnDataCopy = memoryCopierGas(2)
-)
-
-func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasSStore(evm *EVM, contract *Contract, loc, val *uint256.Int) (uint64, error) {
var (
- y, x = stack.Back(1), stack.Back(0)
- current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), x.Bytes32())
+ current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), loc.Bytes32())
)
// The legacy gas metering only takes into consideration the current state
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
@@ -111,9 +94,9 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
// 2. From a non-zero value address to a zero-value address (DELETE)
// 3. From a non-zero to a non-zero (CHANGE)
switch {
- case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0
+ case current == (common.Hash{}) && val.Sign() != 0: // 0 => non 0
return params.SstoreSetGas, nil
- case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0
+ case current != (common.Hash{}) && val.Sign() == 0: // non 0 => 0
evm.StateDB.AddRefund(params.SstoreRefundGas)
return params.SstoreClearGas, nil
default: // non 0 => non 0 (or 0 => 0)
@@ -135,7 +118,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
// (2.2.2.) If original value equals new value (this storage slot is reset)
// (2.2.2.1.) If original value is 0, add 19800 gas to refund counter.
// (2.2.2.2.) Otherwise, add 4800 gas to refund counter.
- value := common.Hash(y.Bytes32())
+ value := common.Hash(val.Bytes32())
if current == value { // noop (1)
return params.NetSstoreNoopGas, nil
}
@@ -180,17 +163,16 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
// (2.2.2.) If original value equals new value (this storage slot is reset):
// (2.2.2.1.) If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter.
// (2.2.2.2.) Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter.
-func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasSStoreEIP2200(evm *EVM, contract *Contract, loc, val *uint256.Int) (uint64, error) {
// If we fail the minimum gas availability invariant, fail (0)
if contract.Gas <= params.SstoreSentryGasEIP2200 {
return 0, errors.New("not enough gas for reentrancy sentry")
}
// Gas sentry honoured, do the actual gas calculation based on the stored value
var (
- y, x = stack.Back(1), stack.Back(0)
- current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), x.Bytes32())
+ current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), loc.Bytes32())
)
- value := common.Hash(y.Bytes32())
+ value := common.Hash(val.Bytes32())
if current == value { // noop (1)
return params.SloadGasEIP2200, nil
@@ -221,42 +203,40 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
return params.SloadGasEIP2200, nil // dirty update (2.2)
}
-func makeGasLog(n uint64) gasFunc {
- return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
- if overflow {
- return 0, ErrGasUintOverflow
- }
-
- gas, err := memoryGasCost(mem, memorySize)
- if err != nil {
- return 0, err
- }
-
- if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
- return 0, ErrGasUintOverflow
- }
- if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
- return 0, ErrGasUintOverflow
- }
-
- var memorySizeGas uint64
- if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
- return 0, ErrGasUintOverflow
- }
- if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
- return 0, ErrGasUintOverflow
- }
- return gas, nil
+func gasLog(mem *Memory, memorySize uint64, n uint64, size *uint256.Int) (uint64, error) {
+ requestedSize, overflow := size.Uint64WithOverflow()
+ if overflow {
+ return 0, ErrGasUintOverflow
}
-}
-func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- wordGas, overflow := stack.Back(1).Uint64WithOverflow()
+
+ if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+
+ var memorySizeGas uint64
+ if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+
+func gasKeccak256(mem *Memory, memorySize uint64, size *uint256.Int) (uint64, error) {
+ gas, err := memoryGasCost(mem, memorySize)
+ if err != nil {
+ return 0, err
+ }
+ wordGas, overflow := size.Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
@@ -269,28 +249,12 @@ func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
return gas, nil
}
-// pureMemoryGascost is used by several operations, which aside from their
-// static cost have a dynamic cost which is solely based on the memory
-// expansion
-func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- return memoryGasCost(mem, memorySize)
-}
-
-var (
- gasReturn = pureMemoryGascost
- gasRevert = pureMemoryGascost
- gasMLoad = pureMemoryGascost
- gasMStore8 = pureMemoryGascost
- gasMStore = pureMemoryGascost
- gasCreate = pureMemoryGascost
-)
-
-func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasCreate2(mem *Memory, memorySize uint64, size *uint256.Int) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- wordGas, overflow := stack.Back(2).Uint64WithOverflow()
+ wordGas, overflow := size.Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
@@ -303,12 +267,12 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
return gas, nil
}
-func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasCreateEip3860(mem *Memory, memorySize uint64, size256 *uint256.Int) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- size, overflow := stack.Back(2).Uint64WithOverflow()
+ size, overflow := size256.Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
@@ -322,12 +286,12 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
}
return gas, nil
}
-func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasCreate2Eip3860(mem *Memory, memorySize uint64, size256 *uint256.Int) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- size, overflow := stack.Back(2).Uint64WithOverflow()
+ size, overflow := size256.Uint64WithOverflow()
if overflow {
return 0, ErrGasUintOverflow
}
@@ -342,8 +306,8 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
return gas, nil
}
-func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
+func gasExpFrontier(exp *uint256.Int) (uint64, error) {
+ expByteLen := uint64((exp.BitLen() + 7) / 8)
var (
gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas
@@ -355,8 +319,8 @@ func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem
return gas, nil
}
-func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
+func gasExpEIP158(exp *uint256.Int) (uint64, error) {
+ expByteLen := uint64((exp.BitLen() + 7) / 8)
var (
gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas
@@ -368,11 +332,11 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
return gas, nil
}
-func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasCall(evm *EVM, contract *Contract, mem *Memory, memorySize uint64, callCost, addr, value *uint256.Int) (uint64, error) {
var (
gas uint64
- transfersValue = !stack.Back(2).IsZero()
- address = common.Address(stack.Back(1).Bytes20())
+ transfersValue = !value.IsZero()
+ address = common.Address(addr.Bytes20())
)
if evm.chainRules.IsEIP158 {
if transfersValue && evm.StateDB.Empty(address) {
@@ -393,7 +357,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
return 0, ErrGasUintOverflow
}
- evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
+ evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, callCost)
if err != nil {
return 0, err
}
@@ -404,7 +368,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
return gas, nil
}
-func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasCallCode(evm *EVM, contract *Contract, mem *Memory, memorySize uint64, callCost, value *uint256.Int) (uint64, error) {
memoryGas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
@@ -413,13 +377,13 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
gas uint64
overflow bool
)
- if stack.Back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 {
+ if value.Sign() != 0 && !evm.chainRules.IsEIP4762 {
gas += params.CallValueTransferGas
}
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
return 0, ErrGasUintOverflow
}
- evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
+ evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, callCost)
if err != nil {
return 0, err
}
@@ -429,12 +393,12 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
return gas, nil
}
-func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasDelegateCall(evm *EVM, contract *Contract, mem *Memory, memorySize uint64, callCost *uint256.Int) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
+ evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, callCost)
if err != nil {
return 0, err
}
@@ -445,12 +409,12 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
return gas, nil
}
-func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasStaticCall(evm *EVM, contract *Contract, mem *Memory, memorySize uint64, callCost *uint256.Int) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
- evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
+ evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, callCost)
if err != nil {
return 0, err
}
@@ -461,12 +425,12 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
return gas, nil
}
-func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasSelfdestruct(evm *EVM, contract *Contract, addr *uint256.Int) (uint64, error) {
var gas uint64
// EIP150 homestead gas reprice fork:
if evm.chainRules.IsEIP150 {
gas = params.SelfdestructGasEIP150
- var address = common.Address(stack.Back(0).Bytes20())
+ var address = common.Address(addr.Bytes20())
if evm.chainRules.IsEIP158 {
// if empty and transfers value
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 95c31a0987..7cb65a82d8 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -29,8 +29,35 @@ import (
// calculateMemorySize calculates the required memory size
// it is important that this function is inlinable
-func calculateMemorySize(memF memorySizeFunc, stack *Stack, mem *Memory) (uint64, error) {
- memSize, overflow := memF(stack)
+func calculateMemorySize(offset, length *uint256.Int) (uint64, error) {
+ memSize, overflow := calcMemSize64(offset, length)
+ return memorySizeCeil(memSize, overflow)
+}
+
+// calculateMemorySizeU64 calculates the required memory size
+// it is important that this function is inlinable
+func calculateMemorySizeU64(offset *uint256.Int, length uint64) (uint64, error) {
+ memSize, overflow := calcMemSize64WithUint(offset, length)
+ return memorySizeCeil(memSize, overflow)
+}
+
+// calculateCallMemorySize calculates the required memory size for a call operation
+func calculateCallMemorySize(argOffset, argSize, retOffset, retSize *uint256.Int) (uint64, error) {
+ x, overflow := calcMemSize64(retOffset, retSize)
+ if overflow {
+ return 0, ErrGasUintOverflow
+ }
+ y, overflow := calcMemSize64(argOffset, argSize)
+ if overflow {
+ return 0, ErrGasUintOverflow
+ }
+ if x > y {
+ return memorySizeCeil(x, false)
+ }
+ return memorySizeCeil(y, false)
+}
+
+func memorySizeCeil(memSize uint64, overflow bool) (uint64, error) {
// memory is expanded in words of 32 bytes. Gas
// is also calculated in words.
if overflow || memSize > math.MaxUint64-31 {
@@ -41,49 +68,74 @@ func calculateMemorySize(memF memorySizeFunc, stack *Stack, mem *Memory) (uint64
}
func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Add(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Add(x, y)
return nil, nil
}
func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Sub(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Sub(x, y)
return nil, nil
}
func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Mul(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Mul(x, y)
return nil, nil
}
func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Div(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Div(x, y)
return nil, nil
}
func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.SDiv(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.SDiv(x, y)
return nil, nil
}
func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Mod(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Mod(x, y)
return nil, nil
}
func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.SMod(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.SMod(x, y)
return nil, nil
}
func opExpEIP158(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasExpEIP158(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ base, exponent, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasExpEIP158(exponent)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -91,11 +143,15 @@ func opExpEIP158(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
return nil, ErrOutOfGas
}
- return opExp(pc, interpreter, scope)
+ return opExp(base, exponent)
}
func opExpFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasExpFrontier(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ base, exponent, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasExpFrontier(exponent)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -103,29 +159,39 @@ func opExpFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
return nil, ErrOutOfGas
}
- return opExp(pc, interpreter, scope)
+ return opExp(base, exponent)
}
-func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- base, exponent := scope.Stack.pop(), scope.Stack.peek()
- exponent.Exp(&base, exponent)
+func opExp(base, exponent *uint256.Int) ([]byte, error) {
+ exponent.Exp(base, exponent)
return nil, nil
}
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- back, num := scope.Stack.pop(), scope.Stack.peek()
- num.ExtendSign(num, &back)
+ back, num, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+
+ num.ExtendSign(num, back)
return nil, nil
}
func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x := scope.Stack.peek()
+ x, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+
x.Not(x)
return nil, nil
}
func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if x.Lt(y) {
y.SetOne()
} else {
@@ -135,7 +201,10 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
}
func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if x.Gt(y) {
y.SetOne()
} else {
@@ -145,7 +214,10 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
}
func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if x.Slt(y) {
y.SetOne()
} else {
@@ -155,7 +227,10 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
}
func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if x.Sgt(y) {
y.SetOne()
} else {
@@ -165,7 +240,10 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
}
func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if x.Eq(y) {
y.SetOne()
} else {
@@ -175,7 +253,11 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte,
}
func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x := scope.Stack.peek()
+ x, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+
if x.IsZero() {
x.SetOne()
} else {
@@ -185,38 +267,56 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
}
func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.And(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.And(x, y)
return nil, nil
}
func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Or(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Or(x, y)
return nil, nil
}
func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y := scope.Stack.pop(), scope.Stack.peek()
- y.Xor(&x, y)
+ x, y, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ y.Xor(x, y)
return nil, nil
}
func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- th, val := scope.Stack.pop(), scope.Stack.peek()
- val.Byte(&th)
+ th, val, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
+ val.Byte(th)
return nil, nil
}
func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
- z.AddMod(&x, &y, z)
+ x, y, z, err := scope.Stack.pop3(1)
+ if err != nil {
+ return nil, err
+ }
+ z.AddMod(x, y, z)
return nil, nil
}
func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
- z.MulMod(&x, &y, z)
+ x, y, z, err := scope.Stack.pop3(1)
+ if err != nil {
+ return nil, err
+ }
+ z.MulMod(x, y, z)
return nil, nil
}
@@ -225,7 +325,10 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
- shift, value := scope.Stack.pop(), scope.Stack.peek()
+ shift, value, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if shift.LtUint64(256) {
value.Lsh(value, uint(shift.Uint64()))
} else {
@@ -239,7 +342,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
- shift, value := scope.Stack.pop(), scope.Stack.peek()
+ shift, value, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if shift.LtUint64(256) {
value.Rsh(value, uint(shift.Uint64()))
} else {
@@ -252,7 +358,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- shift, value := scope.Stack.pop(), scope.Stack.peek()
+ shift, value, err := scope.Stack.pop2(1)
+ if err != nil {
+ return nil, err
+ }
if shift.GtUint64(256) {
if value.Sign() >= 0 {
value.Clear()
@@ -268,11 +377,15 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
}
func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryKeccak256, scope.Stack, scope.Memory)
+ offset, size, err := scope.Stack.pop2(1)
if err != nil {
return nil, err
}
- dynamicCost, err := gasKeccak256(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasKeccak256(scope.Memory, memorySize, size)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -281,9 +394,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
}
scope.Memory.Resize(memorySize)
- offset, size := scope.Stack.pop(), scope.Stack.peek()
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
-
interpreter.hasher.Reset()
interpreter.hasher.Write(data)
interpreter.hasher.Read(interpreter.hasherBuf[:])
@@ -297,12 +408,15 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
}
func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
}
func opBalanceEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasBalance4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasBalance4762(interpreter.evm, scope.Contract, slot)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -310,11 +424,15 @@ func opBalanceEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
return nil, ErrOutOfGas
}
- return opBalance(pc, interpreter, scope)
+ return opBalance(interpreter, slot)
}
func opBalanceEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasEip2929AccountCheck(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasEip2929AccountCheck(interpreter.evm, slot)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -322,33 +440,40 @@ func opBalanceEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
return nil, ErrOutOfGas
}
- return opBalance(pc, interpreter, scope)
+ return opBalance(interpreter, slot)
}
-func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- slot := scope.Stack.peek()
+func opBalanceFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ return opBalance(interpreter, slot)
+}
+
+func opBalance(interpreter *EVMInterpreter, slot *uint256.Int) ([]byte, error) {
address := common.Address(slot.Bytes20())
slot.Set(interpreter.evm.StateDB.GetBalance(address))
return nil, nil
}
func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
}
func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
}
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(scope.Contract.value)
- return nil, nil
+ return nil, scope.Stack.push(scope.Contract.value)
}
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- x := scope.Stack.peek()
+ x, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
if offset, overflow := x.Uint64WithOverflow(); !overflow {
data := getData(scope.Contract.Input, offset, 32)
x.SetBytes(data)
@@ -359,16 +484,20 @@ func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input))))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input))))
}
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCallDataCopy, scope.Stack, scope.Memory)
+ memOffset, dataOffset, length, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallDataCopy(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryCopierGas(scope.Memory, memorySize, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -377,11 +506,6 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
scope.Memory.Resize(memorySize)
- var (
- memOffset = scope.Stack.pop()
- dataOffset = scope.Stack.pop()
- length = scope.Stack.pop()
- )
dataOffset64, overflow := dataOffset.Uint64WithOverflow()
if overflow {
dataOffset64 = math.MaxUint64
@@ -395,16 +519,19 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
}
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryReturnDataCopy, scope.Stack, scope.Memory)
+ memOffset, dataOffset, length, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasReturnDataCopy(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryCopierGas(scope.Memory, memorySize, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -413,19 +540,13 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
}
scope.Memory.Resize(memorySize)
- var (
- memOffset = scope.Stack.pop()
- dataOffset = scope.Stack.pop()
- length = scope.Stack.pop()
- )
-
offset64, overflow := dataOffset.Uint64WithOverflow()
if overflow {
return nil, ErrReturnDataOutOfBounds
}
// we can reuse dataOffset now (aliasing it for clarity)
var end = dataOffset
- end.Add(&dataOffset, &length)
+ end.Add(dataOffset, length)
end64, overflow := end.Uint64WithOverflow()
if overflow || uint64(len(interpreter.returnData)) < end64 {
return nil, ErrReturnDataOutOfBounds
@@ -435,44 +556,62 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
}
func opExtCodeSizeEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasExtCodeSize4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasExtCodeSize4762(interpreter.evm, scope.Contract, slot)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
if !scope.Contract.UseGas(dynamicCost, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallOpCodeDynamic) {
return nil, ErrOutOfGas
}
- return opExtCodeSize(pc, interpreter, scope)
+ return opExtCodeSize(interpreter, slot)
}
func opExtCodeSizeEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasEip2929AccountCheck(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasEip2929AccountCheck(interpreter.evm, slot)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
if !scope.Contract.UseGas(dynamicCost, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallOpCodeDynamic) {
return nil, ErrOutOfGas
}
- return opExtCodeSize(pc, interpreter, scope)
+ return opExtCodeSize(interpreter, slot)
}
-func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- slot := scope.Stack.peek()
+func opExtCodeSizeFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ return opExtCodeSize(interpreter, slot)
+}
+
+func opExtCodeSize(interpreter *EVMInterpreter, slot *uint256.Int) ([]byte, error) {
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
return nil, nil
}
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code))))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code))))
}
func opCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCodeCopy, scope.Stack, scope.Memory)
+ memOffset, codeOffset, length, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCodeCopyEip4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCodeCopyEip4762(interpreter.evm, scope.Contract, scope.Memory, memorySize, codeOffset, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -480,15 +619,19 @@ func opCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCont
return nil, ErrOutOfGas
}
scope.Memory.Resize(memorySize)
- return opCodeCopy(pc, interpreter, scope)
+ return opCodeCopy(scope, memOffset, codeOffset, length)
}
func opCodeCopyFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCodeCopy, scope.Stack, scope.Memory)
+ memOffset, codeOffset, length, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCodeCopy(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryCopierGas(scope.Memory, memorySize, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -496,15 +639,10 @@ func opCodeCopyFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
return nil, ErrOutOfGas
}
scope.Memory.Resize(memorySize)
- return opCodeCopy(pc, interpreter, scope)
+ return opCodeCopy(scope, memOffset, codeOffset, length)
}
-func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- var (
- memOffset = scope.Stack.pop()
- codeOffset = scope.Stack.pop()
- length = scope.Stack.pop()
- )
+func opCodeCopy(scope *ScopeContext, memOffset, codeOffset, length *uint256.Int) ([]byte, error) {
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = math.MaxUint64
@@ -516,11 +654,15 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
func opExtCodeCopyEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryExtCodeCopy, scope.Stack, scope.Memory)
+ a, memOffset, codeOffset, length, err := scope.Stack.pop4(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasExtCodeCopyEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasExtCodeCopyEIP2929(interpreter.evm, scope.Memory, memorySize, a, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -528,15 +670,19 @@ func opExtCodeCopyEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
return nil, ErrOutOfGas
}
scope.Memory.Resize(memorySize)
- return opExtCodeCopy(pc, interpreter, scope)
+ return opExtCodeCopy(interpreter, scope, a, memOffset, codeOffset, length)
}
func opExtCodeCopyFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryExtCodeCopy, scope.Stack, scope.Memory)
+ a, memOffset, codeOffset, length, err := scope.Stack.pop4(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasExtCodeCopy(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(memOffset, length)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryCopierGas(scope.Memory, memorySize, length)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -544,17 +690,10 @@ func opExtCodeCopyFrontier(pc *uint64, interpreter *EVMInterpreter, scope *Scope
return nil, ErrOutOfGas
}
scope.Memory.Resize(memorySize)
- return opExtCodeCopy(pc, interpreter, scope)
+ return opExtCodeCopy(interpreter, scope, a, memOffset, codeOffset, length)
}
-func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- var (
- stack = scope.Stack
- a = stack.pop()
- memOffset = stack.pop()
- codeOffset = stack.pop()
- length = stack.pop()
- )
+func opExtCodeCopy(interpreter *EVMInterpreter, scope *ScopeContext, a, memOffset, codeOffset, length *uint256.Int) ([]byte, error) {
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = math.MaxUint64
@@ -568,25 +707,41 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
func opExtCodeHashEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasExtCodeHash4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasExtCodeHash4762(interpreter.evm, scope.Contract, slot)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
if !scope.Contract.UseGas(dynamicCost, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallOpCodeDynamic) {
return nil, ErrOutOfGas
}
- return opExtCodeHash(pc, interpreter, scope)
+ return opExtCodeHash(interpreter, slot)
}
func opExtCodeHashEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasEip2929AccountCheck(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasEip2929AccountCheck(interpreter.evm, slot)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
if !scope.Contract.UseGas(dynamicCost, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallOpCodeDynamic) {
return nil, ErrOutOfGas
}
- return opExtCodeHash(pc, interpreter, scope)
+ return opExtCodeHash(interpreter, slot)
+}
+
+func opExtCodeHashConstantinople(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ slot, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ return opExtCodeHash(interpreter, slot)
}
// opExtCodeHash returns the code hash of a specified account.
@@ -615,8 +770,7 @@ func opExtCodeHashEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
//
// 6. Caller tries to get the code hash for an account which is marked as deleted, this
// account should be regarded as a non-existent account and zero should be returned.
-func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- slot := scope.Stack.peek()
+func opExtCodeHash(interpreter *EVMInterpreter, slot *uint256.Int) ([]byte, error) {
address := common.Address(slot.Bytes20())
if interpreter.evm.StateDB.Empty(address) {
slot.Clear()
@@ -628,12 +782,14 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.GasPrice)
- scope.Stack.push(v)
- return nil, nil
+ return nil, scope.Stack.push(v)
}
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- num := scope.Stack.peek()
+ num, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
num64, overflow := num.Uint64WithOverflow()
if overflow {
num.Clear()
@@ -663,49 +819,47 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
}
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
}
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time))
}
func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
- scope.Stack.push(v)
- return nil, nil
+ return nil, scope.Stack.push(v)
}
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
- scope.Stack.push(v)
- return nil, nil
+ return nil, scope.Stack.push(v)
}
func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v := new(uint256.Int).SetBytes(interpreter.evm.Context.Random.Bytes())
- scope.Stack.push(v)
- return nil, nil
+ return nil, scope.Stack.push(v)
}
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
}
func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.pop()
- return nil, nil
+ _, err := scope.Stack.pop(0)
+ return nil, err
}
func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryMLoad, scope.Stack, scope.Memory)
+ v, err := scope.Stack.pop(1)
if err != nil {
return nil, err
}
- dynamicCost, err := gasMLoad(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySizeU64(v, 32)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryGasCost(scope.Memory, memorySize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -714,18 +868,21 @@ func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
}
scope.Memory.Resize(memorySize)
- v := scope.Stack.peek()
offset := v.Uint64()
v.SetBytes(scope.Memory.GetPtr(offset, 32))
return nil, nil
}
func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryMStore, scope.Stack, scope.Memory)
+ mStart, val, err := scope.Stack.pop2(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasMStore(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySizeU64(mStart, 32)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryGasCost(scope.Memory, memorySize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -734,17 +891,21 @@ func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
}
scope.Memory.Resize(memorySize)
- mStart, val := scope.Stack.pop(), scope.Stack.pop()
- scope.Memory.Set32(mStart.Uint64(), &val)
+ scope.Memory.Set32(mStart.Uint64(), val)
return nil, nil
}
func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryMStore8, scope.Stack, scope.Memory)
+ off, val, err := scope.Stack.pop2(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasMStore8(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+
+ memorySize, err := calculateMemorySizeU64(off, 1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryGasCost(scope.Memory, memorySize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -753,35 +914,50 @@ func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
}
scope.Memory.Resize(memorySize)
- off, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.store[off.Uint64()] = byte(val.Uint64())
return nil, nil
}
func opSLoadEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSLoad4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+
+ dynamicCost, err := gasSLoad4762(interpreter.evm, scope.Contract, loc)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
if !scope.Contract.UseGas(dynamicCost, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallOpCodeDynamic) {
return nil, ErrOutOfGas
}
- return opSload(pc, interpreter, scope)
+ return opSload(interpreter, scope, loc)
}
func opSLoadEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSLoadEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSLoadEIP2929(interpreter.evm, scope.Contract, loc)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
if !scope.Contract.UseGas(dynamicCost, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallOpCodeDynamic) {
return nil, ErrOutOfGas
}
- return opSload(pc, interpreter, scope)
+ return opSload(interpreter, scope, loc)
}
-func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- loc := scope.Stack.peek()
+func opSLoadFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ loc, err := scope.Stack.pop(1)
+ if err != nil {
+ return nil, err
+ }
+ return opSload(interpreter, scope, loc)
+}
+
+func opSload(interpreter *EVMInterpreter, scope *ScopeContext, loc *uint256.Int) ([]byte, error) {
hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
@@ -789,7 +965,11 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
}
func opSstoreEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSStore4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, val, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSStore4762(interpreter.evm, scope.Contract, loc)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -797,11 +977,15 @@ func opSstoreEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContex
return nil, ErrOutOfGas
}
- return opSstore(pc, interpreter, scope)
+ return opSstore(interpreter, scope, loc, val)
}
func opSstoreEIP3529(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSStoreEIP3529(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, val, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSStoreWithClearingRefund(interpreter.evm, scope.Contract, loc, val, params.SstoreClearsScheduleRefundEIP3529)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -809,11 +993,15 @@ func opSstoreEIP3529(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContex
return nil, ErrOutOfGas
}
- return opSstore(pc, interpreter, scope)
+ return opSstore(interpreter, scope, loc, val)
}
func opSstoreEIP2200(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSStoreEIP2200(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, val, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSStoreEIP2200(interpreter.evm, scope.Contract, loc, val)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -821,11 +1009,15 @@ func opSstoreEIP2200(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContex
return nil, ErrOutOfGas
}
- return opSstore(pc, interpreter, scope)
+ return opSstore(interpreter, scope, loc, val)
}
func opSstoreEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSStoreEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, val, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSStoreWithClearingRefund(interpreter.evm, scope.Contract, loc, val, params.SstoreClearsScheduleRefundEIP2200)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -833,11 +1025,15 @@ func opSstoreEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContex
return nil, ErrOutOfGas
}
- return opSstore(pc, interpreter, scope)
+ return opSstore(interpreter, scope, loc, val)
}
func opSstoreFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSStore(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ loc, val, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSStore(interpreter.evm, scope.Contract, loc, val)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -845,15 +1041,13 @@ func opSstoreFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
return nil, ErrOutOfGas
}
- return opSstore(pc, interpreter, scope)
+ return opSstore(interpreter, scope, loc, val)
}
-func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opSstore(interpreter *EVMInterpreter, scope *ScopeContext, loc, val *uint256.Int) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
- loc := scope.Stack.pop()
- val := scope.Stack.pop()
interpreter.evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
return nil, nil
}
@@ -862,8 +1056,11 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
if interpreter.evm.abort.Load() {
return nil, errStopToken
}
- pos := scope.Stack.pop()
- if !scope.Contract.validJumpdest(&pos) {
+ pos, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ if !scope.Contract.validJumpdest(pos) {
return nil, ErrInvalidJump
}
*pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
@@ -874,9 +1071,12 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
if interpreter.evm.abort.Load() {
return nil, errStopToken
}
- pos, cond := scope.Stack.pop(), scope.Stack.pop()
+ pos, cond, err := scope.Stack.pop2(0)
+ if err != nil {
+ return nil, err
+ }
if !cond.IsZero() {
- if !scope.Contract.validJumpdest(&pos) {
+ if !scope.Contract.validJumpdest(pos) {
return nil, ErrInvalidJump
}
*pc = pos.Uint64() - 1 // pc will be increased by the interpreter loop
@@ -889,106 +1089,91 @@ func opJumpdest(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
func opPc(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(*pc))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(*pc))
}
func opMsize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
}
func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas))
- return nil, nil
+ return nil, scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas))
}
func opSwap1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap1()
- return nil, nil
+ return nil, scope.Stack.swap1()
}
func opSwap2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap2()
- return nil, nil
+ return nil, scope.Stack.swap2()
}
func opSwap3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap3()
- return nil, nil
+ return nil, scope.Stack.swap3()
}
func opSwap4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap4()
- return nil, nil
+ return nil, scope.Stack.swap4()
}
func opSwap5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap5()
- return nil, nil
+ return nil, scope.Stack.swap5()
}
func opSwap6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap6()
- return nil, nil
+ return nil, scope.Stack.swap6()
}
func opSwap7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap7()
- return nil, nil
+ return nil, scope.Stack.swap7()
}
func opSwap8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap8()
- return nil, nil
+ return nil, scope.Stack.swap8()
}
func opSwap9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap9()
- return nil, nil
+ return nil, scope.Stack.swap9()
}
func opSwap10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap10()
- return nil, nil
+ return nil, scope.Stack.swap10()
}
func opSwap11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap11()
- return nil, nil
+ return nil, scope.Stack.swap11()
}
func opSwap12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap12()
- return nil, nil
+ return nil, scope.Stack.swap12()
}
func opSwap13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap13()
- return nil, nil
+ return nil, scope.Stack.swap13()
}
func opSwap14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap14()
- return nil, nil
+ return nil, scope.Stack.swap14()
}
func opSwap15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap15()
- return nil, nil
+ return nil, scope.Stack.swap15()
}
func opSwap16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.swap16()
- return nil, nil
+ return nil, scope.Stack.swap16()
}
func opCreateEIP3860(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCreate, scope.Stack, scope.Memory)
+ value, offset, size, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCreateEip3860(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCreateEip3860(scope.Memory, memorySize, size)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -997,15 +1182,19 @@ func opCreateEIP3860(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContex
}
scope.Memory.Resize(memorySize)
- return opCreate(pc, interpreter, scope)
+ return opCreate(interpreter, scope, value, offset, size)
}
func opCreateFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCreate, scope.Stack, scope.Memory)
+ value, offset, size, err := scope.Stack.pop3(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCreate(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryGasCost(scope.Memory, memorySize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1014,19 +1203,17 @@ func opCreateFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
}
scope.Memory.Resize(memorySize)
- return opCreate(pc, interpreter, scope)
+ return opCreate(interpreter, scope, value, offset, size)
}
-func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opCreate(interpreter *EVMInterpreter, scope *ScopeContext, value, offset, size *uint256.Int) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
var (
- value = scope.Stack.pop()
- offset, size = scope.Stack.pop(), scope.Stack.pop()
- input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
- gas = scope.Contract.Gas
+ input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
+ gas = scope.Contract.Gas
)
if interpreter.evm.chainRules.IsEIP150 {
gas -= gas / 64
@@ -1037,7 +1224,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallContractCreation)
- res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value)
+ res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, value)
// Push item on the stack based on the returned error. If the ruleset is
// homestead we must check for CodeStoreOutOfGasError (homestead only
// rule) and treat as an error, if the ruleset is frontier we must
@@ -1049,7 +1236,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
} else {
stackvalue.SetBytes(addr.Bytes())
}
- scope.Stack.push(&stackvalue)
+ scope.Stack.push(stackvalue)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
@@ -1062,11 +1249,15 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
}
func opCreate2EIP3860(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCreate2, scope.Stack, scope.Memory)
+ endowment, offset, size, salt, err := scope.Stack.pop4(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCreate2Eip3860(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCreate2Eip3860(scope.Memory, memorySize, size)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1075,15 +1266,19 @@ func opCreate2EIP3860(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
}
scope.Memory.Resize(memorySize)
- return opCreate2(pc, interpreter, scope)
+ return opCreate2(interpreter, scope, endowment, offset, size, salt)
}
func opCreate2Constantinople(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCreate2, scope.Stack, scope.Memory)
+ endowment, offset, size, salt, err := scope.Stack.pop4(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCreate2(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCreate2(scope.Memory, memorySize, size)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1092,19 +1287,16 @@ func opCreate2Constantinople(pc *uint64, interpreter *EVMInterpreter, scope *Sco
}
scope.Memory.Resize(memorySize)
- return opCreate2(pc, interpreter, scope)
+ return opCreate2(interpreter, scope, endowment, offset, size, salt)
}
-func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opCreate2(interpreter *EVMInterpreter, scope *ScopeContext, endowment, offset, size, salt *uint256.Int) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
var (
- endowment = scope.Stack.pop()
- offset, size = scope.Stack.pop(), scope.Stack.pop()
- salt = scope.Stack.pop()
- input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
- gas = scope.Contract.Gas
+ input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
+ gas = scope.Contract.Gas
)
// Apply EIP150
@@ -1113,14 +1305,14 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
// reuse size int for stackvalue
stackvalue := size
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas,
- &endowment, &salt)
+ endowment, salt)
// Push item on the stack based on the returned error.
if suberr != nil {
stackvalue.Clear()
} else {
stackvalue.SetBytes(addr.Bytes())
}
- scope.Stack.push(&stackvalue)
+ scope.Stack.push(stackvalue)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
if suberr == ErrExecutionReverted {
@@ -1132,11 +1324,17 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
}
func opCallEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallEIP4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP4762(interpreter.evm, scope.Contract, func() (uint64, error) {
+ return gasCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, addr, value)
+ }, addr, value, true)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1145,15 +1343,21 @@ func opCallEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
scope.Memory.Resize(memorySize)
- return opCall(pc, interpreter, scope)
+ return opCall(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
func opCallEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallEIP7702(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP7702(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, addr, value)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1162,15 +1366,21 @@ func opCallEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
scope.Memory.Resize(memorySize)
- return opCall(pc, interpreter, scope)
+ return opCall(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
func opCallEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP2929(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, addr, value)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1179,15 +1389,19 @@ func opCallEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
scope.Memory.Resize(memorySize)
- return opCall(pc, interpreter, scope)
+ return opCall(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
func opCallFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCall(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, addr, value)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1196,17 +1410,15 @@ func opCallFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
scope.Memory.Resize(memorySize)
- return opCall(pc, interpreter, scope)
+ return opCall(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
-func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opCall(interpreter *EVMInterpreter, scope *ScopeContext,
+ temp, addr, value, inOffset, inSize, retOffset, retSize *uint256.Int,
+) ([]byte, error) {
stack := scope.Stack
- // Pop gas. The actual gas in interpreter.evm.callGasTemp.
- // We can use this as a temporary value
- temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get the arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
@@ -1217,17 +1429,17 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
if !value.IsZero() {
gas += params.CallStipend
}
- ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value)
+ ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, value)
if err != nil {
temp.Clear()
} else {
temp.SetOne()
}
- stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
+ stack.push(temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
@@ -1236,11 +1448,17 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
}
func opCallCodeEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallCodeEIP4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP4762(interpreter.evm, scope.Contract, func() (uint64, error) {
+ return gasCallCode(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, value)
+ }, addr, value, false)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1249,15 +1467,21 @@ func opCallCodeEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCont
}
scope.Memory.Resize(memorySize)
- return opCallCode(pc, interpreter, scope)
+ return opCallCode(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
func opCallCodeEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallCodeEIP7702(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP7702(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasCallCode(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, value)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1266,15 +1490,21 @@ func opCallCodeEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCont
}
scope.Memory.Resize(memorySize)
- return opCallCode(pc, interpreter, scope)
+ return opCallCode(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
func opCallCodeEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallCodeEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP2929(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasCallCode(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, value)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1283,15 +1513,19 @@ func opCallCodeEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCont
}
scope.Memory.Resize(memorySize)
- return opCallCode(pc, interpreter, scope)
+ return opCallCode(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
func opCallCodeFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryCall, scope.Stack, scope.Memory)
+ gas, addr, value, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop7(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasCallCode(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallCode(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas, value)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1300,17 +1534,14 @@ func opCallCodeFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
}
scope.Memory.Resize(memorySize)
- return opCallCode(pc, interpreter, scope)
+ return opCallCode(interpreter, scope, gas, addr, value, inOffset, inSize, retOffset, retSize)
}
-func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
- stack := scope.Stack
- // We use it as a temporary value
- temp := stack.pop()
+func opCallCode(interpreter *EVMInterpreter, scope *ScopeContext,
+ temp, addr, value, inOffset, inSize, retOffset, retSize *uint256.Int,
+) ([]byte, error) {
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
@@ -1319,16 +1550,16 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
gas += params.CallStipend
}
- ret, returnGas, err := interpreter.evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value)
+ ret, returnGas, err := interpreter.evm.CallCode(scope.Contract.Address(), toAddr, args, gas, value)
if err != nil {
temp.Clear()
} else {
temp.SetOne()
}
- stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
+ scope.Stack.push(temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
@@ -1337,11 +1568,17 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
func opDelegateCallEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryDelegateCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasDelegateCallEIP7702(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP7702(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasDelegateCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1350,15 +1587,21 @@ func opDelegateCallEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *Scope
}
scope.Memory.Resize(memorySize)
- return opDelegateCall(pc, interpreter, scope)
+ return opDelegateCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
func opDelegateCallEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryDelegateCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasDelegateCallEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP2929(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasDelegateCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1367,15 +1610,21 @@ func opDelegateCallEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *Scope
}
scope.Memory.Resize(memorySize)
- return opDelegateCall(pc, interpreter, scope)
+ return opDelegateCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
func opDelegateCallEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryDelegateCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasDelegateCallEIP4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP4762(interpreter.evm, scope.Contract, func() (uint64, error) {
+ return gasDelegateCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
+ }, addr, nil, false)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1384,17 +1633,14 @@ func opDelegateCallEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *Scope
}
scope.Memory.Resize(memorySize)
- return opDelegateCall(pc, interpreter, scope)
+ return opDelegateCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
-func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opDelegateCall(interpreter *EVMInterpreter, scope *ScopeContext,
+ temp, addr, inOffset, inSize, retOffset, retSize *uint256.Int,
+) ([]byte, error) {
stack := scope.Stack
- // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
- // We use it as a temporary value
- temp := stack.pop()
gas := interpreter.evm.callGasTemp
- // Pop other call parameters.
- addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
@@ -1405,10 +1651,10 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
} else {
temp.SetOne()
}
- stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
+ stack.push(temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
@@ -1417,11 +1663,15 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
func opDelegateCallHomestead(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryDelegateCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasDelegateCall(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasDelegateCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1430,15 +1680,21 @@ func opDelegateCallHomestead(pc *uint64, interpreter *EVMInterpreter, scope *Sco
}
scope.Memory.Resize(memorySize)
- return opDelegateCall(pc, interpreter, scope)
+ return opDelegateCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
func opStaticCallEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryStaticCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasStaticCallEIP7702(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP7702(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasStaticCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1447,15 +1703,19 @@ func opStaticCallEIP7702(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCo
}
scope.Memory.Resize(memorySize)
- return opStaticCall(pc, interpreter, scope)
+ return opStaticCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
func opStaticCallByzantium(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryStaticCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasStaticCall(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasStaticCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1464,15 +1724,21 @@ func opStaticCallByzantium(pc *uint64, interpreter *EVMInterpreter, scope *Scope
}
scope.Memory.Resize(memorySize)
- return opStaticCall(pc, interpreter, scope)
+ return opStaticCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
func opStaticCallEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryStaticCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasStaticCallEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP2929(interpreter.evm, scope.Contract, addr, func() (uint64, error) {
+ return gasStaticCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
+ })
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1481,15 +1747,21 @@ func opStaticCallEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCo
}
scope.Memory.Resize(memorySize)
- return opStaticCall(pc, interpreter, scope)
+ return opStaticCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
func opStaticCallEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryStaticCall, scope.Stack, scope.Memory)
+ gas, addr, inOffset, inSize, retOffset, retSize, err := scope.Stack.pop6(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasStaticCallEIP4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateCallMemorySize(inOffset, inSize, retOffset, retSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasCallEIP4762(interpreter.evm, scope.Contract, func() (uint64, error) {
+ return gasStaticCall(interpreter.evm, scope.Contract, scope.Memory, memorySize, gas)
+ }, addr, nil, false)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1498,17 +1770,15 @@ func opStaticCallEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCo
}
scope.Memory.Resize(memorySize)
- return opStaticCall(pc, interpreter, scope)
+ return opStaticCall(interpreter, scope, gas, addr, inOffset, inSize, retOffset, retSize)
}
-func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- // Pop gas. The actual gas is in interpreter.evm.callGasTemp.
- stack := scope.Stack
+func opStaticCall(interpreter *EVMInterpreter, scope *ScopeContext,
+ temp, addr, inOffset, inSize, retOffset, retSize *uint256.Int,
+) ([]byte, error) {
// We use it as a temporary value
- temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
- addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())
// Get arguments from the memory.
args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64())
@@ -1519,10 +1789,10 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
} else {
temp.SetOne()
}
- stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
+ scope.Stack.push(temp)
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
@@ -1531,11 +1801,15 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryReturn, scope.Stack, scope.Memory)
+ offset, size, err := scope.Stack.pop2(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasReturn(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryGasCost(scope.Memory, memorySize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1544,18 +1818,21 @@ func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
}
scope.Memory.Resize(memorySize)
- offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
return ret, errStopToken
}
func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- memorySize, err := calculateMemorySize(memoryRevert, scope.Stack, scope.Memory)
+ offset, size, err := scope.Stack.pop2(0)
if err != nil {
return nil, err
}
- dynamicCost, err := gasRevert(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ memorySize, err := calculateMemorySize(offset, size)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := memoryGasCost(scope.Memory, memorySize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1564,7 +1841,6 @@ func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
}
scope.Memory.Resize(memorySize)
- offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
interpreter.returnData = ret
@@ -1580,7 +1856,11 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
}
func opSelfdestructEIP6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSelfdestructEIP3529(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ beneficiary, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSelfdestructEIP(interpreter.evm, scope.Contract, beneficiary, false)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1588,11 +1868,15 @@ func opSelfdestructEIP6780(pc *uint64, interpreter *EVMInterpreter, scope *Scope
return nil, ErrOutOfGas
}
- return opSelfdestruct6780(pc, interpreter, scope)
+ return opSelfdestruct6780(interpreter, scope, beneficiary)
}
func opSelfdestructEIP3529(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSelfdestructEIP3529(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ beneficiary, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSelfdestructEIP(interpreter.evm, scope.Contract, beneficiary, false)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1600,11 +1884,15 @@ func opSelfdestructEIP3529(pc *uint64, interpreter *EVMInterpreter, scope *Scope
return nil, ErrOutOfGas
}
- return opSelfdestruct(pc, interpreter, scope)
+ return opSelfdestruct(interpreter, scope, beneficiary)
}
func opSelfdestructEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSelfdestructEIP2929(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ beneficiary, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSelfdestructEIP(interpreter.evm, scope.Contract, beneficiary, true)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1612,11 +1900,15 @@ func opSelfdestructEIP2929(pc *uint64, interpreter *EVMInterpreter, scope *Scope
return nil, ErrOutOfGas
}
- return opSelfdestruct(pc, interpreter, scope)
+ return opSelfdestruct(interpreter, scope, beneficiary)
}
func opSelfdestructFrontier(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSelfdestruct(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ beneficiary, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSelfdestruct(interpreter.evm, scope.Contract, beneficiary)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1624,15 +1916,14 @@ func opSelfdestructFrontier(pc *uint64, interpreter *EVMInterpreter, scope *Scop
return nil, ErrOutOfGas
}
- return opSelfdestruct(pc, interpreter, scope)
+ return opSelfdestruct(interpreter, scope, beneficiary)
}
-func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opSelfdestruct(interpreter *EVMInterpreter, scope *ScopeContext, beneficiary *uint256.Int) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
- beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
@@ -1646,7 +1937,11 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
func opSelfdestructEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- dynamicCost, err := gasSelfdestructEIP4762(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, 0)
+ beneficiary, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasSelfdestructEIP4762(interpreter.evm, scope.Contract, beneficiary)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1654,14 +1949,13 @@ func opSelfdestructEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *Scope
return nil, ErrOutOfGas
}
- return opSelfdestruct6780(pc, interpreter, scope)
+ return opSelfdestruct6780(interpreter, scope, beneficiary)
}
-func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+func opSelfdestruct6780(interpreter *EVMInterpreter, scope *ScopeContext, beneficiary *uint256.Int) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
- beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
@@ -1678,17 +1972,29 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
// following functions are used by the instruction jump table
// make log instruction function
-func makeLog(size int) executionFunc {
- logGas := makeGasLog(uint64(size))
+func makeLog(size uint64) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
- memorySize, err := calculateMemorySize(memoryLog, scope.Stack, scope.Memory)
+ mStart, mSize, err := scope.Stack.pop2(0)
if err != nil {
return nil, err
}
- dynamicCost, err := logGas(interpreter.evm, scope.Contract, scope.Stack, scope.Memory, memorySize)
+ topics := make([]common.Hash, size)
+ for i := uint64(0); i < size; i++ {
+ addr, err := scope.Stack.pop(0)
+ if err != nil {
+ return nil, err
+ }
+ topics[i] = addr.Bytes32()
+ }
+
+ memorySize, err := calculateMemorySize(mStart, mSize)
+ if err != nil {
+ return nil, err
+ }
+ dynamicCost, err := gasLog(scope.Memory, memorySize, size, mSize)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
}
@@ -1697,14 +2003,6 @@ func makeLog(size int) executionFunc {
}
scope.Memory.Resize(memorySize)
- topics := make([]common.Hash, size)
- stack := scope.Stack
- mStart, mSize := stack.pop(), stack.pop()
- for i := 0; i < size; i++ {
- addr := stack.pop()
- topics[i] = addr.Bytes32()
- }
-
d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64())
interpreter.evm.StateDB.AddLog(&types.Log{
Address: scope.Contract.Address(),
@@ -1727,11 +2025,9 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
)
*pc += 1
if *pc < codeLen {
- scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc])))
- } else {
- scope.Stack.push(integer.Clear())
+ return nil, scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc])))
}
- return nil, nil
+ return nil, scope.Stack.push(integer.Clear())
}
// opPush2 is a specialized version of pushN
@@ -1740,12 +2036,16 @@ func opPush2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
codeLen = uint64(len(scope.Contract.Code))
integer = new(uint256.Int)
)
+ var err error
if *pc+2 < codeLen {
- scope.Stack.push(integer.SetBytes2(scope.Contract.Code[*pc+1 : *pc+3]))
+ err = scope.Stack.push(integer.SetBytes2(scope.Contract.Code[*pc+1 : *pc+3]))
} else if *pc+1 < codeLen {
- scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc+1]) << 8))
+ err = scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc+1]) << 8))
} else {
- scope.Stack.push(integer.Clear())
+ err = scope.Stack.push(integer.Clear())
+ }
+ if err != nil {
+ return nil, err
}
*pc += 2
return nil, nil
@@ -1765,16 +2065,71 @@ func makePush(size uint64, pushByteSize int) executionFunc {
if missing := pushByteSize - (end - start); missing > 0 {
a.Lsh(a, uint(8*missing))
}
- scope.Stack.push(a)
*pc += size
- return nil, nil
+ return nil, scope.Stack.push(a)
}
}
-// make dup instruction function
-func makeDup(size int64) executionFunc {
- return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
- scope.Stack.dup(int(size))
- return nil, nil
- }
+func opDup1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup1()
+}
+
+func opDup2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup2()
+}
+
+func opDup3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup3()
+}
+
+func opDup4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup4()
+}
+
+func opDup5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup5()
+}
+
+func opDup6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup6()
+}
+
+func opDup7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup7()
+}
+
+func opDup8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup8()
+}
+
+func opDup9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup9()
+}
+
+func opDup10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup10()
+}
+
+func opDup11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup11()
+}
+
+func opDup12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup12()
+}
+
+func opDup13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup13()
+}
+
+func opDup14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup14()
+}
+
+func opDup15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup15()
+}
+
+func opDup16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
+ return nil, scope.Stack.dup16()
}
diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go
index 317cb1aee0..88d8bc2b66 100644
--- a/core/vm/instructions_test.go
+++ b/core/vm/instructions_test.go
@@ -20,13 +20,13 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "math"
"math/big"
"os"
"strings"
"testing"
"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/types"
"github.com/ethereum/go-ethereum/crypto"
@@ -77,7 +77,7 @@ func init() {
"sdiv": opSdiv,
"mod": opMod,
"smod": opSmod,
- "exp": opExp,
+ "exp": opExpFrontier,
"signext": opSignExtend,
"lt": opLt,
"gt": opGt,
@@ -107,11 +107,11 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x)
stack.push(y)
- opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
+ opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, &Contract{Gas: math.MaxUint64}})
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
}
- actual := stack.pop()
+ actual, _ := stack.pop(0)
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %v %d, %v(%x, %x): expected %x, got %x", name, i, name, x, y, expected, actual)
@@ -222,7 +222,7 @@ func TestAddMod(t *testing.T) {
stack.push(y)
stack.push(x)
opAddmod(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
- actual := stack.pop()
+ actual, _ := stack.pop(0)
if actual.Cmp(expected) != 0 {
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
}
@@ -248,7 +248,7 @@ func TestWriteExpectedValues(t *testing.T) {
stack.push(x)
stack.push(y)
opFn(&pc, evm.interpreter, &ScopeContext{nil, stack, nil})
- actual := stack.pop()
+ actual, _ := stack.pop(0)
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
}
return result
@@ -283,7 +283,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
var (
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
stack = newstack()
- scope = &ScopeContext{nil, stack, nil}
+ scope = &ScopeContext{nil, stack, &Contract{Gas: math.MaxUint64}}
)
// convert args
intArgs := make([]*uint256.Int, len(args))
@@ -297,7 +297,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
stack.push(arg)
}
op(&pc, evm.interpreter, scope)
- stack.pop()
+ stack.pop(0)
}
bench.StopTimer()
@@ -401,7 +401,7 @@ func BenchmarkOpExp(b *testing.B) {
x := alphabetSoup
y := alphabetSoup
- opBenchmark(b, opExp, x, y)
+ opBenchmark(b, opExpFrontier, x, y)
}
func BenchmarkOpSignExtend(b *testing.B) {
@@ -595,7 +595,7 @@ func TestOpTstore(t *testing.T) {
if stack.len() != 1 {
t.Fatal("stack wrong size")
}
- val := stack.peek()
+ val, _ := stack.pop(1)
if !bytes.Equal(val.Bytes(), value) {
t.Fatal("incorrect element read from transient storage")
}
@@ -676,15 +676,6 @@ func TestCreate2Addresses(t *testing.T) {
code := common.FromHex(tt.code)
codeHash := crypto.Keccak256(code)
address := crypto.CreateAddress2(origin, salt, codeHash)
- /*
- stack := newstack()
- // salt, but we don't need that for this test
- stack.push(big.NewInt(int64(len(code)))) //size
- stack.push(big.NewInt(0)) // memstart
- stack.push(big.NewInt(0)) // value
- gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0)
- fmt.Printf("Example %d\n* address `0x%x`\n* salt `0x%x`\n* init_code `0x%x`\n* gas (assuming no mem expansion): `%v`\n* result: `%s`\n\n", i,origin, salt, code, gas, address.String())
- */
expected := common.BytesToAddress(common.FromHex(tt.expected))
if !bytes.Equal(expected.Bytes(), address.Bytes()) {
t.Errorf("test %d: expected %s, got %s", i, expected.String(), address.String())
@@ -713,7 +704,7 @@ func TestRandom(t *testing.T) {
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
}
- actual := stack.pop()
+ actual, _ := stack.pop(0)
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.random.Bytes()))
if overflow {
t.Errorf("Testcase %v: invalid overflow", tt.name)
@@ -755,7 +746,7 @@ func TestBlobHash(t *testing.T) {
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
}
- actual := stack.pop()
+ actual, _ := stack.pop(0)
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.expect.Bytes()))
if overflow {
t.Errorf("Testcase %v: invalid overflow", tt.name)
@@ -868,37 +859,20 @@ func TestOpMCopy(t *testing.T) {
stack.push(src)
stack.push(dst)
wantErr := (tc.wantGas == 0)
- // Calc mem expansion
- var memorySize uint64
- if memSize, overflow := memoryMcopy(stack); overflow {
- if wantErr {
- continue
- }
- t.Errorf("overflow")
- } else {
- var overflow bool
- if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
- t.Error(ErrGasUintOverflow)
- }
- }
- // and the dynamic cost
- var haveGas uint64
- if dynamicCost, err := gasMcopy(evm, nil, stack, mem, memorySize); err != nil {
- t.Error(err)
- } else {
- haveGas = GasFastestStep + dynamicCost
- }
- // Expand mem
- if memorySize > 0 {
- mem.Resize(memorySize)
- }
// Do the copy
- opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, contract})
+ _, err := opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, contract})
+ if wantErr {
+ if err == nil {
+ t.Error("wanted error")
+ }
+ continue
+ }
want := common.FromHex(strings.ReplaceAll(tc.want, " ", ""))
if have := mem.store; !bytes.Equal(want, have) {
t.Errorf("case %d: \nwant: %#x\nhave: %#x\n", i, want, have)
}
wantGas := tc.wantGas
+ haveGas := 30_000_000 - contract.Gas + GasFastestStep
if haveGas != wantGas {
t.Errorf("case %d: gas wrong, want %d have %d\n", i, wantGas, haveGas)
}
@@ -970,7 +944,7 @@ func TestPush(t *testing.T) {
pc := new(uint64)
*pc = uint64(i)
push32(pc, nil, scope)
- res := scope.Stack.pop()
+ res, _ := scope.Stack.pop(0)
if have := res.Hex(); have != want {
t.Fatalf("case %d, have %v want %v", i, have, want)
}
@@ -1010,7 +984,7 @@ func TestOpCLZ(t *testing.T) {
if gotLen := stack.len(); gotLen != 1 {
t.Fatalf("stack length = %d; want 1", gotLen)
}
- result := stack.pop()
+ result, _ := stack.pop(0)
if got := result.Uint64(); got != tc.want {
t.Fatalf("clz(%q) = %d; want %d", tc.inputHex, got, tc.want)
}
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index b6a44550b0..d3b1c083c4 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -261,17 +261,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
}
- // Get the operation from the jump table and validate the stack to ensure there are
- // enough stack items available to perform the operation.
+ // Get the operation from the jump table
op = contract.GetOp(pc)
operation := jumpTable[op]
cost = operation.constantGas // For tracing
- // Validate stack
- if sLen := stack.len(); sLen < operation.minStack {
- return nil, traceAndReturnError(&ErrStackUnderflow{stackLen: sLen, required: operation.minStack})
- } else if sLen > operation.maxStack {
- return nil, traceAndReturnError(&ErrStackOverflow{stackLen: sLen, limit: operation.maxStack})
- }
// for tracing: this gas consumption event is emitted in the executeWithTracer wrapper.
if contract.Gas < cost {
return nil, traceAndReturnError(ErrOutOfGas)
diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go
index 8ed512316b..bb8bc54586 100644
--- a/core/vm/interpreter_test.go
+++ b/core/vm/interpreter_test.go
@@ -82,15 +82,11 @@ func BenchmarkInterpreter(b *testing.B) {
evm = NewEVM(BlockContext{BlockNumber: big.NewInt(1), Time: 1, Random: &common.Hash{}}, statedb, params.MergedTestChainConfig, Config{})
startGas uint64 = 100_000_000
value = uint256.NewInt(0)
- stack = newstack()
- mem = NewMemory()
contract = NewContract(common.Address{}, common.Address{}, value, startGas, nil)
)
- stack.push(uint256.NewInt(123))
- stack.push(uint256.NewInt(123))
- gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529)
+ args := uint256.NewInt(123)
b.ResetTimer()
for i := 0; i < b.N; i++ {
- gasSStoreEIP3529(evm, contract, stack, mem, 1234)
+ gasSStoreWithClearingRefund(evm, contract, args, args, params.SstoreClearsScheduleRefundEIP2200)
}
}
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 37e334ea82..18a9f47058 100644
--- a/core/vm/jump_table.go
+++ b/core/vm/jump_table.go
@@ -22,23 +22,12 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-type (
- executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
- gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
- // memorySizeFunc returns the required size, and whether the operation overflowed a uint64
- memorySizeFunc func(*Stack) (size uint64, overflow bool)
-)
+type executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
type operation struct {
// execute is the operation function
execute executionFunc
constantGas uint64
- // minStack tells how many stack items are required
- minStack int
- // maxStack specifies the max length the stack can have for this operation
- // to not overflow the stack.
- maxStack int
-
// undefined denotes if the instruction is not officially defined in the jump table
undefined bool
}
@@ -114,8 +103,6 @@ func newMergeInstructionSet() JumpTable {
instructionSet[PREVRANDAO] = &operation{
execute: opRandom,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
return validate(instructionSet)
}
@@ -156,32 +143,22 @@ func newConstantinopleInstructionSet() JumpTable {
instructionSet[SHL] = &operation{
execute: opSHL,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
}
instructionSet[SHR] = &operation{
execute: opSHR,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
}
instructionSet[SAR] = &operation{
execute: opSAR,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
}
instructionSet[EXTCODEHASH] = &operation{
- execute: opExtCodeHash,
+ execute: opExtCodeHashConstantinople,
constantGas: params.ExtcodeHashGasConstantinople,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
}
instructionSet[CREATE2] = &operation{
execute: opCreate2Constantinople,
constantGas: params.Create2Gas,
- minStack: minStack(4, 1),
- maxStack: maxStack(4, 1),
}
return validate(instructionSet)
}
@@ -193,25 +170,17 @@ func newByzantiumInstructionSet() JumpTable {
instructionSet[STATICCALL] = &operation{
execute: opStaticCallByzantium,
constantGas: params.CallGasEIP150,
- minStack: minStack(6, 1),
- maxStack: maxStack(6, 1),
}
instructionSet[RETURNDATASIZE] = &operation{
execute: opReturnDataSize,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
}
instructionSet[RETURNDATACOPY] = &operation{
execute: opReturnDataCopy,
constantGas: GasFastestStep,
- minStack: minStack(3, 0),
- maxStack: maxStack(3, 0),
}
instructionSet[REVERT] = &operation{
- execute: opRevert,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
+ execute: opRevert,
}
return validate(instructionSet)
}
@@ -243,8 +212,6 @@ func newHomesteadInstructionSet() JumpTable {
instructionSet[DELEGATECALL] = &operation{
execute: opDelegateCallHomestead,
constantGas: params.CallGasFrontier,
- minStack: minStack(6, 1),
- maxStack: maxStack(6, 1),
}
return validate(instructionSet)
}
@@ -256,779 +223,519 @@ func newFrontierInstructionSet() JumpTable {
STOP: {
execute: opStop,
constantGas: 0,
- minStack: minStack(0, 0),
- maxStack: maxStack(0, 0),
},
ADD: {
execute: opAdd,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
MUL: {
execute: opMul,
constantGas: GasFastStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
SUB: {
execute: opSub,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
DIV: {
execute: opDiv,
constantGas: GasFastStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
SDIV: {
execute: opSdiv,
constantGas: GasFastStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
MOD: {
execute: opMod,
constantGas: GasFastStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
SMOD: {
execute: opSmod,
constantGas: GasFastStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
ADDMOD: {
execute: opAddmod,
constantGas: GasMidStep,
- minStack: minStack(3, 1),
- maxStack: maxStack(3, 1),
},
MULMOD: {
execute: opMulmod,
constantGas: GasMidStep,
- minStack: minStack(3, 1),
- maxStack: maxStack(3, 1),
},
EXP: {
- execute: opExpFrontier,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
+ execute: opExpFrontier,
},
SIGNEXTEND: {
execute: opSignExtend,
constantGas: GasFastStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
LT: {
execute: opLt,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
GT: {
execute: opGt,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
SLT: {
execute: opSlt,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
SGT: {
execute: opSgt,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
EQ: {
execute: opEq,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
ISZERO: {
execute: opIszero,
constantGas: GasFastestStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
AND: {
execute: opAnd,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
XOR: {
execute: opXor,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
OR: {
execute: opOr,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
NOT: {
execute: opNot,
constantGas: GasFastestStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
BYTE: {
execute: opByte,
constantGas: GasFastestStep,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
KECCAK256: {
execute: opKeccak256,
constantGas: params.Keccak256Gas,
- minStack: minStack(2, 1),
- maxStack: maxStack(2, 1),
},
ADDRESS: {
execute: opAddress,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
BALANCE: {
- execute: opBalance,
+ execute: opBalanceFrontier,
constantGas: params.BalanceGasFrontier,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
ORIGIN: {
execute: opOrigin,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
CALLER: {
execute: opCaller,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
CALLVALUE: {
execute: opCallValue,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
CALLDATALOAD: {
execute: opCallDataLoad,
constantGas: GasFastestStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
CALLDATASIZE: {
execute: opCallDataSize,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
CALLDATACOPY: {
execute: opCallDataCopy,
constantGas: GasFastestStep,
- minStack: minStack(3, 0),
- maxStack: maxStack(3, 0),
},
CODESIZE: {
execute: opCodeSize,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
CODECOPY: {
execute: opCodeCopyFrontier,
constantGas: GasFastestStep,
- minStack: minStack(3, 0),
- maxStack: maxStack(3, 0),
},
GASPRICE: {
execute: opGasprice,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
EXTCODESIZE: {
- execute: opExtCodeSize,
+ execute: opExtCodeSizeFrontier,
constantGas: params.ExtcodeSizeGasFrontier,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
EXTCODECOPY: {
execute: opExtCodeCopyFrontier,
constantGas: params.ExtcodeCopyBaseFrontier,
- minStack: minStack(4, 0),
- maxStack: maxStack(4, 0),
},
BLOCKHASH: {
execute: opBlockhash,
constantGas: GasExtStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
COINBASE: {
execute: opCoinbase,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
TIMESTAMP: {
execute: opTimestamp,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
NUMBER: {
execute: opNumber,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
DIFFICULTY: {
execute: opDifficulty,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
GASLIMIT: {
execute: opGasLimit,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
POP: {
execute: opPop,
constantGas: GasQuickStep,
- minStack: minStack(1, 0),
- maxStack: maxStack(1, 0),
},
MLOAD: {
execute: opMload,
constantGas: GasFastestStep,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
MSTORE: {
execute: opMstore,
constantGas: GasFastestStep,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
},
MSTORE8: {
execute: opMstore8,
constantGas: GasFastestStep,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
},
SLOAD: {
- execute: opSload,
+ execute: opSLoadFrontier,
constantGas: params.SloadGasFrontier,
- minStack: minStack(1, 1),
- maxStack: maxStack(1, 1),
},
SSTORE: {
- execute: opSstoreFrontier,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
+ execute: opSstoreFrontier,
},
JUMP: {
execute: opJump,
constantGas: GasMidStep,
- minStack: minStack(1, 0),
- maxStack: maxStack(1, 0),
},
JUMPI: {
execute: opJumpi,
constantGas: GasSlowStep,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
},
PC: {
execute: opPc,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
MSIZE: {
execute: opMsize,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
GAS: {
execute: opGas,
constantGas: GasQuickStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
JUMPDEST: {
execute: opJumpdest,
constantGas: params.JumpdestGas,
- minStack: minStack(0, 0),
- maxStack: maxStack(0, 0),
},
PUSH1: {
execute: opPush1,
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH2: {
execute: opPush2,
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH3: {
execute: makePush(3, 3),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH4: {
execute: makePush(4, 4),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH5: {
execute: makePush(5, 5),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH6: {
execute: makePush(6, 6),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH7: {
execute: makePush(7, 7),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH8: {
execute: makePush(8, 8),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH9: {
execute: makePush(9, 9),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH10: {
execute: makePush(10, 10),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH11: {
execute: makePush(11, 11),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH12: {
execute: makePush(12, 12),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH13: {
execute: makePush(13, 13),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH14: {
execute: makePush(14, 14),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH15: {
execute: makePush(15, 15),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH16: {
execute: makePush(16, 16),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH17: {
execute: makePush(17, 17),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH18: {
execute: makePush(18, 18),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH19: {
execute: makePush(19, 19),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH20: {
execute: makePush(20, 20),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH21: {
execute: makePush(21, 21),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH22: {
execute: makePush(22, 22),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH23: {
execute: makePush(23, 23),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH24: {
execute: makePush(24, 24),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH25: {
execute: makePush(25, 25),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH26: {
execute: makePush(26, 26),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH27: {
execute: makePush(27, 27),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH28: {
execute: makePush(28, 28),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH29: {
execute: makePush(29, 29),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH30: {
execute: makePush(30, 30),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH31: {
execute: makePush(31, 31),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
PUSH32: {
execute: makePush(32, 32),
constantGas: GasFastestStep,
- minStack: minStack(0, 1),
- maxStack: maxStack(0, 1),
},
DUP1: {
- execute: makeDup(1),
+ execute: opDup1,
constantGas: GasFastestStep,
- minStack: minDupStack(1),
- maxStack: maxDupStack(1),
},
DUP2: {
- execute: makeDup(2),
+ execute: opDup2,
constantGas: GasFastestStep,
- minStack: minDupStack(2),
- maxStack: maxDupStack(2),
},
DUP3: {
- execute: makeDup(3),
+ execute: opDup3,
constantGas: GasFastestStep,
- minStack: minDupStack(3),
- maxStack: maxDupStack(3),
},
DUP4: {
- execute: makeDup(4),
+ execute: opDup4,
constantGas: GasFastestStep,
- minStack: minDupStack(4),
- maxStack: maxDupStack(4),
},
DUP5: {
- execute: makeDup(5),
+ execute: opDup5,
constantGas: GasFastestStep,
- minStack: minDupStack(5),
- maxStack: maxDupStack(5),
},
DUP6: {
- execute: makeDup(6),
+ execute: opDup6,
constantGas: GasFastestStep,
- minStack: minDupStack(6),
- maxStack: maxDupStack(6),
},
DUP7: {
- execute: makeDup(7),
+ execute: opDup7,
constantGas: GasFastestStep,
- minStack: minDupStack(7),
- maxStack: maxDupStack(7),
},
DUP8: {
- execute: makeDup(8),
+ execute: opDup8,
constantGas: GasFastestStep,
- minStack: minDupStack(8),
- maxStack: maxDupStack(8),
},
DUP9: {
- execute: makeDup(9),
+ execute: opDup9,
constantGas: GasFastestStep,
- minStack: minDupStack(9),
- maxStack: maxDupStack(9),
},
DUP10: {
- execute: makeDup(10),
+ execute: opDup10,
constantGas: GasFastestStep,
- minStack: minDupStack(10),
- maxStack: maxDupStack(10),
},
DUP11: {
- execute: makeDup(11),
+ execute: opDup11,
constantGas: GasFastestStep,
- minStack: minDupStack(11),
- maxStack: maxDupStack(11),
},
DUP12: {
- execute: makeDup(12),
+ execute: opDup12,
constantGas: GasFastestStep,
- minStack: minDupStack(12),
- maxStack: maxDupStack(12),
},
DUP13: {
- execute: makeDup(13),
+ execute: opDup13,
constantGas: GasFastestStep,
- minStack: minDupStack(13),
- maxStack: maxDupStack(13),
},
DUP14: {
- execute: makeDup(14),
+ execute: opDup14,
constantGas: GasFastestStep,
- minStack: minDupStack(14),
- maxStack: maxDupStack(14),
},
DUP15: {
- execute: makeDup(15),
+ execute: opDup15,
constantGas: GasFastestStep,
- minStack: minDupStack(15),
- maxStack: maxDupStack(15),
},
DUP16: {
- execute: makeDup(16),
+ execute: opDup16,
constantGas: GasFastestStep,
- minStack: minDupStack(16),
- maxStack: maxDupStack(16),
},
SWAP1: {
execute: opSwap1,
constantGas: GasFastestStep,
- minStack: minSwapStack(2),
- maxStack: maxSwapStack(2),
},
SWAP2: {
execute: opSwap2,
constantGas: GasFastestStep,
- minStack: minSwapStack(3),
- maxStack: maxSwapStack(3),
},
SWAP3: {
execute: opSwap3,
constantGas: GasFastestStep,
- minStack: minSwapStack(4),
- maxStack: maxSwapStack(4),
},
SWAP4: {
execute: opSwap4,
constantGas: GasFastestStep,
- minStack: minSwapStack(5),
- maxStack: maxSwapStack(5),
},
SWAP5: {
execute: opSwap5,
constantGas: GasFastestStep,
- minStack: minSwapStack(6),
- maxStack: maxSwapStack(6),
},
SWAP6: {
execute: opSwap6,
constantGas: GasFastestStep,
- minStack: minSwapStack(7),
- maxStack: maxSwapStack(7),
},
SWAP7: {
execute: opSwap7,
constantGas: GasFastestStep,
- minStack: minSwapStack(8),
- maxStack: maxSwapStack(8),
},
SWAP8: {
execute: opSwap8,
constantGas: GasFastestStep,
- minStack: minSwapStack(9),
- maxStack: maxSwapStack(9),
},
SWAP9: {
execute: opSwap9,
constantGas: GasFastestStep,
- minStack: minSwapStack(10),
- maxStack: maxSwapStack(10),
},
SWAP10: {
execute: opSwap10,
constantGas: GasFastestStep,
- minStack: minSwapStack(11),
- maxStack: maxSwapStack(11),
},
SWAP11: {
execute: opSwap11,
constantGas: GasFastestStep,
- minStack: minSwapStack(12),
- maxStack: maxSwapStack(12),
},
SWAP12: {
execute: opSwap12,
constantGas: GasFastestStep,
- minStack: minSwapStack(13),
- maxStack: maxSwapStack(13),
},
SWAP13: {
execute: opSwap13,
constantGas: GasFastestStep,
- minStack: minSwapStack(14),
- maxStack: maxSwapStack(14),
},
SWAP14: {
execute: opSwap14,
constantGas: GasFastestStep,
- minStack: minSwapStack(15),
- maxStack: maxSwapStack(15),
},
SWAP15: {
execute: opSwap15,
constantGas: GasFastestStep,
- minStack: minSwapStack(16),
- maxStack: maxSwapStack(16),
},
SWAP16: {
execute: opSwap16,
constantGas: GasFastestStep,
- minStack: minSwapStack(17),
- maxStack: maxSwapStack(17),
},
LOG0: {
- execute: makeLog(0),
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
+ execute: makeLog(0),
},
LOG1: {
- execute: makeLog(1),
- minStack: minStack(3, 0),
- maxStack: maxStack(3, 0),
+ execute: makeLog(1),
},
LOG2: {
- execute: makeLog(2),
- minStack: minStack(4, 0),
- maxStack: maxStack(4, 0),
+ execute: makeLog(2),
},
LOG3: {
- execute: makeLog(3),
- minStack: minStack(5, 0),
- maxStack: maxStack(5, 0),
+ execute: makeLog(3),
},
LOG4: {
- execute: makeLog(4),
- minStack: minStack(6, 0),
- maxStack: maxStack(6, 0),
+ execute: makeLog(4),
},
CREATE: {
execute: opCreateFrontier,
constantGas: params.CreateGas,
- minStack: minStack(3, 1),
- maxStack: maxStack(3, 1),
},
CALL: {
execute: opCallFrontier,
constantGas: params.CallGasFrontier,
- minStack: minStack(7, 1),
- maxStack: maxStack(7, 1),
},
CALLCODE: {
execute: opCallCodeFrontier,
constantGas: params.CallGasFrontier,
- minStack: minStack(7, 1),
- maxStack: maxStack(7, 1),
},
RETURN: {
- execute: opReturn,
- minStack: minStack(2, 0),
- maxStack: maxStack(2, 0),
+ execute: opReturn,
},
SELFDESTRUCT: {
- execute: opSelfdestructFrontier,
- minStack: minStack(1, 0),
- maxStack: maxStack(1, 0),
+ execute: opSelfdestructFrontier,
},
INVALID: {
- execute: opUndefined,
- minStack: minStack(0, 0),
- maxStack: maxStack(0, 0),
+ execute: opUndefined,
},
}
// Fill all unassigned slots with opUndefined.
for i, entry := range tbl {
if entry == nil {
- tbl[i] = &operation{execute: opUndefined, maxStack: maxStack(0, 0), undefined: true}
+ tbl[i] = &operation{execute: opUndefined, undefined: true}
}
}
diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go
index bc41512074..70fbcda56d 100644
--- a/core/vm/jump_table_export.go
+++ b/core/vm/jump_table_export.go
@@ -57,8 +57,3 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
}
return newFrontierInstructionSet(), nil
}
-
-// Stack returns the minimum and maximum stack requirements.
-func (op *operation) Stack() (int, int) {
- return op.minStack, op.maxStack
-}
diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go
deleted file mode 100644
index 63ad967850..0000000000
--- a/core/vm/memory_table.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2017 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 .
-
-package vm
-
-func memoryKeccak256(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(1))
-}
-
-func memoryCallDataCopy(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(2))
-}
-
-func memoryReturnDataCopy(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(2))
-}
-
-func memoryCodeCopy(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(2))
-}
-
-func memoryExtCodeCopy(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(1), stack.Back(3))
-}
-
-func memoryMLoad(stack *Stack) (uint64, bool) {
- return calcMemSize64WithUint(stack.Back(0), 32)
-}
-
-func memoryMStore8(stack *Stack) (uint64, bool) {
- return calcMemSize64WithUint(stack.Back(0), 1)
-}
-
-func memoryMStore(stack *Stack) (uint64, bool) {
- return calcMemSize64WithUint(stack.Back(0), 32)
-}
-
-func memoryMcopy(stack *Stack) (uint64, bool) {
- mStart := stack.Back(0) // stack[0]: dest
- if stack.Back(1).Gt(mStart) {
- mStart = stack.Back(1) // stack[1]: source
- }
- return calcMemSize64(mStart, stack.Back(2)) // stack[2]: length
-}
-
-func memoryCreate(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(1), stack.Back(2))
-}
-
-func memoryCreate2(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(1), stack.Back(2))
-}
-
-func memoryCall(stack *Stack) (uint64, bool) {
- x, overflow := calcMemSize64(stack.Back(5), stack.Back(6))
- if overflow {
- return 0, true
- }
- y, overflow := calcMemSize64(stack.Back(3), stack.Back(4))
- if overflow {
- return 0, true
- }
- if x > y {
- return x, false
- }
- return y, false
-}
-
-func memoryDelegateCall(stack *Stack) (uint64, bool) {
- x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
- if overflow {
- return 0, true
- }
- y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
- if overflow {
- return 0, true
- }
- if x > y {
- return x, false
- }
- return y, false
-}
-
-func memoryStaticCall(stack *Stack) (uint64, bool) {
- x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
- if overflow {
- return 0, true
- }
- y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
- if overflow {
- return 0, true
- }
- if x > y {
- return x, false
- }
- return y, false
-}
-
-func memoryReturn(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(1))
-}
-
-func memoryRevert(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(1))
-}
-
-func memoryLog(stack *Stack) (uint64, bool) {
- return calcMemSize64(stack.Back(0), stack.Back(1))
-}
diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go
index 49e82f50b3..6cb7bdcb6a 100644
--- a/core/vm/operations_acl.go
+++ b/core/vm/operations_acl.go
@@ -24,70 +24,68 @@ import (
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
)
-func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
- return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- // If we fail the minimum gas availability invariant, fail (0)
- if contract.Gas <= params.SstoreSentryGasEIP2200 {
- return 0, errors.New("not enough gas for reentrancy sentry")
- }
- // Gas sentry honoured, do the actual gas calculation based on the stored value
- var (
- y, x = stack.Back(1), stack.peek()
- slot = common.Hash(x.Bytes32())
- current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
- cost = uint64(0)
- )
- // Check slot presence in the access list
- if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
- cost = params.ColdSloadCostEIP2929
- // If the caller cannot afford the cost, this change will be rolled back
- evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
- }
- value := common.Hash(y.Bytes32())
+func gasSStoreWithClearingRefund(evm *EVM, contract *Contract, slot256, value256 *uint256.Int, clearingRefund uint64) (uint64, error) {
+ // If we fail the minimum gas availability invariant, fail (0)
+ if contract.Gas <= params.SstoreSentryGasEIP2200 {
+ return 0, errors.New("not enough gas for reentrancy sentry")
+ }
+ // Gas sentry honoured, do the actual gas calculation based on the stored value
+ var (
+ slot = common.Hash(slot256.Bytes32())
+ current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
+ cost = uint64(0)
+ )
+ // Check slot presence in the access list
+ if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
+ cost = params.ColdSloadCostEIP2929
+ // If the caller cannot afford the cost, this change will be rolled back
+ evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
+ }
+ value := common.Hash(value256.Bytes32())
- if current == value { // noop (1)
- // EIP 2200 original clause:
- // return params.SloadGasEIP2200, nil
- return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS
+ if current == value { // noop (1)
+ // EIP 2200 original clause:
+ // return params.SloadGasEIP2200, nil
+ return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS
+ }
+ if original == current {
+ if original == (common.Hash{}) { // create slot (2.1.1)
+ return cost + params.SstoreSetGasEIP2200, nil
}
- if original == current {
- if original == (common.Hash{}) { // create slot (2.1.1)
- return cost + params.SstoreSetGasEIP2200, nil
- }
- if value == (common.Hash{}) { // delete slot (2.1.2b)
- evm.StateDB.AddRefund(clearingRefund)
- }
- // EIP-2200 original clause:
- // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
- return cost + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929), nil // write existing slot (2.1.2)
- }
- if original != (common.Hash{}) {
- if current == (common.Hash{}) { // recreate slot (2.2.1.1)
- evm.StateDB.SubRefund(clearingRefund)
- } else if value == (common.Hash{}) { // delete slot (2.2.1.2)
- evm.StateDB.AddRefund(clearingRefund)
- }
- }
- if original == value {
- if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
- // EIP 2200 Original clause:
- //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
- evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.WarmStorageReadCostEIP2929)
- } else { // reset to original existing slot (2.2.2.2)
- // EIP 2200 Original clause:
- // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
- // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST)
- // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST
- // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST
- evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.WarmStorageReadCostEIP2929)
- }
+ if value == (common.Hash{}) { // delete slot (2.1.2b)
+ evm.StateDB.AddRefund(clearingRefund)
}
// EIP-2200 original clause:
- //return params.SloadGasEIP2200, nil // dirty update (2.2)
- return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.2)
+ // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
+ return cost + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929), nil // write existing slot (2.1.2)
}
+ if original != (common.Hash{}) {
+ if current == (common.Hash{}) { // recreate slot (2.2.1.1)
+ evm.StateDB.SubRefund(clearingRefund)
+ } else if value == (common.Hash{}) { // delete slot (2.2.1.2)
+ evm.StateDB.AddRefund(clearingRefund)
+ }
+ }
+ if original == value {
+ if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
+ // EIP 2200 Original clause:
+ //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
+ evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.WarmStorageReadCostEIP2929)
+ } else { // reset to original existing slot (2.2.2.2)
+ // EIP 2200 Original clause:
+ // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
+ // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST)
+ // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST
+ // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST
+ evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.WarmStorageReadCostEIP2929)
+ }
+ }
+ // EIP-2200 original clause:
+ //return params.SloadGasEIP2200, nil // dirty update (2.2)
+ return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.2)
}
// gasSLoadEIP2929 calculates dynamic gas for SLOAD according to EIP-2929
@@ -95,8 +93,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
// whose storage is being read) is not yet in accessed_storage_keys,
// charge 2100 gas and add the pair to accessed_storage_keys.
// If the pair is already in accessed_storage_keys, charge 100 gas.
-func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- loc := stack.peek()
+func gasSLoadEIP2929(evm *EVM, contract *Contract, loc *uint256.Int) (uint64, error) {
slot := common.Hash(loc.Bytes32())
// Check slot presence in the access list
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
@@ -113,13 +110,13 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
// > If the target is not in accessed_addresses,
// > charge COLD_ACCOUNT_ACCESS_COST gas, and add the address to accessed_addresses.
// > Otherwise, charge WARM_STORAGE_READ_COST gas.
-func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasExtCodeCopyEIP2929(evm *EVM, mem *Memory, memorySize uint64, a, length *uint256.Int) (uint64, error) {
// memory expansion first (dynamic part of pre-2929 implementation)
- gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
+ gas, err := memoryCopierGas(mem, memorySize, length)
if err != nil {
return 0, err
}
- addr := common.Address(stack.peek().Bytes20())
+ addr := common.Address(a.Bytes20())
// Check slot presence in the access list
if !evm.StateDB.AddressInAccessList(addr) {
evm.StateDB.AddAddressToAccessList(addr)
@@ -140,172 +137,129 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo
// - extcodehash,
// - extcodesize,
// - (ext) balance
-func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- addr := common.Address(stack.peek().Bytes20())
+func gasEip2929AccountCheck(evm *EVM, addr *uint256.Int) (uint64, error) {
+ address := common.Address(addr.Bytes20())
// Check slot presence in the access list
- if !evm.StateDB.AddressInAccessList(addr) {
+ if !evm.StateDB.AddressInAccessList(address) {
// If the caller cannot afford the cost, this change will be rolled back
- evm.StateDB.AddAddressToAccessList(addr)
+ evm.StateDB.AddAddressToAccessList(address)
// The warm storage read cost is already charged as constantGas
return params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929, nil
}
return 0, nil
}
-func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) gasFunc {
- return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- addr := common.Address(stack.Back(addressPosition).Bytes20())
- // Check slot presence in the access list
- warmAccess := evm.StateDB.AddressInAccessList(addr)
+func gasCallEIP2929(evm *EVM, contract *Contract, address *uint256.Int, oldCalculator func() (uint64, error)) (uint64, error) {
+ addr := common.Address(address.Bytes20())
+ // Check slot presence in the access list
+ warmAccess := evm.StateDB.AddressInAccessList(addr)
+ // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
+ // the cost to charge for cold access, if any, is Cold - Warm
+ coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
+ if !warmAccess {
+ evm.StateDB.AddAddressToAccessList(addr)
+ // Charge the remaining difference here already, to correctly calculate available
+ // gas for call
+ if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
+ return 0, ErrOutOfGas
+ }
+ }
+ // Now call the old calculator, which takes into account
+ // - create new account
+ // - transfer value
+ // - memory expansion
+ // - 63/64ths rule
+ gas, err := oldCalculator()
+ if warmAccess || err != nil {
+ return gas, err
+ }
+ // In case of a cold access, we temporarily add the cold charge back, and also
+ // add it to the returned gas. By adding it to the return, it will be charged
+ // outside of this function, as part of the dynamic gas, and that will make it
+ // also become correctly reported to tracers.
+ contract.Gas += coldCost
+
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, coldCost); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, nil
+}
+
+func gasSelfdestructEIP(evm *EVM, contract *Contract, addr *uint256.Int, refundsEnabled bool) (uint64, error) {
+ var (
+ gas uint64
+ address = common.Address(addr.Bytes20())
+ )
+ if !evm.StateDB.AddressInAccessList(address) {
+ // If the caller cannot afford the cost, this change will be rolled back
+ evm.StateDB.AddAddressToAccessList(address)
+ gas = params.ColdAccountAccessCostEIP2929
+ }
+ // if empty and transfers value
+ if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
+ gas += params.CreateBySelfdestructGas
+ }
+ if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) {
+ evm.StateDB.AddRefund(params.SelfdestructRefundGas)
+ }
+ return gas, nil
+}
+
+func gasCallEIP7702(evm *EVM, contract *Contract, address *uint256.Int, oldCalculator func() (uint64, error)) (uint64, error) {
+ var (
+ total uint64 // total dynamic gas used
+ addr = common.Address(address.Bytes20())
+ )
+
+ // Check slot presence in the access list
+ if !evm.StateDB.AddressInAccessList(addr) {
+ evm.StateDB.AddAddressToAccessList(addr)
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
// the cost to charge for cold access, if any, is Cold - Warm
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
- if !warmAccess {
- evm.StateDB.AddAddressToAccessList(addr)
- // Charge the remaining difference here already, to correctly calculate available
- // gas for call
- if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
- return 0, ErrOutOfGas
- }
+ // Charge the remaining difference here already, to correctly calculate available
+ // gas for call
+ if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
+ return 0, ErrOutOfGas
}
- // Now call the old calculator, which takes into account
- // - create new account
- // - transfer value
- // - memory expansion
- // - 63/64ths rule
- gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
- if warmAccess || err != nil {
- return gas, err
- }
- // In case of a cold access, we temporarily add the cold charge back, and also
- // add it to the returned gas. By adding it to the return, it will be charged
- // outside of this function, as part of the dynamic gas, and that will make it
- // also become correctly reported to tracers.
- contract.Gas += coldCost
-
- var overflow bool
- if gas, overflow = math.SafeAdd(gas, coldCost); overflow {
- return 0, ErrGasUintOverflow
- }
- return gas, nil
+ total += coldCost
}
-}
-var (
- gasCallEIP2929 = makeCallVariantGasCallEIP2929(gasCall, 1)
- gasDelegateCallEIP2929 = makeCallVariantGasCallEIP2929(gasDelegateCall, 1)
- gasStaticCallEIP2929 = makeCallVariantGasCallEIP2929(gasStaticCall, 1)
- gasCallCodeEIP2929 = makeCallVariantGasCallEIP2929(gasCallCode, 1)
- gasSelfdestructEIP2929 = makeSelfdestructGasFn(true)
- // gasSelfdestructEIP3529 implements the changes in EIP-3529 (no refunds)
- gasSelfdestructEIP3529 = makeSelfdestructGasFn(false)
-
- // gasSStoreEIP2929 implements gas cost for SSTORE according to EIP-2929
- //
- // When calling SSTORE, check if the (address, storage_key) pair is in accessed_storage_keys.
- // If it is not, charge an additional COLD_SLOAD_COST gas, and add the pair to accessed_storage_keys.
- // Additionally, modify the parameters defined in EIP 2200 as follows:
- //
- // Parameter Old value New value
- // SLOAD_GAS 800 = WARM_STORAGE_READ_COST
- // SSTORE_RESET_GAS 5000 5000 - COLD_SLOAD_COST
- //
- //The other parameters defined in EIP 2200 are unchanged.
- // see gasSStoreEIP2200(...) in core/vm/gas_table.go for more info about how EIP 2200 is specified
- gasSStoreEIP2929 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP2200)
-
- // gasSStoreEIP3529 implements gas cost for SSTORE according to EIP-3529
- // Replace `SSTORE_CLEARS_SCHEDULE` with `SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST` (4,800)
- gasSStoreEIP3529 = makeGasSStoreFunc(params.SstoreClearsScheduleRefundEIP3529)
-)
-
-// makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529
-func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
- gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- var (
- gas uint64
- address = common.Address(stack.peek().Bytes20())
- )
- if !evm.StateDB.AddressInAccessList(address) {
- // If the caller cannot afford the cost, this change will be rolled back
- evm.StateDB.AddAddressToAccessList(address)
- gas = params.ColdAccountAccessCostEIP2929
+ // Check if code is a delegation and if so, charge for resolution.
+ if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok {
+ var cost uint64
+ if evm.StateDB.AddressInAccessList(target) {
+ cost = params.WarmStorageReadCostEIP2929
+ } else {
+ evm.StateDB.AddAddressToAccessList(target)
+ cost = params.ColdAccountAccessCostEIP2929
}
- // if empty and transfers value
- if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
- gas += params.CreateBySelfdestructGas
+ if !contract.UseGas(cost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
+ return 0, ErrOutOfGas
}
- if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) {
- evm.StateDB.AddRefund(params.SelfdestructRefundGas)
- }
- return gas, nil
+ total += cost
}
- return gasFunc
-}
-var (
- gasCallEIP7702 = makeCallVariantGasCallEIP7702(gasCall)
- gasDelegateCallEIP7702 = makeCallVariantGasCallEIP7702(gasDelegateCall)
- gasStaticCallEIP7702 = makeCallVariantGasCallEIP7702(gasStaticCall)
- gasCallCodeEIP7702 = makeCallVariantGasCallEIP7702(gasCallCode)
-)
-
-func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
- return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- var (
- total uint64 // total dynamic gas used
- addr = common.Address(stack.Back(1).Bytes20())
- )
-
- // Check slot presence in the access list
- if !evm.StateDB.AddressInAccessList(addr) {
- evm.StateDB.AddAddressToAccessList(addr)
- // The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
- // the cost to charge for cold access, if any, is Cold - Warm
- coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
- // Charge the remaining difference here already, to correctly calculate available
- // gas for call
- if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
- return 0, ErrOutOfGas
- }
- total += coldCost
- }
-
- // Check if code is a delegation and if so, charge for resolution.
- if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok {
- var cost uint64
- if evm.StateDB.AddressInAccessList(target) {
- cost = params.WarmStorageReadCostEIP2929
- } else {
- evm.StateDB.AddAddressToAccessList(target)
- cost = params.ColdAccountAccessCostEIP2929
- }
- if !contract.UseGas(cost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
- return 0, ErrOutOfGas
- }
- total += cost
- }
-
- // Now call the old calculator, which takes into account
- // - create new account
- // - transfer value
- // - memory expansion
- // - 63/64ths rule
- old, err := oldCalculator(evm, contract, stack, mem, memorySize)
- if err != nil {
- return old, err
- }
-
- // Temporarily add the gas charge back to the contract and return value. By
- // adding it to the return, it will be charged outside of this function, as
- // part of the dynamic gas. This will ensure it is correctly reported to
- // tracers.
- contract.Gas += total
-
- var overflow bool
- if total, overflow = math.SafeAdd(old, total); overflow {
- return 0, ErrGasUintOverflow
- }
- return total, nil
+ // Now call the old calculator, which takes into account
+ // - create new account
+ // - transfer value
+ // - memory expansion
+ // - 63/64ths rule
+ old, err := oldCalculator()
+ if err != nil {
+ return old, err
}
+
+ // Temporarily add the gas charge back to the contract and return value. By
+ // adding it to the return, it will be charged outside of this function, as
+ // part of the dynamic gas. This will ensure it is correctly reported to
+ // tracers.
+ contract.Gas += total
+
+ var overflow bool
+ if total, overflow = math.SafeAdd(old, total); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return total, nil
}
diff --git a/core/vm/operations_verkle.go b/core/vm/operations_verkle.go
index 30f9957775..decb640aa5 100644
--- a/core/vm/operations_verkle.go
+++ b/core/vm/operations_verkle.go
@@ -22,93 +22,84 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
)
-func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- return evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true, contract.Gas, true), nil
+func gasSStore4762(evm *EVM, contract *Contract, loc *uint256.Int) (uint64, error) {
+ return evm.AccessEvents.SlotGas(contract.Address(), loc.Bytes32(), true, contract.Gas, true), nil
}
-func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- return evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false, contract.Gas, true), nil
+func gasSLoad4762(evm *EVM, contract *Contract, loc *uint256.Int) (uint64, error) {
+ return evm.AccessEvents.SlotGas(contract.Address(), loc.Bytes32(), false, contract.Gas, true), nil
}
-func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- address := stack.peek().Bytes20()
- return evm.AccessEvents.BasicDataGas(address, false, contract.Gas, true), nil
+func gasBalance4762(evm *EVM, contract *Contract, addr *uint256.Int) (uint64, error) {
+ return evm.AccessEvents.BasicDataGas(addr.Bytes20(), false, contract.Gas, true), nil
}
-func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- address := stack.peek().Bytes20()
+func gasExtCodeSize4762(evm *EVM, contract *Contract, addr *uint256.Int) (uint64, error) {
+ address := addr.Bytes20()
if _, isPrecompile := evm.precompile(address); isPrecompile {
return 0, nil
}
return evm.AccessEvents.BasicDataGas(address, false, contract.Gas, true), nil
}
-func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- address := stack.peek().Bytes20()
+func gasExtCodeHash4762(evm *EVM, contract *Contract, addr *uint256.Int) (uint64, error) {
+ address := addr.Bytes20()
if _, isPrecompile := evm.precompile(address); isPrecompile {
return 0, nil
}
return evm.AccessEvents.CodeHashGas(address, false, contract.Gas, true), nil
}
-func makeCallVariantGasEIP4762(oldCalculator gasFunc, withTransferCosts bool) gasFunc {
- return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- var (
- target = common.Address(stack.Back(1).Bytes20())
- witnessGas uint64
- _, isPrecompile = evm.precompile(target)
- isSystemContract = target == params.HistoryStorageAddress
- )
+func gasCallEIP4762(evm *EVM, contract *Contract, oldCalculator func() (uint64, error), addr, value *uint256.Int, withTransferCosts bool) (uint64, error) {
+ var (
+ target = common.Address(addr.Bytes20())
+ witnessGas uint64
+ _, isPrecompile = evm.precompile(target)
+ isSystemContract = target == params.HistoryStorageAddress
+ )
- // If value is transferred, it is charged before 1/64th
- // is subtracted from the available gas pool.
- if withTransferCosts && !stack.Back(2).IsZero() {
- wantedValueTransferWitnessGas := evm.AccessEvents.ValueTransferGas(contract.Address(), target, contract.Gas)
- if wantedValueTransferWitnessGas > contract.Gas {
- return wantedValueTransferWitnessGas, nil
- }
- witnessGas = wantedValueTransferWitnessGas
- } else if isPrecompile || isSystemContract {
- witnessGas = params.WarmStorageReadCostEIP2929
- } else {
- // The charging for the value transfer is done BEFORE subtracting
- // the 1/64th gas, as this is considered part of the CALL instruction.
- // (so before we get to this point)
- // But the message call is part of the subcall, for which only 63/64th
- // of the gas should be available.
- wantedMessageCallWitnessGas := evm.AccessEvents.MessageCallGas(target, contract.Gas-witnessGas)
- var overflow bool
- if witnessGas, overflow = math.SafeAdd(witnessGas, wantedMessageCallWitnessGas); overflow {
- return 0, ErrGasUintOverflow
- }
- if witnessGas > contract.Gas {
- return witnessGas, nil
- }
+ // If value is transferred, it is charged before 1/64th
+ // is subtracted from the available gas pool.
+ if withTransferCosts && !value.IsZero() {
+ wantedValueTransferWitnessGas := evm.AccessEvents.ValueTransferGas(contract.Address(), target, contract.Gas)
+ if wantedValueTransferWitnessGas > contract.Gas {
+ return wantedValueTransferWitnessGas, nil
}
-
- contract.Gas -= witnessGas
- // if the operation fails, adds witness gas to the gas before returning the error
- gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
- contract.Gas += witnessGas // restore witness gas so that it can be charged at the callsite
+ witnessGas = wantedValueTransferWitnessGas
+ } else if isPrecompile || isSystemContract {
+ witnessGas = params.WarmStorageReadCostEIP2929
+ } else {
+ // The charging for the value transfer is done BEFORE subtracting
+ // the 1/64th gas, as this is considered part of the CALL instruction.
+ // (so before we get to this point)
+ // But the message call is part of the subcall, for which only 63/64th
+ // of the gas should be available.
+ wantedMessageCallWitnessGas := evm.AccessEvents.MessageCallGas(target, contract.Gas-witnessGas)
var overflow bool
- if gas, overflow = math.SafeAdd(gas, witnessGas); overflow {
+ if witnessGas, overflow = math.SafeAdd(witnessGas, wantedMessageCallWitnessGas); overflow {
return 0, ErrGasUintOverflow
}
- return gas, err
+ if witnessGas > contract.Gas {
+ return witnessGas, nil
+ }
}
+
+ contract.Gas -= witnessGas
+ // if the operation fails, adds witness gas to the gas before returning the error
+ gas, err := oldCalculator()
+ contract.Gas += witnessGas // restore witness gas so that it can be charged at the callsite
+ var overflow bool
+ if gas, overflow = math.SafeAdd(gas, witnessGas); overflow {
+ return 0, ErrGasUintOverflow
+ }
+ return gas, err
}
-var (
- gasCallEIP4762 = makeCallVariantGasEIP4762(gasCall, true)
- gasCallCodeEIP4762 = makeCallVariantGasEIP4762(gasCallCode, false)
- gasStaticCallEIP4762 = makeCallVariantGasEIP4762(gasStaticCall, false)
- gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall, false)
-)
-
-func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- beneficiaryAddr := common.Address(stack.peek().Bytes20())
+func gasSelfdestructEIP4762(evm *EVM, contract *Contract, beneficiary *uint256.Int) (uint64, error) {
+ beneficiaryAddr := common.Address(beneficiary.Bytes20())
if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile {
return 0, nil
}
@@ -159,16 +150,12 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem
return statelessGas, nil
}
-func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
- gas, err := gasCodeCopy(evm, contract, stack, mem, memorySize)
+func gasCodeCopyEip4762(evm *EVM, contract *Contract, mem *Memory, memorySize uint64, codeOffset, length *uint256.Int) (uint64, error) {
+ gas, err := memoryCopierGas(mem, memorySize, length)
if err != nil {
return 0, err
}
if !contract.IsDeployment && !contract.IsSystemCall {
- var (
- codeOffset = stack.Back(1)
- length = stack.Back(2)
- )
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = gomath.MaxUint64
@@ -181,13 +168,13 @@ func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
return gas, nil
}
-func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, mem *Memory, memorySize uint64, a, length *uint256.Int) (uint64, error) {
// memory expansion first (dynamic part of pre-2929 implementation)
- gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
+ gas, err := memoryCopierGas(mem, memorySize, length)
if err != nil {
return 0, err
}
- addr := common.Address(stack.peek().Bytes20())
+ addr := common.Address(a.Bytes20())
_, isPrecompile := evm.precompile(addr)
if isPrecompile || addr == params.HistoryStorageAddress {
var overflow bool
diff --git a/core/vm/stack.go b/core/vm/stack.go
index 879dc9aa6d..2a29b60074 100644
--- a/core/vm/stack.go
+++ b/core/vm/stack.go
@@ -17,8 +17,11 @@
package vm
import (
+ "reflect"
"sync"
+ "unsafe"
+ "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
@@ -49,79 +52,411 @@ func (st *Stack) Data() []uint256.Int {
return st.data
}
-func (st *Stack) push(d *uint256.Int) {
- // NOTE push limit (1024) is checked in baseCheck
- st.data = append(st.data, *d)
-}
-
-func (st *Stack) pop() (ret uint256.Int) {
- ret = st.data[len(st.data)-1]
- st.data = st.data[:len(st.data)-1]
- return
-}
-
func (st *Stack) len() int {
return len(st.data)
}
-func (st *Stack) swap1() {
- st.data[st.len()-2], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-2]
-}
-func (st *Stack) swap2() {
- st.data[st.len()-3], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-3]
-}
-func (st *Stack) swap3() {
- st.data[st.len()-4], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-4]
-}
-func (st *Stack) swap4() {
- st.data[st.len()-5], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-5]
-}
-func (st *Stack) swap5() {
- st.data[st.len()-6], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-6]
-}
-func (st *Stack) swap6() {
- st.data[st.len()-7], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-7]
-}
-func (st *Stack) swap7() {
- st.data[st.len()-8], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-8]
-}
-func (st *Stack) swap8() {
- st.data[st.len()-9], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-9]
-}
-func (st *Stack) swap9() {
- st.data[st.len()-10], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-10]
-}
-func (st *Stack) swap10() {
- st.data[st.len()-11], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-11]
-}
-func (st *Stack) swap11() {
- st.data[st.len()-12], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-12]
-}
-func (st *Stack) swap12() {
- st.data[st.len()-13], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-13]
-}
-func (st *Stack) swap13() {
- st.data[st.len()-14], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-14]
-}
-func (st *Stack) swap14() {
- st.data[st.len()-15], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-15]
-}
-func (st *Stack) swap15() {
- st.data[st.len()-16], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-16]
-}
-func (st *Stack) swap16() {
- st.data[st.len()-17], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-17]
+func (st *Stack) growUnsafeByN(n uint) {
+ sh := (*reflect.SliceHeader)(unsafe.Pointer(&st.data))
+ sh.Len += int(n)
}
-func (st *Stack) dup(n int) {
- st.push(&st.data[st.len()-n])
+func (st *Stack) push(d *uint256.Int) error {
+ if uint64(st.len()) >= params.StackLimit {
+ return ErrStackOverflow{st.len(), int(params.StackLimit)}
+ }
+ st.data = append(st.data, *d)
+ return nil
}
-func (st *Stack) peek() *uint256.Int {
- return &st.data[st.len()-1]
+func (st *Stack) pop(peekLastN uint) (*uint256.Int, error) {
+ const requiredDepth = 1
+ depth := st.len()
+ if depth < requiredDepth {
+ return nil, ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ stack := st.data
+ st.data = st.data[:depth-requiredDepth]
+ st.growUnsafeByN(peekLastN)
+ return &stack[depth-1], nil
}
-// Back returns the n'th item in stack
-func (st *Stack) Back(n int) *uint256.Int {
- return &st.data[st.len()-n-1]
+func (st *Stack) pop2(peekLastN uint) (*uint256.Int, *uint256.Int, error) {
+ const requiredDepth = 2
+ depth := st.len()
+ if depth < requiredDepth {
+ return nil, nil, ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ stack := st.data
+ st.data = st.data[:depth-requiredDepth]
+ st.growUnsafeByN(peekLastN)
+ return &stack[depth-1], &stack[depth-2], nil
+}
+
+func (st *Stack) pop3(peekLastN uint) (*uint256.Int, *uint256.Int, *uint256.Int, error) {
+ const requiredDepth = 3
+ depth := st.len()
+ if depth < requiredDepth {
+ return nil, nil, nil, ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ stack := st.data
+ st.data = st.data[:depth-requiredDepth]
+ st.growUnsafeByN(peekLastN)
+ return &stack[depth-1], &stack[depth-2], &stack[depth-3], nil
+}
+
+func (st *Stack) pop4(peekLastN uint) (*uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, error) {
+ const requiredDepth = 4
+ depth := st.len()
+ if depth < requiredDepth {
+ return nil, nil, nil, nil, ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ stack := st.data
+ st.data = st.data[:depth-requiredDepth]
+ st.growUnsafeByN(peekLastN)
+ return &stack[depth-1], &stack[depth-2], &stack[depth-3], &stack[depth-4], nil
+}
+
+func (st *Stack) pop6(peekLastN uint) (*uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, error) {
+ const requiredDepth = 6
+ depth := st.len()
+ if depth < requiredDepth {
+ return nil, nil, nil, nil, nil, nil, ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ stack := st.data
+ st.data = st.data[:depth-requiredDepth]
+ st.growUnsafeByN(peekLastN)
+ return &stack[depth-1], &stack[depth-2], &stack[depth-3], &stack[depth-4], &stack[depth-5], &stack[depth-6], nil
+}
+
+func (st *Stack) pop7(peekLastN uint) (*uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, *uint256.Int, error) {
+ const requiredDepth = 7
+ depth := st.len()
+ if depth < requiredDepth {
+ return nil, nil, nil, nil, nil, nil, nil, ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ stack := st.data
+ st.data = st.data[:depth-requiredDepth]
+ st.growUnsafeByN(peekLastN)
+ return &stack[depth-1], &stack[depth-2], &stack[depth-3], &stack[depth-4], &stack[depth-5], &stack[depth-6], &stack[depth-7], nil
+}
+
+func (st *Stack) swap1() error {
+ const requiredDepth = 2
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap2() error {
+ const requiredDepth = 3
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap3() error {
+ const requiredDepth = 4
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap4() error {
+ const requiredDepth = 5
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap5() error {
+ const requiredDepth = 6
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap6() error {
+ const requiredDepth = 7
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap7() error {
+ const requiredDepth = 8
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap8() error {
+ const requiredDepth = 9
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap9() error {
+ const requiredDepth = 10
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap10() error {
+ const requiredDepth = 11
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap11() error {
+ const requiredDepth = 12
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap12() error {
+ const requiredDepth = 13
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap13() error {
+ const requiredDepth = 14
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap14() error {
+ const requiredDepth = 15
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap15() error {
+ const requiredDepth = 16
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) swap16() error {
+ const requiredDepth = 17
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ topOfStack := st.data[depth-requiredDepth:]
+ topOfStack[0], topOfStack[len(topOfStack)-1] = topOfStack[len(topOfStack)-1], topOfStack[0]
+ return nil
+}
+
+func (st *Stack) dup1() error {
+ const requiredDepth = 1
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup2() error {
+ const requiredDepth = 2
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup3() error {
+ const requiredDepth = 3
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup4() error {
+ const requiredDepth = 4
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup5() error {
+ const requiredDepth = 5
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup6() error {
+ const requiredDepth = 6
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup7() error {
+ const requiredDepth = 7
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup8() error {
+ const requiredDepth = 8
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup9() error {
+ const requiredDepth = 9
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup10() error {
+ const requiredDepth = 10
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup11() error {
+ const requiredDepth = 11
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup12() error {
+ const requiredDepth = 12
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup13() error {
+ const requiredDepth = 13
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup14() error {
+ const requiredDepth = 14
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup15() error {
+ const requiredDepth = 15
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
+}
+
+func (st *Stack) dup16() error {
+ const requiredDepth = 16
+ depth := st.len()
+ if depth < requiredDepth {
+ return ErrStackUnderflow{st.len(), requiredDepth}
+ }
+ return st.push(&st.data[depth-requiredDepth])
}
diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go
deleted file mode 100644
index 10c12901af..0000000000
--- a/core/vm/stack_table.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2017 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 .
-
-package vm
-
-import (
- "github.com/ethereum/go-ethereum/params"
-)
-
-func minSwapStack(n int) int {
- return minStack(n, n)
-}
-func maxSwapStack(n int) int {
- return maxStack(n, n)
-}
-
-func minDupStack(n int) int {
- return minStack(n, n+1)
-}
-func maxDupStack(n int) int {
- return maxStack(n, n+1)
-}
-
-func maxStack(pop, push int) int {
- return int(params.StackLimit) + pop - push
-}
-func minStack(pops, push int) int {
- return pops
-}
diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go
index 8bf9d048d7..a65420e4ab 100644
--- a/eth/tracers/internal/tracetest/calltrace_test.go
+++ b/eth/tracers/internal/tracetest/calltrace_test.go
@@ -286,7 +286,7 @@ func TestInternals(t *testing.T) {
name: "Stack depletion in LOG0",
code: []byte{byte(vm.LOG3)},
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
- want: fmt.Sprintf(`{"from":"%s","gas":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, originHex),
+ want: fmt.Sprintf(`{"from":"%s","gas":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 2)","value":"0x0","type":"CALL"}`, originHex),
},
{
name: "Mem expansion in LOG0",