aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorMartin Holst Swende <martin@swende.se>2019-08-05 16:01:02 +0800
committerPéter Szilágyi <peterke@gmail.com>2019-08-05 16:01:02 +0800
commitaa6005b469fdd1aa7a95f501ce87908011f43159 (patch)
tree53a14d1b2f32798bbf22b2d74d4cbf16239b86b7 /core
parenta7de796840eeb267e298bcc98cdaa3a538234bef (diff)
downloadgo-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.tar
go-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.tar.gz
go-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.tar.bz2
go-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.tar.lz
go-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.tar.xz
go-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.tar.zst
go-tangerine-aa6005b469fdd1aa7a95f501ce87908011f43159.zip
core/vm, params: refactor chain configuration (#19735)
* params, core/vm: deprecating gastable, part 1 * core/vm, params: deprecate gastable, use both constant and dynamic gas * core/vm, params: remove gastable, remove copypaste * core/vm: make use of the chainrules * interpreter: make tracing count constant+dynamic gas * core/vm: review concerns (param/method name changes) * core/vm: make use of chainrules more
Diffstat (limited to 'core')
-rw-r--r--core/vm/evm.go12
-rw-r--r--core/vm/gas.go10
-rw-r--r--core/vm/gas_table.go335
-rw-r--r--core/vm/instructions.go4
-rw-r--r--core/vm/interpreter.go28
-rw-r--r--core/vm/jump_table.go275
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,