internal/ethapi: Add support for fetching information about the current call in JS traces

This commit is contained in:
Nick Johnson 2017-04-11 11:37:23 +01:00
parent cc13d576f0
commit 49f1e84253
1 changed files with 62 additions and 22 deletions

View File

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
) )
@ -164,20 +165,53 @@ func (dw *dbWrapper) toValue(vm *otto.Otto) otto.Value {
return value return value
} }
// contractWrapper provides a JS wrapper around vm.Contract
type contractWrapper struct {
contract *vm.Contract
}
func (c *contractWrapper) caller() common.Address {
return c.contract.Caller()
}
func (c *contractWrapper) address() common.Address {
return c.contract.Address()
}
func (c *contractWrapper) value() *big.Int {
return c.contract.Value()
}
func (c *contractWrapper) calldata() []byte {
return c.contract.Input
}
func (c *contractWrapper) toValue(vm *otto.Otto) otto.Value {
value, _ := vm.ToValue(c)
obj := value.Object()
obj.Set("caller", c.caller)
obj.Set("address", c.address)
obj.Set("value", c.value)
obj.Set("calldata", c.calldata)
return value
}
// JavascriptTracer provides an implementation of Tracer that evaluates a // JavascriptTracer provides an implementation of Tracer that evaluates a
// Javascript function for each VM execution step. // Javascript function for each VM execution step.
type JavascriptTracer struct { type JavascriptTracer struct {
vm *otto.Otto // Javascript VM instance vm *otto.Otto // Javascript VM instance
traceobj *otto.Object // User-supplied object to call traceobj *otto.Object // User-supplied object to call
log map[string]interface{} // (Reusable) map for the `log` arg to `step` log map[string]interface{} // (Reusable) map for the `log` arg to `step`
logvalue otto.Value // JS view of `log` logvalue otto.Value // JS view of `log`
memory *memoryWrapper // Wrapper around the VM memory memory *memoryWrapper // Wrapper around the VM memory
memvalue otto.Value // JS view of `memory` memvalue otto.Value // JS view of `memory`
stack *stackWrapper // Wrapper around the VM stack stack *stackWrapper // Wrapper around the VM stack
stackvalue otto.Value // JS view of `stack` stackvalue otto.Value // JS view of `stack`
db *dbWrapper // Wrapper around the VM environment db *dbWrapper // Wrapper around the VM environment
dbvalue otto.Value // JS view of `db` dbvalue otto.Value // JS view of `db`
err error // Error, if one has occurred contract *contractWrapper // Wrapper around the contract object
contractvalue otto.Value // JS view of `contract`
err error // Error, if one has occurred
} }
// NewJavascriptTracer instantiates a new JavascriptTracer instance. // NewJavascriptTracer instantiates a new JavascriptTracer instance.
@ -189,6 +223,7 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) {
// Set up builtins for this environment // Set up builtins for this environment
vm.Set("big", &fakeBig{}) vm.Set("big", &fakeBig{})
vm.Set("toHex", hexutil.Encode)
jstracer, err := vm.Object("(" + code + ")") jstracer, err := vm.Object("(" + code + ")")
if err != nil { if err != nil {
@ -220,19 +255,22 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) {
mem := &memoryWrapper{} mem := &memoryWrapper{}
stack := &stackWrapper{} stack := &stackWrapper{}
db := &dbWrapper{} db := &dbWrapper{}
contract := &contractWrapper{}
return &JavascriptTracer{ return &JavascriptTracer{
vm: vm, vm: vm,
traceobj: jstracer, traceobj: jstracer,
log: log, log: log,
logvalue: logvalue, logvalue: logvalue,
memory: mem, memory: mem,
memvalue: mem.toValue(vm), memvalue: mem.toValue(vm),
stack: stack, stack: stack,
stackvalue: stack.toValue(vm), stackvalue: stack.toValue(vm),
db: db, db: db,
dbvalue: db.toValue(vm), dbvalue: db.toValue(vm),
err: nil, contract: contract,
contractvalue: contract.toValue(vm),
err: nil,
}, nil }, nil
} }
@ -283,6 +321,7 @@ func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
jst.memory.memory = memory jst.memory.memory = memory
jst.stack.stack = stack jst.stack.stack = stack
jst.db.db = env.StateDB jst.db.db = env.StateDB
jst.contract.contract = contract
ocw := &opCodeWrapper{op} ocw := &opCodeWrapper{op}
@ -292,6 +331,7 @@ func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
jst.log["gasPrice"] = cost jst.log["gasPrice"] = cost
jst.log["memory"] = jst.memvalue jst.log["memory"] = jst.memvalue
jst.log["stack"] = jst.stackvalue jst.log["stack"] = jst.stackvalue
jst.log["contract"] = jst.contractvalue
jst.log["depth"] = depth jst.log["depth"] = depth
jst.log["account"] = contract.Address() jst.log["account"] = contract.Address()
jst.log["err"] = err jst.log["err"] = err