internal/ethapi: Add support for fetching information about the current call in JS traces
This commit is contained in:
parent
cc13d576f0
commit
49f1e84253
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user