|
|
@ -43,6 +43,31 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) { |
|
|
|
code = context.Code |
|
|
|
code = context.Code |
|
|
|
value = context.value |
|
|
|
value = context.value |
|
|
|
price = context.Price |
|
|
|
price = context.Price |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
op OpCode // current opcode
|
|
|
|
|
|
|
|
codehash = crypto.Sha3Hash(code) // codehash is used when doing jump dest caching
|
|
|
|
|
|
|
|
mem = NewMemory() // bound memory
|
|
|
|
|
|
|
|
stack = newstack() // local stack
|
|
|
|
|
|
|
|
statedb = self.env.State() // current state
|
|
|
|
|
|
|
|
// For optimisation reason we're using uint64 as the program counter.
|
|
|
|
|
|
|
|
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Pratically much less so feasible.
|
|
|
|
|
|
|
|
pc = uint64(0) // program counter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// jump evaluates and checks whether the given jump destination is a valid one
|
|
|
|
|
|
|
|
// if valid move the `pc` otherwise return an error.
|
|
|
|
|
|
|
|
jump = func(from uint64, to *big.Int) error { |
|
|
|
|
|
|
|
if !context.jumpdests.has(codehash, code, to) { |
|
|
|
|
|
|
|
nop := context.GetOp(to.Uint64()) |
|
|
|
|
|
|
|
return fmt.Errorf("invalid jump destination (%v) %v", nop, to) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pc = to.Uint64() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newMemSize *big.Int |
|
|
|
|
|
|
|
cost *big.Int |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
|
|
|
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
|
|
@ -52,6 +77,7 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
self.log(pc, op, context.Gas, cost, mem, stack, context, err) |
|
|
|
|
|
|
|
|
|
|
|
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
|
|
|
|
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
|
|
|
|
context.UseGas(context.Gas) |
|
|
|
context.UseGas(context.Gas) |
|
|
@ -71,30 +97,6 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) { |
|
|
|
return context.Return(nil), nil |
|
|
|
return context.Return(nil), nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
op OpCode // current opcode
|
|
|
|
|
|
|
|
codehash = crypto.Sha3Hash(code) // codehash is used when doing jump dest caching
|
|
|
|
|
|
|
|
mem = NewMemory() // bound memory
|
|
|
|
|
|
|
|
stack = newstack() // local stack
|
|
|
|
|
|
|
|
statedb = self.env.State() // current state
|
|
|
|
|
|
|
|
// For optimisation reason we're using uint64 as the program counter.
|
|
|
|
|
|
|
|
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Pratically much less so feasible.
|
|
|
|
|
|
|
|
pc = uint64(0) // program counter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// jump evaluates and checks whether the given jump destination is a valid one
|
|
|
|
|
|
|
|
// if valid move the `pc` otherwise return an error.
|
|
|
|
|
|
|
|
jump = func(from uint64, to *big.Int) error { |
|
|
|
|
|
|
|
if !context.jumpdests.has(codehash, code, to) { |
|
|
|
|
|
|
|
nop := context.GetOp(to.Uint64()) |
|
|
|
|
|
|
|
return fmt.Errorf("invalid jump destination (%v) %v", nop, to) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pc = to.Uint64() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for { |
|
|
|
for { |
|
|
|
// The base for all big integer arithmetic
|
|
|
|
// The base for all big integer arithmetic
|
|
|
|
base := new(big.Int) |
|
|
|
base := new(big.Int) |
|
|
@ -103,24 +105,23 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) { |
|
|
|
op = context.GetOp(pc) |
|
|
|
op = context.GetOp(pc) |
|
|
|
|
|
|
|
|
|
|
|
// calculate the new memory size and gas price for the current executing opcode
|
|
|
|
// calculate the new memory size and gas price for the current executing opcode
|
|
|
|
newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack) |
|
|
|
newMemSize, cost, err = self.calculateGasAndSize(context, caller, op, statedb, mem, stack) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
self.log(pc, op, context.Gas, gas, mem, stack, context) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use the calculated gas. When insufficient gas is present, use all gas and return an
|
|
|
|
// Use the calculated gas. When insufficient gas is present, use all gas and return an
|
|
|
|
// Out Of Gas error
|
|
|
|
// Out Of Gas error
|
|
|
|
if !context.UseGas(gas) { |
|
|
|
if !context.UseGas(cost) { |
|
|
|
tmp := new(big.Int).Set(context.Gas) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context.UseGas(context.Gas) |
|
|
|
context.UseGas(context.Gas) |
|
|
|
|
|
|
|
|
|
|
|
return context.Return(nil), OOG(gas, tmp) |
|
|
|
return context.Return(nil), OutOfGasError{} |
|
|
|
} |
|
|
|
} |
|
|
|
// Resize the memory calculated previously
|
|
|
|
// Resize the memory calculated previously
|
|
|
|
mem.Resize(newMemSize.Uint64()) |
|
|
|
mem.Resize(newMemSize.Uint64()) |
|
|
|
|
|
|
|
// Add a log message
|
|
|
|
|
|
|
|
self.log(pc, op, context.Gas, cost, mem, stack, context, nil) |
|
|
|
|
|
|
|
|
|
|
|
switch op { |
|
|
|
switch op { |
|
|
|
case ADD: |
|
|
|
case ADD: |
|
|
@ -783,15 +784,13 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, input []byte, context *Con |
|
|
|
|
|
|
|
|
|
|
|
return context.Return(ret), nil |
|
|
|
return context.Return(ret), nil |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
tmp := new(big.Int).Set(context.Gas) |
|
|
|
return nil, OutOfGasError{} |
|
|
|
|
|
|
|
|
|
|
|
return nil, OOG(gas, tmp) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// log emits a log event to the environment for each opcode encountered. This is not to be confused with the
|
|
|
|
// log emits a log event to the environment for each opcode encountered. This is not to be confused with the
|
|
|
|
// LOG* opcode.
|
|
|
|
// LOG* opcode.
|
|
|
|
func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, context *Context) { |
|
|
|
func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, context *Context, err error) { |
|
|
|
if Debug { |
|
|
|
if Debug { |
|
|
|
mem := make([]byte, len(memory.Data())) |
|
|
|
mem := make([]byte, len(memory.Data())) |
|
|
|
copy(mem, memory.Data()) |
|
|
|
copy(mem, memory.Data()) |
|
|
@ -804,7 +803,7 @@ func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, st |
|
|
|
storage[common.BytesToHash(k)] = v |
|
|
|
storage[common.BytesToHash(k)] = v |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage}) |
|
|
|
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, err}) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|