|
|
@@ -769,27 +769,97 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
|
|
|
- gas := new(big.Int)
|
|
|
- addStepGasUsage := func(amount *big.Int) {
|
|
|
- if amount.Cmp(ethutil.Big0) >= 0 {
|
|
|
- gas.Add(gas, amount)
|
|
|
- }
|
|
|
+type req struct {
|
|
|
+ stack int
|
|
|
+ gas *big.Int
|
|
|
+}
|
|
|
+
|
|
|
+var _baseCheck = map[OpCode]req{
|
|
|
+ // Req Stack Gas price
|
|
|
+ ADD: {2, GasFastestStep},
|
|
|
+ LT: {2, GasFastestStep},
|
|
|
+ GT: {2, GasFastestStep},
|
|
|
+ SLT: {2, GasFastestStep},
|
|
|
+ SGT: {2, GasFastestStep},
|
|
|
+ EQ: {2, GasFastestStep},
|
|
|
+ ISZERO: {1, GasFastestStep},
|
|
|
+ SUB: {2, GasFastestStep},
|
|
|
+ AND: {2, GasFastestStep},
|
|
|
+ OR: {2, GasFastestStep},
|
|
|
+ XOR: {2, GasFastestStep},
|
|
|
+ NOT: {1, GasFastestStep},
|
|
|
+ BYTE: {2, GasFastestStep},
|
|
|
+ CALLDATALOAD: {1, GasFastestStep},
|
|
|
+ CALLDATACOPY: {3, GasFastestStep},
|
|
|
+ MLOAD: {1, GasFastestStep},
|
|
|
+ MSTORE: {2, GasFastestStep},
|
|
|
+ MSTORE8: {2, GasFastestStep},
|
|
|
+ CODECOPY: {3, GasFastestStep},
|
|
|
+ MUL: {2, GasFastStep},
|
|
|
+ DIV: {2, GasFastStep},
|
|
|
+ SDIV: {2, GasFastStep},
|
|
|
+ MOD: {2, GasFastStep},
|
|
|
+ SMOD: {2, GasFastStep},
|
|
|
+ SIGNEXTEND: {2, GasFastStep},
|
|
|
+ ADDMOD: {3, GasMidStep},
|
|
|
+ MULMOD: {3, GasMidStep},
|
|
|
+ JUMP: {1, GasMidStep},
|
|
|
+ JUMPI: {2, GasSlowStep},
|
|
|
+ EXP: {2, GasSlowStep},
|
|
|
+ ADDRESS: {0, GasQuickStep},
|
|
|
+ ORIGIN: {0, GasQuickStep},
|
|
|
+ CALLER: {0, GasQuickStep},
|
|
|
+ CALLVALUE: {0, GasQuickStep},
|
|
|
+ CODESIZE: {0, GasQuickStep},
|
|
|
+ GASPRICE: {0, GasQuickStep},
|
|
|
+ COINBASE: {0, GasQuickStep},
|
|
|
+ TIMESTAMP: {0, GasQuickStep},
|
|
|
+ NUMBER: {0, GasQuickStep},
|
|
|
+ DIFFICULTY: {0, GasQuickStep},
|
|
|
+ GASLIMIT: {0, GasQuickStep},
|
|
|
+ POP: {0, GasQuickStep},
|
|
|
+ PC: {0, GasQuickStep},
|
|
|
+ MSIZE: {0, GasQuickStep},
|
|
|
+ GAS: {0, GasQuickStep},
|
|
|
+ BLOCKHASH: {1, GasExtStep},
|
|
|
+ BALANCE: {0, GasExtStep},
|
|
|
+ EXTCODESIZE: {1, GasExtStep},
|
|
|
+ EXTCODECOPY: {4, GasExtStep},
|
|
|
+ SLOAD: {1, GasStorageGet},
|
|
|
+ SSTORE: {2, Zero},
|
|
|
+ SHA3: {1, GasSha3Base},
|
|
|
+ CREATE: {3, GasCreate},
|
|
|
+ CALL: {7, GasCall},
|
|
|
+ CALLCODE: {7, GasCall},
|
|
|
+ JUMPDEST: {0, GasJumpDest},
|
|
|
+ SUICIDE: {1, Zero},
|
|
|
+ RETURN: {2, Zero},
|
|
|
+}
|
|
|
+
|
|
|
+func baseCheck(op OpCode, stack *Stack, gas *big.Int) {
|
|
|
+ if r, ok := _baseCheck[op]; ok {
|
|
|
+ stack.require(r.stack)
|
|
|
+
|
|
|
+ gas.Add(gas, r.gas)
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- addStepGasUsage(GasStep)
|
|
|
+func toWordSize(size *big.Int) *big.Int {
|
|
|
+ tmp := new(big.Int)
|
|
|
+ tmp.Add(tmp, u256(31))
|
|
|
+ tmp.Div(tmp, u256(32))
|
|
|
+ return tmp
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
|
|
|
+ var (
|
|
|
+ gas = new(big.Int)
|
|
|
+ newMemSize *big.Int = new(big.Int)
|
|
|
+ )
|
|
|
+ baseCheck(op, stack, gas)
|
|
|
|
|
|
- var newMemSize *big.Int = ethutil.Big0
|
|
|
- var additionalGas *big.Int = new(big.Int)
|
|
|
// Stack Check, memory resize & gas phase
|
|
|
switch op {
|
|
|
- // Stack checks only
|
|
|
- case ISZERO, CALLDATALOAD, POP, JUMP, NOT, EXTCODESIZE, BLOCKHASH: // 1
|
|
|
- stack.require(1)
|
|
|
- case JUMPI, ADD, SUB, DIV, MUL, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
|
|
|
- stack.require(2)
|
|
|
- case ADDMOD, MULMOD: // 3
|
|
|
- stack.require(3)
|
|
|
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
|
|
n := int(op - SWAP1 + 2)
|
|
|
stack.require(n)
|
|
|
@@ -800,112 +870,83 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
|
|
n := int(op - LOG0)
|
|
|
stack.require(n + 2)
|
|
|
|
|
|
- gas.Set(GasLog)
|
|
|
- addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog))
|
|
|
-
|
|
|
mSize, mStart := stack.Peekn()
|
|
|
- addStepGasUsage(mSize)
|
|
|
+
|
|
|
+ gas.Add(gas, GasLogBase)
|
|
|
+ gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
|
|
|
+ gas.Add(gas, new(big.Int).Mul(mSize, GasLogData))
|
|
|
|
|
|
newMemSize = calcMemSize(mStart, mSize)
|
|
|
case EXP:
|
|
|
- stack.require(2)
|
|
|
-
|
|
|
- gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1)))
|
|
|
- // Gas only
|
|
|
- case STOP:
|
|
|
- gas.Set(ethutil.Big0)
|
|
|
- case SUICIDE:
|
|
|
- stack.require(1)
|
|
|
-
|
|
|
- gas.Set(ethutil.Big0)
|
|
|
- case SLOAD:
|
|
|
- stack.require(1)
|
|
|
-
|
|
|
- gas.Set(GasSLoad)
|
|
|
- // Memory resize & Gas
|
|
|
+ gas.Add(gas, big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes())+1)))
|
|
|
case SSTORE:
|
|
|
stack.require(2)
|
|
|
|
|
|
- var mult *big.Int
|
|
|
+ var g *big.Int
|
|
|
y, x := stack.Peekn()
|
|
|
val := statedb.GetState(context.Address(), x.Bytes())
|
|
|
if len(val) == 0 && len(y.Bytes()) > 0 {
|
|
|
// 0 => non 0
|
|
|
- mult = ethutil.Big3
|
|
|
+ g = GasStorageAdd
|
|
|
} else if len(val) > 0 && len(y.Bytes()) == 0 {
|
|
|
- statedb.Refund(self.env.Origin(), GasSStoreRefund)
|
|
|
+ statedb.Refund(self.env.Origin(), RefundStorage)
|
|
|
|
|
|
- mult = ethutil.Big0
|
|
|
+ g = GasStorageMod
|
|
|
} else {
|
|
|
// non 0 => non 0 (or 0 => 0)
|
|
|
- mult = ethutil.Big1
|
|
|
+ g = GasStorageMod
|
|
|
}
|
|
|
- gas.Set(new(big.Int).Mul(mult, GasSStore))
|
|
|
- case BALANCE:
|
|
|
- stack.require(1)
|
|
|
- gas.Set(GasBalance)
|
|
|
- case MSTORE:
|
|
|
- stack.require(2)
|
|
|
+ gas.Set(g)
|
|
|
newMemSize = calcMemSize(stack.Peek(), u256(32))
|
|
|
case MLOAD:
|
|
|
- stack.require(1)
|
|
|
-
|
|
|
newMemSize = calcMemSize(stack.Peek(), u256(32))
|
|
|
case MSTORE8:
|
|
|
- stack.require(2)
|
|
|
newMemSize = calcMemSize(stack.Peek(), u256(1))
|
|
|
case RETURN:
|
|
|
- stack.require(2)
|
|
|
-
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
|
|
|
case SHA3:
|
|
|
- stack.require(2)
|
|
|
- gas.Set(GasSha)
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
|
|
|
- additionalGas.Set(stack.data[stack.Len()-2])
|
|
|
- case CALLDATACOPY:
|
|
|
- stack.require(3)
|
|
|
|
|
|
+ words := toWordSize(stack.data[stack.Len()-2])
|
|
|
+ gas.Add(gas, words.Mul(words, GasSha3Word))
|
|
|
+ case CALLDATACOPY:
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
|
|
|
- additionalGas.Set(stack.data[stack.Len()-3])
|
|
|
- case CODECOPY:
|
|
|
- stack.require(3)
|
|
|
|
|
|
+ words := toWordSize(stack.data[stack.Len()-3])
|
|
|
+ gas.Add(gas, words.Mul(words, GasCopyWord))
|
|
|
+ case CODECOPY:
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
|
|
|
- additionalGas.Set(stack.data[stack.Len()-3])
|
|
|
- case EXTCODECOPY:
|
|
|
- stack.require(4)
|
|
|
|
|
|
+ words := toWordSize(stack.data[stack.Len()-3])
|
|
|
+ gas.Add(gas, words.Mul(words, GasCopyWord))
|
|
|
+ case EXTCODECOPY:
|
|
|
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
|
|
|
- additionalGas.Set(stack.data[stack.Len()-4])
|
|
|
+
|
|
|
+ words := toWordSize(stack.data[stack.Len()-4])
|
|
|
+ gas.Add(gas, words.Mul(words, GasCopyWord))
|
|
|
+ case CREATE:
|
|
|
+ size := new(big.Int).Set(stack.data[stack.Len()-2])
|
|
|
+ gas.Add(gas, size.Mul(size, GasCreateByte))
|
|
|
case CALL, CALLCODE:
|
|
|
- stack.require(7)
|
|
|
- gas.Set(GasCall)
|
|
|
- addStepGasUsage(stack.data[stack.Len()-1])
|
|
|
+ gas.Add(gas, stack.data[stack.Len()-1])
|
|
|
+
|
|
|
+ if op == CALL {
|
|
|
+ if self.env.State().GetStateObject(stack.data[stack.Len()-2].Bytes()) == nil {
|
|
|
+ gas.Add(gas, GasCallNewAccount)
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(stack.data[stack.Len()].Bytes()) > 0 {
|
|
|
+ gas.Add(gas, GasCallValueTransfer)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
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 = ethutil.BigMax(x, y)
|
|
|
- case CREATE:
|
|
|
- stack.require(3)
|
|
|
- gas.Set(GasCreate)
|
|
|
-
|
|
|
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
|
|
|
}
|
|
|
|
|
|
- switch op {
|
|
|
- case CALLDATACOPY, CODECOPY, EXTCODECOPY:
|
|
|
- additionalGas.Add(additionalGas, u256(31))
|
|
|
- additionalGas.Div(additionalGas, u256(32))
|
|
|
- addStepGasUsage(additionalGas)
|
|
|
- case SHA3:
|
|
|
- additionalGas.Add(additionalGas, u256(31))
|
|
|
- additionalGas.Div(additionalGas, u256(32))
|
|
|
- additionalGas.Mul(additionalGas, GasSha3Byte)
|
|
|
- addStepGasUsage(additionalGas)
|
|
|
- }
|
|
|
-
|
|
|
if newMemSize.Cmp(ethutil.Big0) > 0 {
|
|
|
newMemSize.Add(newMemSize, u256(31))
|
|
|
newMemSize.Div(newMemSize, u256(32))
|
|
|
@@ -913,10 +954,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
|
|
|
|
|
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
|
|
|
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
|
|
|
- memGasUsage.Mul(GasMemory, memGasUsage)
|
|
|
+ memGasUsage.Mul(GasMemWord, memGasUsage)
|
|
|
memGasUsage.Div(memGasUsage, u256(32))
|
|
|
|
|
|
- addStepGasUsage(memGasUsage)
|
|
|
+ gas.Add(gas, memGasUsage)
|
|
|
}
|
|
|
|
|
|
}
|