|
|
@@ -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) {
|