|
|
|
@ -49,15 +49,11 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * |
|
|
|
|
}) |
|
|
|
|
closure := NewClosure(msg, caller, me, code, gas, price) |
|
|
|
|
|
|
|
|
|
if p := Precompiled[string(me.Address())]; p != nil { |
|
|
|
|
return self.RunPrecompiled(p, callData, closure) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if self.Recoverable { |
|
|
|
|
// Recover from any require exception
|
|
|
|
|
defer func() { |
|
|
|
|
if r := recover(); r != nil { |
|
|
|
|
self.Endl() |
|
|
|
|
self.Printf(" %v", r).Endl() |
|
|
|
|
|
|
|
|
|
closure.UseGas(closure.Gas) |
|
|
|
|
|
|
|
|
@ -69,6 +65,10 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if p := Precompiled[string(me.Address())]; p != nil { |
|
|
|
|
return self.RunPrecompiled(p, callData, closure) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
op OpCode |
|
|
|
|
|
|
|
|
@ -79,11 +79,6 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * |
|
|
|
|
step = 0 |
|
|
|
|
prevStep = 0 |
|
|
|
|
statedb = self.env.State() |
|
|
|
|
require = func(m int) { |
|
|
|
|
if stack.Len() < m { |
|
|
|
|
panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
jump = func(from uint64, to *big.Int) { |
|
|
|
|
p := to.Uint64() |
|
|
|
@ -124,160 +119,11 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * |
|
|
|
|
// Get the memory location of pc
|
|
|
|
|
op = closure.GetOp(pc) |
|
|
|
|
|
|
|
|
|
gas := new(big.Int) |
|
|
|
|
addStepGasUsage := func(amount *big.Int) { |
|
|
|
|
if amount.Cmp(ethutil.Big0) >= 0 { |
|
|
|
|
gas.Add(gas, amount) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addStepGasUsage(GasStep) |
|
|
|
|
|
|
|
|
|
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: // 1
|
|
|
|
|
require(1) |
|
|
|
|
case JUMPI, ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
|
|
|
|
|
require(2) |
|
|
|
|
case ADDMOD, MULMOD: // 3
|
|
|
|
|
require(3) |
|
|
|
|
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: |
|
|
|
|
n := int(op - SWAP1 + 2) |
|
|
|
|
require(n) |
|
|
|
|
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: |
|
|
|
|
n := int(op - DUP1 + 1) |
|
|
|
|
require(n) |
|
|
|
|
case LOG0, LOG1, LOG2, LOG3, LOG4: |
|
|
|
|
n := int(op - LOG0) |
|
|
|
|
require(n + 2) |
|
|
|
|
|
|
|
|
|
gas.Set(GasLog) |
|
|
|
|
addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) |
|
|
|
|
|
|
|
|
|
mSize, mStart := stack.Peekn() |
|
|
|
|
addStepGasUsage(mSize) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(mStart, mSize) |
|
|
|
|
case EXP: |
|
|
|
|
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: |
|
|
|
|
require(1) |
|
|
|
|
|
|
|
|
|
gas.Set(ethutil.Big0) |
|
|
|
|
case SLOAD: |
|
|
|
|
require(1) |
|
|
|
|
|
|
|
|
|
gas.Set(GasSLoad) |
|
|
|
|
// Memory resize & Gas
|
|
|
|
|
case SSTORE: |
|
|
|
|
require(2) |
|
|
|
|
|
|
|
|
|
var mult *big.Int |
|
|
|
|
y, x := stack.Peekn() |
|
|
|
|
val := statedb.GetState(closure.Address(), x.Bytes()) |
|
|
|
|
if len(val) == 0 && len(y.Bytes()) > 0 { |
|
|
|
|
// 0 => non 0
|
|
|
|
|
mult = ethutil.Big3 |
|
|
|
|
} else if len(val) > 0 && len(y.Bytes()) == 0 { |
|
|
|
|
statedb.Refund(caller.Address(), GasSStoreRefund) |
|
|
|
|
|
|
|
|
|
mult = ethutil.Big0 |
|
|
|
|
} else { |
|
|
|
|
// non 0 => non 0 (or 0 => 0)
|
|
|
|
|
mult = ethutil.Big1 |
|
|
|
|
} |
|
|
|
|
gas.Set(new(big.Int).Mul(mult, GasSStore)) |
|
|
|
|
case BALANCE: |
|
|
|
|
require(1) |
|
|
|
|
gas.Set(GasBalance) |
|
|
|
|
case MSTORE: |
|
|
|
|
require(2) |
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), u256(32)) |
|
|
|
|
case MLOAD: |
|
|
|
|
require(1) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), u256(32)) |
|
|
|
|
case MSTORE8: |
|
|
|
|
require(2) |
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), u256(1)) |
|
|
|
|
case RETURN: |
|
|
|
|
require(2) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) |
|
|
|
|
case SHA3: |
|
|
|
|
require(2) |
|
|
|
|
gas.Set(GasSha) |
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-2]) |
|
|
|
|
case CALLDATACOPY: |
|
|
|
|
require(2) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-3]) |
|
|
|
|
case CODECOPY: |
|
|
|
|
require(3) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-3]) |
|
|
|
|
case EXTCODECOPY: |
|
|
|
|
require(4) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-4]) |
|
|
|
|
case CALL, CALLCODE: |
|
|
|
|
require(7) |
|
|
|
|
gas.Set(GasCall) |
|
|
|
|
addStepGasUsage(stack.data[stack.Len()-1]) |
|
|
|
|
|
|
|
|
|
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: |
|
|
|
|
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)) |
|
|
|
|
newMemSize.Mul(newMemSize, u256(32)) |
|
|
|
|
|
|
|
|
|
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { |
|
|
|
|
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) |
|
|
|
|
memGasUsage.Mul(GasMemory, memGasUsage) |
|
|
|
|
memGasUsage.Div(memGasUsage, u256(32)) |
|
|
|
|
|
|
|
|
|
addStepGasUsage(memGasUsage) |
|
|
|
|
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.Len()) |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
newMemSize, gas := self.calculateGasAndSize(closure, caller, op, statedb, mem, stack) |
|
|
|
|
|
|
|
|
|
self.Printf("(pc) %-3d -o- %-14s", pc, op.String()) |
|
|
|
|
self.Printf(" (m) %-4d (s) %-4d (g) %-3v (%v)", mem.Len(), stack.Len(), gas, closure.Gas) |
|
|
|
|
self.Printf("(g) %-3v (%v)", gas, closure.Gas) |
|
|
|
|
|
|
|
|
|
if !closure.UseGas(gas) { |
|
|
|
|
self.Endl() |
|
|
|
@ -939,6 +785,161 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (self *DebugVm) calculateGasAndSize(closure *Closure, caller ClosureRef, 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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addStepGasUsage(GasStep) |
|
|
|
|
|
|
|
|
|
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: // 1
|
|
|
|
|
stack.require(1) |
|
|
|
|
case JUMPI, ADD, SUB, DIV, 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) |
|
|
|
|
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: |
|
|
|
|
n := int(op - DUP1 + 1) |
|
|
|
|
stack.require(n) |
|
|
|
|
case LOG0, LOG1, LOG2, LOG3, LOG4: |
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
case SSTORE: |
|
|
|
|
stack.require(2) |
|
|
|
|
|
|
|
|
|
var mult *big.Int |
|
|
|
|
y, x := stack.Peekn() |
|
|
|
|
val := statedb.GetState(closure.Address(), x.Bytes()) |
|
|
|
|
if len(val) == 0 && len(y.Bytes()) > 0 { |
|
|
|
|
// 0 => non 0
|
|
|
|
|
mult = ethutil.Big3 |
|
|
|
|
} else if len(val) > 0 && len(y.Bytes()) == 0 { |
|
|
|
|
statedb.Refund(caller.Address(), GasSStoreRefund) |
|
|
|
|
|
|
|
|
|
mult = ethutil.Big0 |
|
|
|
|
} else { |
|
|
|
|
// non 0 => non 0 (or 0 => 0)
|
|
|
|
|
mult = ethutil.Big1 |
|
|
|
|
} |
|
|
|
|
gas.Set(new(big.Int).Mul(mult, GasSStore)) |
|
|
|
|
case BALANCE: |
|
|
|
|
stack.require(1) |
|
|
|
|
gas.Set(GasBalance) |
|
|
|
|
case MSTORE: |
|
|
|
|
stack.require(2) |
|
|
|
|
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(2) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-3]) |
|
|
|
|
case CODECOPY: |
|
|
|
|
stack.require(3) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-3]) |
|
|
|
|
case EXTCODECOPY: |
|
|
|
|
stack.require(4) |
|
|
|
|
|
|
|
|
|
newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) |
|
|
|
|
additionalGas.Set(stack.data[stack.Len()-4]) |
|
|
|
|
case CALL, CALLCODE: |
|
|
|
|
stack.require(7) |
|
|
|
|
gas.Set(GasCall) |
|
|
|
|
addStepGasUsage(stack.data[stack.Len()-1]) |
|
|
|
|
|
|
|
|
|
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)) |
|
|
|
|
newMemSize.Mul(newMemSize, u256(32)) |
|
|
|
|
|
|
|
|
|
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { |
|
|
|
|
memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) |
|
|
|
|
memGasUsage.Mul(GasMemory, memGasUsage) |
|
|
|
|
memGasUsage.Div(memGasUsage, u256(32)) |
|
|
|
|
|
|
|
|
|
addStepGasUsage(memGasUsage) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return newMemSize, gas |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (self *DebugVm) RunPrecompiled(p *PrecompiledAccount, callData []byte, closure *Closure) (ret []byte, err error) { |
|
|
|
|
gas := p.Gas(len(callData)) |
|
|
|
|
if closure.UseGas(gas) { |
|
|
|
|