mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
core/vm: refactor stack for less implicit bound checks
This commit is contained in:
parent
cbe64f51c7
commit
27d6bed930
15 changed files with 1541 additions and 1484 deletions
143
core/vm/eips.go
143
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, 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()
|
||||
|
|
@ -449,103 +442,71 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
|
|||
func enable4762(jt *JumpTable) {
|
||||
jt[SSTORE] = &operation{
|
||||
execute: opSstoreEIP4762,
|
||||
minStack: minStack(2, 0),
|
||||
maxStack: maxStack(2, 0),
|
||||
}
|
||||
jt[SLOAD] = &operation{
|
||||
execute: opSLoadEIP4762,
|
||||
minStack: minStack(1, 1),
|
||||
maxStack: maxStack(1, 1),
|
||||
}
|
||||
|
||||
jt[BALANCE] = &operation{
|
||||
execute: opBalanceEIP4762,
|
||||
minStack: minStack(1, 1),
|
||||
maxStack: maxStack(1, 1),
|
||||
}
|
||||
|
||||
jt[EXTCODESIZE] = &operation{
|
||||
execute: opExtCodeSizeEIP4762,
|
||||
minStack: minStack(1, 1),
|
||||
maxStack: maxStack(1, 1),
|
||||
}
|
||||
|
||||
jt[EXTCODEHASH] = &operation{
|
||||
execute: opExtCodeHashEIP4762,
|
||||
minStack: minStack(1, 1),
|
||||
maxStack: maxStack(1, 1),
|
||||
}
|
||||
|
||||
jt[EXTCODECOPY] = &operation{
|
||||
execute: opExtCodeCopyEIP4762,
|
||||
minStack: minStack(4, 0),
|
||||
maxStack: maxStack(4, 0),
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
|
||||
jt[CALLCODE] = &operation{
|
||||
execute: opCallCodeEIP4762,
|
||||
minStack: minStack(7, 1),
|
||||
maxStack: maxStack(7, 1),
|
||||
}
|
||||
|
||||
jt[STATICCALL] = &operation{
|
||||
execute: opStaticCallEIP4762,
|
||||
minStack: minStack(6, 1),
|
||||
maxStack: maxStack(6, 1),
|
||||
}
|
||||
|
||||
jt[DELEGATECALL] = &operation{
|
||||
execute: opDelegateCallEIP4762,
|
||||
minStack: minStack(6, 1),
|
||||
maxStack: maxStack(6, 1),
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,23 +57,15 @@ 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) {
|
||||
// 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 := stack.Back(stackpos).Uint64WithOverflow()
|
||||
words, overflow := words256.Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
|
|
@ -85,21 +78,11 @@ func memoryCopierGas(stackpos int) gasFunc {
|
|||
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,9 +203,8 @@ 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()
|
||||
func gasLog(mem *Memory, memorySize uint64, n uint64, size *uint256.Int) (uint64, error) {
|
||||
requestedSize, overflow := size.Uint64WithOverflow()
|
||||
if overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
|
|
@ -248,15 +229,14 @@ func makeGasLog(n uint64) gasFunc {
|
|||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
}
|
||||
|
||||
func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
func gasKeccak256(mem *Memory, memorySize uint64, size *uint256.Int) (uint64, error) {
|
||||
gas, err := memoryGasCost(mem, memorySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
wordGas, overflow := stack.Back(1).Uint64WithOverflow()
|
||||
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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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 {
|
||||
// Do the copy
|
||||
_, err := opMcopy(&pc, evm.interpreter, &ScopeContext{mem, stack, contract})
|
||||
if wantErr {
|
||||
if err == nil {
|
||||
t.Error("wanted error")
|
||||
}
|
||||
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})
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
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),
|
||||
},
|
||||
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),
|
||||
},
|
||||
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),
|
||||
},
|
||||
LOG1: {
|
||||
execute: makeLog(1),
|
||||
minStack: minStack(3, 0),
|
||||
maxStack: maxStack(3, 0),
|
||||
},
|
||||
LOG2: {
|
||||
execute: makeLog(2),
|
||||
minStack: minStack(4, 0),
|
||||
maxStack: maxStack(4, 0),
|
||||
},
|
||||
LOG3: {
|
||||
execute: makeLog(3),
|
||||
minStack: minStack(5, 0),
|
||||
maxStack: maxStack(5, 0),
|
||||
},
|
||||
LOG4: {
|
||||
execute: makeLog(4),
|
||||
minStack: minStack(6, 0),
|
||||
maxStack: maxStack(6, 0),
|
||||
},
|
||||
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),
|
||||
},
|
||||
SELFDESTRUCT: {
|
||||
execute: opSelfdestructFrontier,
|
||||
minStack: minStack(1, 0),
|
||||
maxStack: maxStack(1, 0),
|
||||
},
|
||||
INVALID: {
|
||||
execute: opUndefined,
|
||||
minStack: minStack(0, 0),
|
||||
maxStack: maxStack(0, 0),
|
||||
},
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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))
|
||||
}
|
||||
|
|
@ -24,18 +24,17 @@ 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) {
|
||||
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 (
|
||||
y, x = stack.Back(1), stack.peek()
|
||||
slot = common.Hash(x.Bytes32())
|
||||
slot = common.Hash(slot256.Bytes32())
|
||||
current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
|
||||
cost = uint64(0)
|
||||
)
|
||||
|
|
@ -45,7 +44,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
|||
// If the caller cannot afford the cost, this change will be rolled back
|
||||
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
||||
}
|
||||
value := common.Hash(y.Bytes32())
|
||||
value := common.Hash(value256.Bytes32())
|
||||
|
||||
if current == value { // noop (1)
|
||||
// EIP 2200 original clause:
|
||||
|
|
@ -87,7 +86,6 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
|
|||
// 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,21 +137,20 @@ 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())
|
||||
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
|
||||
|
|
@ -173,7 +169,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
|
|||
// - transfer value
|
||||
// - memory expansion
|
||||
// - 63/64ths rule
|
||||
gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
||||
gas, err := oldCalculator()
|
||||
if warmAccess || err != nil {
|
||||
return gas, err
|
||||
}
|
||||
|
|
@ -188,43 +184,12 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
|
|||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
func gasSelfdestructEIP(evm *EVM, contract *Contract, addr *uint256.Int, refundsEnabled bool) (uint64, error) {
|
||||
var (
|
||||
gas uint64
|
||||
address = common.Address(stack.peek().Bytes20())
|
||||
address = common.Address(addr.Bytes20())
|
||||
)
|
||||
if !evm.StateDB.AddressInAccessList(address) {
|
||||
// If the caller cannot afford the cost, this change will be rolled back
|
||||
|
|
@ -239,22 +204,12 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
|||
evm.StateDB.AddRefund(params.SelfdestructRefundGas)
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
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) {
|
||||
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(stack.Back(1).Bytes20())
|
||||
addr = common.Address(address.Bytes20())
|
||||
)
|
||||
|
||||
// Check slot presence in the access list
|
||||
|
|
@ -291,7 +246,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
|
|||
// - transfer value
|
||||
// - memory expansion
|
||||
// - 63/64ths rule
|
||||
old, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
||||
old, err := oldCalculator()
|
||||
if err != nil {
|
||||
return old, err
|
||||
}
|
||||
|
|
@ -307,5 +262,4 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
|
|||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,41 +22,40 @@ 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) {
|
||||
func gasCallEIP4762(evm *EVM, contract *Contract, oldCalculator func() (uint64, error), addr, value *uint256.Int, withTransferCosts bool) (uint64, error) {
|
||||
var (
|
||||
target = common.Address(stack.Back(1).Bytes20())
|
||||
target = common.Address(addr.Bytes20())
|
||||
witnessGas uint64
|
||||
_, isPrecompile = evm.precompile(target)
|
||||
isSystemContract = target == params.HistoryStorageAddress
|
||||
|
|
@ -64,7 +63,7 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc, withTransferCosts bool) ga
|
|||
|
||||
// If value is transferred, it is charged before 1/64th
|
||||
// is subtracted from the available gas pool.
|
||||
if withTransferCosts && !stack.Back(2).IsZero() {
|
||||
if withTransferCosts && !value.IsZero() {
|
||||
wantedValueTransferWitnessGas := evm.AccessEvents.ValueTransferGas(contract.Address(), target, contract.Gas)
|
||||
if wantedValueTransferWitnessGas > contract.Gas {
|
||||
return wantedValueTransferWitnessGas, nil
|
||||
|
|
@ -90,25 +89,17 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc, withTransferCosts bool) ga
|
|||
|
||||
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)
|
||||
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
|
||||
|
|
|
|||
465
core/vm/stack.go
465
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])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue