From b0190189a386d13eb2e8bbdb6d64d9ef8c0e572a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 16 Nov 2017 18:53:18 +0200 Subject: core/vm, internal/ethapi: tracer no full storage, nicer json output (#15499) * core/vm, internal/ethapi: tracer no full storage, nicer json output * core/vm, internal/ethapi: omit disabled trace fields --- internal/ethapi/api.go | 57 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'internal') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 59a29d722..cf15d1c71 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -710,45 +710,52 @@ type ExecutionResult struct { // StructLogRes stores a structured log emitted by the EVM while replaying a // transaction in debug mode type StructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth int `json:"depth"` - Error error `json:"error"` - Stack []string `json:"stack"` - Memory []string `json:"memory"` - Storage map[string]string `json:"storage"` + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error error `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` } // formatLogs formats EVM returned structured logs for json output -func FormatLogs(structLogs []vm.StructLog) []StructLogRes { - formattedStructLogs := make([]StructLogRes, len(structLogs)) - for index, trace := range structLogs { - formattedStructLogs[index] = StructLogRes{ +func FormatLogs(logs []vm.StructLog) []StructLogRes { + formatted := make([]StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = StructLogRes{ Pc: trace.Pc, Op: trace.Op.String(), Gas: trace.Gas, GasCost: trace.GasCost, Depth: trace.Depth, Error: trace.Err, - Stack: make([]string, len(trace.Stack)), - Storage: make(map[string]string), } - - for i, stackValue := range trace.Stack { - formattedStructLogs[index].Stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + } + formatted[index].Stack = &stack } - - for i := 0; i+32 <= len(trace.Memory); i += 32 { - formattedStructLogs[index].Memory = append(formattedStructLogs[index].Memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory } - - for i, storageValue := range trace.Storage { - formattedStructLogs[index].Storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage } } - return formattedStructLogs + return formatted } // rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are -- cgit v1.2.3 From c7b0abf86bf3039a87b5b5ae88635326a762cf31 Mon Sep 17 00:00:00 2001 From: tsarpaul Date: Fri, 17 Nov 2017 15:07:57 +0200 Subject: Added output to clarify gas calculation in txpool.inspect --- internal/ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'internal') diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cf15d1c71..025f42617 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -151,9 +151,9 @@ func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string { // Define a formatter to flatten a transaction into a string var format = func(tx *types.Transaction) string { if to := tx.To(); to != nil { - return fmt.Sprintf("%s: %v wei + %v × %v gas", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice()) + return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice()) } - return fmt.Sprintf("contract creation: %v wei + %v × %v gas", tx.Value(), tx.Gas(), tx.GasPrice()) + return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value(), tx.Gas(), tx.GasPrice()) } // Flatten the pending transactions for account, txs := range pending { -- cgit v1.2.3 From f5091e5711fc18205ed3a7c2d9d6a7fe7f0262f2 Mon Sep 17 00:00:00 2001 From: Pulyak Viktor Date: Sat, 18 Nov 2017 04:56:03 +0300 Subject: internal/ethapi: fix js tracer to properly decode addresses (#15297) * Add method getBalanceFromJs for work with address as bytes * expect []byte instead of common.Address in ethapi tracer --- internal/ethapi/tracer.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'internal') diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go index 051626527..fc742e6c4 100644 --- a/internal/ethapi/tracer.go +++ b/internal/ethapi/tracer.go @@ -130,28 +130,28 @@ type dbWrapper struct { } // getBalance retrieves an account's balance -func (dw *dbWrapper) getBalance(addr common.Address) *big.Int { - return dw.db.GetBalance(addr) +func (dw *dbWrapper) getBalance(addr []byte) *big.Int { + return dw.db.GetBalance(common.BytesToAddress(addr)) } // getNonce retrieves an account's nonce -func (dw *dbWrapper) getNonce(addr common.Address) uint64 { - return dw.db.GetNonce(addr) +func (dw *dbWrapper) getNonce(addr []byte) uint64 { + return dw.db.GetNonce(common.BytesToAddress(addr)) } // getCode retrieves an account's code -func (dw *dbWrapper) getCode(addr common.Address) []byte { - return dw.db.GetCode(addr) +func (dw *dbWrapper) getCode(addr []byte) []byte { + return dw.db.GetCode(common.BytesToAddress(addr)) } // getState retrieves an account's state data for the given hash -func (dw *dbWrapper) getState(addr common.Address, hash common.Hash) common.Hash { - return dw.db.GetState(addr, hash) +func (dw *dbWrapper) getState(addr []byte, hash common.Hash) common.Hash { + return dw.db.GetState(common.BytesToAddress(addr), hash) } // exists returns true iff the account exists -func (dw *dbWrapper) exists(addr common.Address) bool { - return dw.db.Exist(addr) +func (dw *dbWrapper) exists(addr []byte) bool { + return dw.db.Exist(common.BytesToAddress(addr)) } // toValue returns an otto.Value for the dbWrapper -- cgit v1.2.3 From 72ed186f46a31ec29bb255bfcadfbfd036cce791 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Mon, 20 Nov 2017 16:18:50 +0100 Subject: eth, internal: Implement getModifiedAccountsBy(Hash|Number) using trie diffs (#15512) * eth, internal: Implement using trie diffs * eth, internal: Changes in response to review * eth: More fixes to getModifiedAccountsBy* * eth: minor polishes on error capitalization --- internal/web3ext/web3ext.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'internal') diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1ae6e2d73..ef0d2b4e6 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -354,6 +354,18 @@ web3._extend({ call: 'debug_storageRangeAt', params: 5, }), + new web3._extend.Method({ + name: 'getModifiedAccountsByNumber', + call: 'debug_getModifiedAccountsByNumber', + params: 2, + inputFormatter: [null, null], + }), + new web3._extend.Method({ + name: 'getModifiedAccountsByHash', + call: 'debug_getModifiedAccountsByHash', + params: 2, + inputFormatter:[null, null], + }), ], properties: [] }); -- cgit v1.2.3 From 989fb4472a25a9b92cba95150c97719761c7ed1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 24 Nov 2017 13:50:14 +0200 Subject: internal/ethapi: avoid recreating JavaScript tracer wrappers --- internal/ethapi/tracer.go | 85 +++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 43 deletions(-) (limited to 'internal') diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go index fc742e6c4..71cafc6e9 100644 --- a/internal/ethapi/tracer.go +++ b/internal/ethapi/tracer.go @@ -200,19 +200,18 @@ func (c *contractWrapper) toValue(vm *otto.Otto) otto.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` - contract *contractWrapper // Wrapper around the contract object - contractvalue otto.Value // JS view of `contract` - err error // Error, if one has occurred + vm *otto.Otto // Javascript VM instance + traceobj *otto.Object // User-supplied object to call + op *opCodeWrapper // Wrapper around the VM opcode + 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 + stack *stackWrapper // Wrapper around the VM stack + db *dbWrapper // Wrapper around the VM environment + dbvalue otto.Value // JS view of `db` + contract *contractWrapper // Wrapper around the contract object + err error // Error, if one has occurred + result interface{} // Final result to return to the user } // NewJavascriptTracer instantiates a new JavascriptTracer instance. @@ -230,7 +229,6 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) { if err != nil { return nil, err } - // Check the required functions exist step, err := jstracer.Get("step") if err != nil { @@ -247,31 +245,34 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) { if !result.IsFunction() { return nil, fmt.Errorf("Trace object must expose a function result()") } - // Create the persistent log object - log := make(map[string]interface{}) + var ( + op = new(opCodeWrapper) + mem = new(memoryWrapper) + stack = new(stackWrapper) + db = new(dbWrapper) + contract = new(contractWrapper) + ) + log := map[string]interface{}{ + "op": op.toValue(vm), + "memory": mem.toValue(vm), + "stack": stack.toValue(vm), + "contract": contract.toValue(vm), + } logvalue, _ := vm.ToValue(log) - // Create persistent wrappers for memory and stack - 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), - contract: contract, - contractvalue: contract.toValue(vm), - err: nil, + vm: vm, + traceobj: jstracer, + op: op, + log: log, + logvalue: logvalue, + memory: mem, + stack: stack, + db: db, + dbvalue: db.toValue(vm), + contract: contract, + err: nil, }, nil } @@ -319,24 +320,22 @@ func wrapError(context string, err error) error { // CaptureState implements the Tracer interface to trace a single step of VM execution func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { if jst.err == nil { + jst.op.op = op jst.memory.memory = memory jst.stack.stack = stack jst.db.db = env.StateDB jst.contract.contract = contract - ocw := &opCodeWrapper{op} - jst.log["pc"] = pc - jst.log["op"] = ocw.toValue(jst.vm) jst.log["gas"] = gas - jst.log["gasPrice"] = cost - jst.log["memory"] = jst.memvalue - jst.log["stack"] = jst.stackvalue - jst.log["contract"] = jst.contractvalue + jst.log["cost"] = cost jst.log["depth"] = depth jst.log["account"] = contract.Address() - jst.log["err"] = err + delete(jst.log, "error") + if err != nil { + jst.log["error"] = err + } _, err := jst.callSafely("step", jst.logvalue, jst.dbvalue) if err != nil { jst.err = wrapError("step", err) -- cgit v1.2.3