diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go index fe26853753a12a32f9d77df2425ca18a86608586..d343635641f7af9c79d8bb878c386520e687a140 100644 --- a/internal/ethapi/tracer.go +++ b/internal/ethapi/tracer.go @@ -23,6 +23,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/vm" "github.com/robertkrimen/otto" ) @@ -164,20 +165,53 @@ func (dw *dbWrapper) toValue(vm *otto.Otto) otto.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 // Javascript function for each VM execution step. type JavascriptTracer struct { - vm *otto.Otto // Javascript VM instance - traceobj *otto.Object // User-supplied object to call - log map[string]interface{} // (Reusable) map for the `log` arg to `step` - logvalue otto.Value // JS view of `log` - memory *memoryWrapper // Wrapper around the VM memory - memvalue otto.Value // JS view of `memory` - stack *stackWrapper // Wrapper around the VM stack - stackvalue otto.Value // JS view of `stack` - db *dbWrapper // Wrapper around the VM environment - dbvalue otto.Value // JS view of `db` - err error // Error, if one has occurred + vm *otto.Otto // Javascript VM instance + traceobj *otto.Object // User-supplied object to call + log map[string]interface{} // (Reusable) map for the `log` arg to `step` + logvalue otto.Value // JS view of `log` + memory *memoryWrapper // Wrapper around the VM memory + memvalue otto.Value // JS view of `memory` + stack *stackWrapper // Wrapper around the VM stack + stackvalue otto.Value // JS view of `stack` + db *dbWrapper // Wrapper around the VM environment + dbvalue otto.Value // JS view of `db` + 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. @@ -189,6 +223,7 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) { // Set up builtins for this environment vm.Set("big", &fakeBig{}) + vm.Set("toHex", hexutil.Encode) jstracer, err := vm.Object("(" + code + ")") if err != nil { @@ -220,19 +255,22 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) { mem := &memoryWrapper{} stack := &stackWrapper{} db := &dbWrapper{} + contract := &contractWrapper{} return &JavascriptTracer{ - vm: vm, - traceobj: jstracer, - log: log, - logvalue: logvalue, - memory: mem, - memvalue: mem.toValue(vm), - stack: stack, - stackvalue: stack.toValue(vm), - db: db, - dbvalue: db.toValue(vm), - err: nil, + vm: vm, + traceobj: jstracer, + log: log, + logvalue: logvalue, + memory: mem, + memvalue: mem.toValue(vm), + stack: stack, + stackvalue: stack.toValue(vm), + db: db, + dbvalue: db.toValue(vm), + contract: contract, + contractvalue: contract.toValue(vm), + err: nil, }, nil } @@ -283,6 +321,7 @@ func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, jst.memory.memory = memory jst.stack.stack = stack jst.db.db = env.StateDB + jst.contract.contract = contract 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["memory"] = jst.memvalue jst.log["stack"] = jst.stackvalue + jst.log["contract"] = jst.contractvalue jst.log["depth"] = depth jst.log["account"] = contract.Address() jst.log["err"] = err