diff options
Diffstat (limited to 'core/vm')
-rw-r--r-- | core/vm/evm.go | 12 | ||||
-rw-r--r-- | core/vm/gas.go | 10 | ||||
-rw-r--r-- | core/vm/gas_table.go | 335 | ||||
-rw-r--r-- | core/vm/instructions.go | 4 | ||||
-rw-r--r-- | core/vm/interpreter.go | 28 | ||||
-rw-r--r-- | core/vm/jump_table.go | 275 |
6 files changed, 287 insertions, 377 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go index d47b00938..030f0c789 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -44,7 +44,7 @@ type ( func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { precompiles := PrecompiledContractsHomestead - if evm.ChainConfig().IsByzantium(evm.BlockNumber) { + if evm.chainRules.IsByzantium { precompiles = PrecompiledContractsByzantium } if p := precompiles[*contract.CodeAddr]; p != nil { @@ -203,10 +203,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas ) if !evm.StateDB.Exist(addr) { precompiles := PrecompiledContractsHomestead - if evm.ChainConfig().IsByzantium(evm.BlockNumber) { + if evm.chainRules.IsByzantium { precompiles = PrecompiledContractsByzantium } - if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { + if precompiles[addr] == nil && evm.chainRules.IsEIP158 && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer if evm.vmConfig.Debug && evm.depth == 0 { evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) @@ -394,7 +394,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Create a new account on the state snapshot := evm.StateDB.Snapshot() evm.StateDB.CreateAccount(address) - if evm.ChainConfig().IsEIP158(evm.BlockNumber) { + if evm.chainRules.IsEIP158 { evm.StateDB.SetNonce(address, 1) } evm.Transfer(evm.StateDB, caller.Address(), address, value) @@ -416,7 +416,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, ret, err := run(evm, contract, nil, false) // check whether the max code size has been exceeded - maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize + maxCodeSizeExceeded := evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize // if the contract creation ran successfully and no errors were returned // calculate the gas required to store the code. If the code could not // be stored due to not enough gas set an error and let it be handled @@ -433,7 +433,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. - if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { + if maxCodeSizeExceeded || (err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas)) { evm.StateDB.RevertToSnapshot(snapshot) if err != errExecutionReverted { contract.UseGas(contract.Gas) diff --git a/core/vm/gas.go b/core/vm/gas.go index 022a84f24..bd8b4f104 100644 --- a/core/vm/gas.go +++ b/core/vm/gas.go @@ -18,8 +18,6 @@ package vm import ( "math/big" - - "github.com/ethereum/go-ethereum/params" ) // Gas costs @@ -34,10 +32,10 @@ const ( // calcGas returns the actual gas cost of the call. // -// The cost of gas was changed during the homestead price change HF. To allow for EIP150 -// to be implemented. The returned gas is gas - base * 63 / 64. -func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) { - if gasTable.CreateBySuicide > 0 { +// The cost of gas was changed during the homestead price change HF. +// As part of EIP 150 (TangerineWhistle), the returned gas is gas - base * 63 / 64. +func callGas(isEip150 bool, availableGas, base uint64, callCost *big.Int) (uint64, error) { + if isEip150 { availableGas = availableGas - base gas := availableGas - availableGas/64 // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150 diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 8270300ba..b2999fdea 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -53,59 +53,45 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { return 0, nil } -func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - - words, overflow := bigUint64(stack.Back(2)) - if overflow { - return 0, errGasUintOverflow - } +// 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) +// EXTCODECOPY (stack poition 3) +// RETURNDATACOPY (stack position 2) +func memoryCopierGas(stackpos int) gasFunc { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // Gas for expanding the memory + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + // And gas for copying data, charged per word at param.CopyGas + words, overflow := bigUint64(stack.Back(stackpos)) + if overflow { + return 0, errGasUintOverflow + } - if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { - return 0, errGasUintOverflow - } + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, errGasUintOverflow + } - if gas, overflow = math.SafeAdd(gas, words); overflow { - return 0, errGasUintOverflow + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, errGasUintOverflow + } + return gas, nil } - return gas, nil } -func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - - words, overflow := bigUint64(stack.Back(2)) - if overflow { - return 0, errGasUintOverflow - } - - if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { - return 0, errGasUintOverflow - } - - if gas, overflow = math.SafeAdd(gas, words); overflow { - return 0, errGasUintOverflow - } - return gas, nil -} +var ( + gasCallDataCopy = memoryCopierGas(2) + gasCodeCopy = memoryCopierGas(2) + gasExtCodeCopy = memoryCopierGas(3) + gasReturnDataCopy = memoryCopierGas(2) +) -func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) @@ -175,7 +161,7 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m } func makeGasLog(n uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { requestedSize, overflow := bigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow @@ -204,17 +190,11 @@ func makeGasLog(n uint64) gasFunc { } } -func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool +func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - - if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow { - return 0, errGasUintOverflow - } - wordGas, overflow := bigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow @@ -228,117 +208,27 @@ func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return gas, nil } -func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - - wordGas, overflow := bigUint64(stack.Back(2)) - if overflow { - return 0, errGasUintOverflow - } - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil -} - -func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - - var overflow bool - if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow { - return 0, errGasUintOverflow - } - - wordGas, overflow := bigUint64(stack.Back(3)) - if overflow { - return 0, errGasUintOverflow - } - - if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { - return 0, errGasUintOverflow - } - - if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil -} - -func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.ExtcodeHash, nil -} - -func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - return gas, nil -} - -func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - return gas, nil -} - -func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, errGasUintOverflow - } - if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { - return 0, errGasUintOverflow - } - 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) } -func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool - gas, err := memoryGasCost(mem, memorySize) - if err != nil { - return 0, err - } - if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow { - return 0, errGasUintOverflow - } - return gas, nil -} +var ( + gasReturn = pureMemoryGascost + gasRevert = pureMemoryGascost + gasMLoad = pureMemoryGascost + gasMStore8 = pureMemoryGascost + gasMStore = pureMemoryGascost + gasCreate = pureMemoryGascost +) -func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool +func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow { - return 0, errGasUintOverflow - } wordGas, overflow := bigUint64(stack.Back(2)) if overflow { return 0, errGasUintOverflow @@ -349,27 +239,27 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, if gas, overflow = math.SafeAdd(gas, wordGas); overflow { return 0, errGasUintOverflow } - return gas, nil } -func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.Balance, nil -} - -func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.ExtcodeSize, 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 gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return gt.SLoad, nil + var ( + gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas + overflow bool + ) + if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { + return 0, errGasUintOverflow + } + return gas, nil } -func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) var ( - gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas + gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas overflow bool ) if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { @@ -378,14 +268,13 @@ func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return gas, nil } -func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( - gas = gt.Calls + gas uint64 transfersValue = stack.Back(2).Sign() != 0 address = common.BigToAddress(stack.Back(1)) - eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) ) - if eip158 { + if evm.chainRules.IsEIP158 { if transfersValue && evm.StateDB.Empty(address) { gas += params.CallNewAccountGas } @@ -404,7 +293,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return 0, errGasUintOverflow } - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } @@ -414,21 +303,22 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem return gas, nil } -func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - gas := gt.Calls - if stack.Back(2).Sign() != 0 { - gas += params.CallValueTransferGas - } +func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { memoryGas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - var overflow bool + var ( + gas uint64 + overflow bool + ) + if stack.Back(2).Sign() != 0 { + gas += params.CallValueTransferGas + } if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { return 0, errGasUintOverflow } - - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } @@ -438,76 +328,57 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, return gas, nil } -func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) -} - -func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) -} - -func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var gas uint64 - // EIP150 homestead gas reprice fork: - if evm.ChainConfig().IsEIP150(evm.BlockNumber) { - gas = gt.Suicide - var ( - address = common.BigToAddress(stack.Back(0)) - eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) - ) - - if eip158 { - // if empty and transfers value - if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { - gas += gt.CreateBySuicide - } - } else if !evm.StateDB.Exist(address) { - gas += gt.CreateBySuicide - } - } - - if !evm.StateDB.HasSuicided(contract.Address()) { - evm.StateDB.AddRefund(params.SuicideRefundGas) - } - return gas, nil -} - -func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - var overflow bool - if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { - return 0, errGasUintOverflow - } - - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } + var overflow bool if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil } -func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - var overflow bool - if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { - return 0, errGasUintOverflow - } - - evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err } + var overflow bool if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { return 0, errGasUintOverflow } return gas, nil } + +func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + var gas uint64 + // EIP150 homestead gas reprice fork: + if evm.chainRules.IsEIP150 { + gas = params.SelfdestructGasEIP150 + var address = common.BigToAddress(stack.Back(0)) + + if evm.chainRules.IsEIP158 { + // if empty and transfers value + if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { + gas += params.CreateBySelfdestructGas + } + } else if !evm.StateDB.Exist(address) { + gas += params.CreateBySelfdestructGas + } + } + + if !evm.StateDB.HasSuicided(contract.Address()) { + evm.StateDB.AddRefund(params.SelfdestructRefundGas) + } + return gas, nil +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2a062d7e7..7b6909c92 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -694,7 +694,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor input = memory.Get(offset.Int64(), size.Int64()) gas = contract.Gas ) - if interpreter.evm.ChainConfig().IsEIP150(interpreter.evm.BlockNumber) { + if interpreter.evm.chainRules.IsEIP150 { gas -= gas / 64 } @@ -704,7 +704,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if interpreter.evm.ChainConfig().IsHomestead(interpreter.evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { + if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { stack.push(interpreter.intPool.getZero()) } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stack.push(interpreter.intPool.getZero()) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 989f85f5d..18081ec4c 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/params" ) // Config are the configuration options for the Interpreter @@ -71,9 +70,8 @@ type keccakState interface { // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { - evm *EVM - cfg Config - gasTable params.GasTable + evm *EVM + cfg Config intPool *intPool @@ -91,11 +89,15 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { switch { - case evm.ChainConfig().IsConstantinople(evm.BlockNumber): + case evm.chainRules.IsConstantinople: cfg.JumpTable = constantinopleInstructionSet - case evm.ChainConfig().IsByzantium(evm.BlockNumber): + case evm.chainRules.IsByzantium: cfg.JumpTable = byzantiumInstructionSet - case evm.ChainConfig().IsHomestead(evm.BlockNumber): + case evm.chainRules.IsEIP158: + cfg.JumpTable = spuriousDragonInstructionSet + case evm.chainRules.IsEIP150: + cfg.JumpTable = tangerineWhistleInstructionSet + case evm.chainRules.IsHomestead: cfg.JumpTable = homesteadInstructionSet default: cfg.JumpTable = frontierInstructionSet @@ -103,9 +105,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { } return &EVMInterpreter{ - evm: evm, - cfg: cfg, - gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), + evm: evm, + cfg: cfg, } } @@ -210,6 +211,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } } // Static portion of gas + cost = operation.constantGas // For tracing if !contract.UseGas(operation.constantGas) { return nil, ErrOutOfGas } @@ -234,8 +236,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method can get the proper cost if operation.dynamicGas != nil { - cost, err = operation.dynamicGas(in.gasTable, in.evm, contract, stack, mem, memorySize) - if err != nil || !contract.UseGas(cost) { + var dynamicCost uint64 + dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) + cost += dynamicCost // total cost, for debug tracing + if err != nil || !contract.UseGas(dynamicCost) { return nil, ErrOutOfGas } } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 425436f9e..a14f3fd98 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -24,7 +24,7 @@ import ( type ( executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) - gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + 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) ) @@ -54,10 +54,12 @@ type operation struct { } var ( - frontierInstructionSet = newFrontierInstructionSet() - homesteadInstructionSet = newHomesteadInstructionSet() - byzantiumInstructionSet = newByzantiumInstructionSet() - constantinopleInstructionSet = newConstantinopleInstructionSet() + frontierInstructionSet = newFrontierInstructionSet() + homesteadInstructionSet = newHomesteadInstructionSet() + tangerineWhistleInstructionSet = newTangerineWhistleInstructionSet() + spuriousDragonInstructionSet = newSpuriousDragonInstructionSet() + byzantiumInstructionSet = newByzantiumInstructionSet() + constantinopleInstructionSet = newConstantinopleInstructionSet() ) // NewConstantinopleInstructionSet returns the frontier, homestead @@ -87,21 +89,22 @@ func newConstantinopleInstructionSet() [256]operation { valid: true, } instructionSet[EXTCODEHASH] = operation{ - execute: opExtCodeHash, - dynamicGas: gasExtCodeHash, - minStack: minStack(1, 1), - maxStack: maxStack(1, 1), - valid: true, + execute: opExtCodeHash, + constantGas: params.ExtcodeHashGas, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, } instructionSet[CREATE2] = operation{ - execute: opCreate2, - dynamicGas: gasCreate2, - minStack: minStack(4, 1), - maxStack: maxStack(4, 1), - memorySize: memoryCreate2, - valid: true, - writes: true, - returns: true, + execute: opCreate2, + constantGas: params.Create2Gas, + dynamicGas: gasCreate2, + minStack: minStack(4, 1), + maxStack: maxStack(4, 1), + memorySize: memoryCreate2, + valid: true, + writes: true, + returns: true, } return instructionSet } @@ -110,15 +113,16 @@ func newConstantinopleInstructionSet() [256]operation { // byzantium instructions. func newByzantiumInstructionSet() [256]operation { // instructions that can be executed during the homestead phase. - instructionSet := newHomesteadInstructionSet() + instructionSet := newSpuriousDragonInstructionSet() instructionSet[STATICCALL] = operation{ - execute: opStaticCall, - dynamicGas: gasStaticCall, - minStack: minStack(6, 1), - maxStack: maxStack(6, 1), - memorySize: memoryStaticCall, - valid: true, - returns: true, + execute: opStaticCall, + constantGas: params.CallGasEIP150, + dynamicGas: gasStaticCall, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryStaticCall, + valid: true, + returns: true, } instructionSet[RETURNDATASIZE] = operation{ execute: opReturnDataSize, @@ -128,12 +132,13 @@ func newByzantiumInstructionSet() [256]operation { valid: true, } instructionSet[RETURNDATACOPY] = operation{ - execute: opReturnDataCopy, - dynamicGas: gasReturnDataCopy, - minStack: minStack(3, 0), - maxStack: maxStack(3, 0), - memorySize: memoryReturnDataCopy, - valid: true, + execute: opReturnDataCopy, + constantGas: GasFastestStep, + dynamicGas: gasReturnDataCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, } instructionSet[REVERT] = operation{ execute: opRevert, @@ -148,18 +153,40 @@ func newByzantiumInstructionSet() [256]operation { return instructionSet } +// EIP 158 a.k.a Spurious Dragon +func newSpuriousDragonInstructionSet() [256]operation { + instructionSet := newTangerineWhistleInstructionSet() + instructionSet[EXP].dynamicGas = gasExpEIP158 + return instructionSet + +} + +// EIP 150 a.k.a Tangerine Whistle +func newTangerineWhistleInstructionSet() [256]operation { + instructionSet := newHomesteadInstructionSet() + instructionSet[BALANCE].constantGas = params.BalanceGasEIP150 + instructionSet[EXTCODESIZE].constantGas = params.ExtcodeSizeGasEIP150 + instructionSet[SLOAD].constantGas = params.SloadGasEIP150 + instructionSet[EXTCODECOPY].constantGas = params.ExtcodeCopyBaseEIP150 + instructionSet[CALL].constantGas = params.CallGasEIP150 + instructionSet[CALLCODE].constantGas = params.CallGasEIP150 + instructionSet[DELEGATECALL].constantGas = params.CallGasEIP150 + return instructionSet +} + // NewHomesteadInstructionSet returns the frontier and homestead // instructions that can be executed during the homestead phase. func newHomesteadInstructionSet() [256]operation { instructionSet := newFrontierInstructionSet() instructionSet[DELEGATECALL] = operation{ - execute: opDelegateCall, - dynamicGas: gasDelegateCall, - minStack: minStack(6, 1), - maxStack: maxStack(6, 1), - memorySize: memoryDelegateCall, - valid: true, - returns: true, + execute: opDelegateCall, + dynamicGas: gasDelegateCall, + constantGas: params.CallGasFrontier, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryDelegateCall, + valid: true, + returns: true, } return instructionSet } @@ -241,7 +268,7 @@ func newFrontierInstructionSet() [256]operation { }, EXP: { execute: opExp, - dynamicGas: gasExp, + dynamicGas: gasExpFrontier, minStack: minStack(2, 1), maxStack: maxStack(2, 1), valid: true, @@ -331,12 +358,13 @@ func newFrontierInstructionSet() [256]operation { valid: true, }, SHA3: { - execute: opSha3, - dynamicGas: gasSha3, - minStack: minStack(2, 1), - maxStack: maxStack(2, 1), - memorySize: memorySha3, - valid: true, + execute: opSha3, + constantGas: params.Sha3Gas, + dynamicGas: gasSha3, + minStack: minStack(2, 1), + maxStack: maxStack(2, 1), + memorySize: memorySha3, + valid: true, }, ADDRESS: { execute: opAddress, @@ -346,11 +374,11 @@ func newFrontierInstructionSet() [256]operation { valid: true, }, BALANCE: { - execute: opBalance, - dynamicGas: gasBalance, - minStack: minStack(1, 1), - maxStack: maxStack(1, 1), - valid: true, + execute: opBalance, + constantGas: params.BalanceGasFrontier, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, ORIGIN: { execute: opOrigin, @@ -388,12 +416,13 @@ func newFrontierInstructionSet() [256]operation { valid: true, }, CALLDATACOPY: { - execute: opCallDataCopy, - dynamicGas: gasCallDataCopy, - minStack: minStack(3, 0), - maxStack: maxStack(3, 0), - memorySize: memoryCallDataCopy, - valid: true, + execute: opCallDataCopy, + constantGas: GasFastestStep, + dynamicGas: gasCallDataCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCallDataCopy, + valid: true, }, CODESIZE: { execute: opCodeSize, @@ -403,12 +432,13 @@ func newFrontierInstructionSet() [256]operation { valid: true, }, CODECOPY: { - execute: opCodeCopy, - dynamicGas: gasCodeCopy, - minStack: minStack(3, 0), - maxStack: maxStack(3, 0), - memorySize: memoryCodeCopy, - valid: true, + execute: opCodeCopy, + constantGas: GasFastestStep, + dynamicGas: gasCodeCopy, + minStack: minStack(3, 0), + maxStack: maxStack(3, 0), + memorySize: memoryCodeCopy, + valid: true, }, GASPRICE: { execute: opGasprice, @@ -418,19 +448,20 @@ func newFrontierInstructionSet() [256]operation { valid: true, }, EXTCODESIZE: { - execute: opExtCodeSize, - dynamicGas: gasExtCodeSize, - minStack: minStack(1, 1), - maxStack: maxStack(1, 1), - valid: true, + execute: opExtCodeSize, + constantGas: params.ExtcodeSizeGasFrontier, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, EXTCODECOPY: { - execute: opExtCodeCopy, - dynamicGas: gasExtCodeCopy, - minStack: minStack(4, 0), - maxStack: maxStack(4, 0), - memorySize: memoryExtCodeCopy, - valid: true, + execute: opExtCodeCopy, + constantGas: params.ExtcodeCopyBaseFrontier, + dynamicGas: gasExtCodeCopy, + minStack: minStack(4, 0), + maxStack: maxStack(4, 0), + memorySize: memoryExtCodeCopy, + valid: true, }, BLOCKHASH: { execute: opBlockhash, @@ -482,36 +513,39 @@ func newFrontierInstructionSet() [256]operation { valid: true, }, MLOAD: { - execute: opMload, - dynamicGas: gasMLoad, - minStack: minStack(1, 1), - maxStack: maxStack(1, 1), - memorySize: memoryMLoad, - valid: true, + execute: opMload, + constantGas: GasFastestStep, + dynamicGas: gasMLoad, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + memorySize: memoryMLoad, + valid: true, }, MSTORE: { - execute: opMstore, - dynamicGas: gasMStore, - minStack: minStack(2, 0), - maxStack: maxStack(2, 0), - memorySize: memoryMStore, - valid: true, + execute: opMstore, + constantGas: GasFastestStep, + dynamicGas: gasMStore, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + memorySize: memoryMStore, + valid: true, }, MSTORE8: { - execute: opMstore8, - dynamicGas: gasMStore8, - memorySize: memoryMStore8, - minStack: minStack(2, 0), - maxStack: maxStack(2, 0), + execute: opMstore8, + constantGas: GasFastestStep, + dynamicGas: gasMStore8, + memorySize: memoryMStore8, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), valid: true, }, SLOAD: { - execute: opSload, - dynamicGas: gasSLoad, - minStack: minStack(1, 1), - maxStack: maxStack(1, 1), - valid: true, + execute: opSload, + constantGas: params.SloadGasFrontier, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + valid: true, }, SSTORE: { execute: opSstore, @@ -1059,32 +1093,35 @@ func newFrontierInstructionSet() [256]operation { writes: true, }, CREATE: { - execute: opCreate, - dynamicGas: gasCreate, - minStack: minStack(3, 1), - maxStack: maxStack(3, 1), - memorySize: memoryCreate, - valid: true, - writes: true, - returns: true, + execute: opCreate, + constantGas: params.CreateGas, + dynamicGas: gasCreate, + minStack: minStack(3, 1), + maxStack: maxStack(3, 1), + memorySize: memoryCreate, + valid: true, + writes: true, + returns: true, }, CALL: { - execute: opCall, - dynamicGas: gasCall, - minStack: minStack(7, 1), - maxStack: maxStack(7, 1), - memorySize: memoryCall, - valid: true, - returns: true, + execute: opCall, + constantGas: params.CallGasFrontier, + dynamicGas: gasCall, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, }, CALLCODE: { - execute: opCallCode, - dynamicGas: gasCallCode, - minStack: minStack(7, 1), - maxStack: maxStack(7, 1), - memorySize: memoryCall, - valid: true, - returns: true, + execute: opCallCode, + constantGas: params.CallGasFrontier, + dynamicGas: gasCallCode, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, }, RETURN: { execute: opReturn, @@ -1097,7 +1134,7 @@ func newFrontierInstructionSet() [256]operation { }, SELFDESTRUCT: { execute: opSuicide, - dynamicGas: gasSuicide, + dynamicGas: gasSelfdestruct, minStack: minStack(1, 0), maxStack: maxStack(1, 0), halts: true, |