aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/vm.go
diff options
context:
space:
mode:
authorJeffrey Wilcke <geffobscura@gmail.com>2016-10-08 06:23:45 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2016-10-15 00:09:17 +0800
commit64af2aafdaf16d0bab4c2b89573324b076602bab (patch)
treefb8f5d30ce7ff12ee8f56c3621254edea55885be /core/vm/vm.go
parenteeb2a1a6e3c7a0c77ee6836f3103708cff4102ad (diff)
downloadgo-tangerine-64af2aafdaf16d0bab4c2b89573324b076602bab.tar.gz
go-tangerine-64af2aafdaf16d0bab4c2b89573324b076602bab.tar.zst
go-tangerine-64af2aafdaf16d0bab4c2b89573324b076602bab.zip
core, core/vm: added gas price variance table
This implements 1b & 1c of EIP150 by adding a new GasTable which must be returned from the RuleSet config method. This table is used to determine the gas prices for the current epoch. Please note that when the CreateBySuicide gas price is set it is assumed that we're in the new epoch phase. In addition this PR will serve as temporary basis while refactorisation in being done in the EVM64 PR, which will substentially overhaul the gas price code.
Diffstat (limited to 'core/vm/vm.go')
-rw-r--r--core/vm/vm.go77
1 files changed, 66 insertions, 11 deletions
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 033ada21c..fcffcf317 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -44,6 +44,7 @@ type EVM struct {
env Environment
jumpTable vmJumpTable
cfg Config
+ gasTable params.GasTable
}
// New returns a new instance of the EVM.
@@ -52,6 +53,7 @@ func New(env Environment, cfg Config) *EVM {
env: env,
jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()),
cfg: cfg,
+ gasTable: env.RuleSet().GasTable(env.BlockNumber()),
}
}
@@ -169,7 +171,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Get the memory location of pc
op = contract.GetOp(pc)
// calculate the new memory size and gas price for the current executing opcode
- newMemSize, cost, err = calculateGasAndSize(evm.env, contract, caller, op, statedb, mem, stack)
+ newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
if err != nil {
return nil, err
}
@@ -234,7 +236,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
// the operation. This does not reduce gas or resizes the memory.
-func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
+func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
@@ -246,6 +248,24 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
// stack Check, memory resize & gas phase
switch op {
+ case SUICIDE:
+ // if suicide is not nil: homestead gas fork
+ if gasTable.CreateBySuicide != nil {
+ gas.Set(gasTable.Suicide)
+ if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) {
+ gas.Add(gas, gasTable.CreateBySuicide)
+ }
+ }
+
+ if !statedb.HasSuicided(contract.Address()) {
+ statedb.AddRefund(params.SuicideRefundGas)
+ }
+ case EXTCODESIZE:
+ gas.Set(gasTable.ExtcodeSize)
+ case BALANCE:
+ gas.Set(gasTable.Balance)
+ case SLOAD:
+ gas.Set(gasTable.SLoad)
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
err := stack.require(n)
@@ -274,6 +294,8 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
newMemSize = calcMemSize(mStart, mSize)
+
+ quadMemGas(mem, newMemSize, gas)
case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
case SSTORE:
@@ -302,67 +324,100 @@ func calculateGasAndSize(env Environment, contract *Contract, caller ContractRef
g = params.SstoreResetGas
}
gas.Set(g)
- case SUICIDE:
- if !statedb.HasSuicided(contract.Address()) {
- statedb.AddRefund(params.SuicideRefundGas)
- }
case MLOAD:
newMemSize = calcMemSize(stack.peek(), u256(32))
+ quadMemGas(mem, newMemSize, gas)
case MSTORE8:
newMemSize = calcMemSize(stack.peek(), u256(1))
+ quadMemGas(mem, newMemSize, gas)
case MSTORE:
newMemSize = calcMemSize(stack.peek(), u256(32))
+ quadMemGas(mem, newMemSize, gas)
case RETURN:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
+ quadMemGas(mem, newMemSize, gas)
case SHA3:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
words := toWordSize(stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, params.Sha3WordGas))
+
+ quadMemGas(mem, newMemSize, gas)
case CALLDATACOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas))
+
+ quadMemGas(mem, newMemSize, gas)
case CODECOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas))
+
+ quadMemGas(mem, newMemSize, gas)
case EXTCODECOPY:
+ gas.Set(gasTable.ExtcodeCopy)
+
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
words := toWordSize(stack.data[stack.len()-4])
gas.Add(gas, words.Mul(words, params.CopyGas))
+ quadMemGas(mem, newMemSize, gas)
case CREATE:
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
+
+ quadMemGas(mem, newMemSize, gas)
case CALL, CALLCODE:
- gas.Add(gas, stack.data[stack.len()-1])
+ gas.Set(gasTable.Calls)
if op == CALL {
if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) {
gas.Add(gas, params.CallNewAccountGas)
}
}
-
if len(stack.data[stack.len()-3].Bytes()) > 0 {
gas.Add(gas, params.CallValueTransferGas)
}
-
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
newMemSize = common.BigMax(x, y)
+
+ quadMemGas(mem, newMemSize, gas)
+
+ cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1])
+ // Replace the stack item with the new gas calculation. This means that
+ // either the original item is left on the stack or the item is replaced by:
+ // (availableGas - gas) * 63 / 64
+ // We replace the stack item so that it's available when the opCall instruction is
+ // called. This information is otherwise lost due to the dependency on *current*
+ // available gas.
+ stack.data[stack.len()-1] = cg
+ gas.Add(gas, cg)
+
case DELEGATECALL:
- gas.Add(gas, stack.data[stack.len()-1])
+ gas.Set(gasTable.Calls)
x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6])
y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4])
newMemSize = common.BigMax(x, y)
+
+ quadMemGas(mem, newMemSize, gas)
+
+ cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1])
+ // Replace the stack item with the new gas calculation. This means that
+ // either the original item is left on the stack or the item is replaced by:
+ // (availableGas - gas) * 63 / 64
+ // We replace the stack item so that it's available when the opCall instruction is
+ // called.
+ stack.data[stack.len()-1] = cg
+ gas.Add(gas, cg)
+
}
- quadMemGas(mem, newMemSize, gas)
return newMemSize, gas, nil
}