mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
feat: backport flatCallTracer (#895)
This commit is contained in:
parent
9de4980851
commit
972fe8afc4
11 changed files with 527 additions and 27 deletions
|
|
@ -194,6 +194,7 @@ type StdTraceConfig struct {
|
||||||
|
|
||||||
// txTraceResult is the result of a single transaction trace.
|
// txTraceResult is the result of a single transaction trace.
|
||||||
type txTraceResult struct {
|
type txTraceResult struct {
|
||||||
|
TxHash common.Hash `json:"txHash"` // Hash of the transaction being traced
|
||||||
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
||||||
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
|
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
|
||||||
}
|
}
|
||||||
|
|
@ -280,9 +281,10 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
|
||||||
for i, tx := range task.block.Transactions() {
|
for i, tx := range task.block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
|
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: task.block.Hash(),
|
BlockNumber: task.block.NumberU64(),
|
||||||
TxIndex: i,
|
BlockHash: task.block.Hash(),
|
||||||
TxHash: tx.Hash(),
|
TxIndex: i,
|
||||||
|
TxHash: tx.Hash(),
|
||||||
}
|
}
|
||||||
|
|
||||||
l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb, api.backend.ChainConfig(), task.block.Number())
|
l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb, api.backend.ChainConfig(), task.block.Number())
|
||||||
|
|
@ -613,6 +615,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
}
|
}
|
||||||
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
|
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
|
||||||
blockHash := block.Hash()
|
blockHash := block.Hash()
|
||||||
|
blockNumber := block.NumberU64()
|
||||||
for th := 0; th < threads; th++ {
|
for th := 0; th < threads; th++ {
|
||||||
pend.Add(1)
|
pend.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -621,23 +624,33 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
for task := range jobs {
|
for task := range jobs {
|
||||||
msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
|
msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: blockHash,
|
BlockNumber: blockNumber,
|
||||||
TxIndex: task.index,
|
BlockHash: blockHash,
|
||||||
TxHash: txs[task.index].Hash(),
|
TxIndex: task.index,
|
||||||
|
TxHash: txs[task.index].Hash(),
|
||||||
}
|
}
|
||||||
|
|
||||||
l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb, api.backend.ChainConfig(), block.Number())
|
l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb, api.backend.ChainConfig(), block.Number())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// though it's not a "tracing error", we still need to put it here
|
// though it's not a "tracing error", we still need to put it here
|
||||||
results[task.index] = &txTraceResult{Error: err.Error()}
|
results[task.index] = &txTraceResult{
|
||||||
|
TxHash: txs[task.index].Hash(),
|
||||||
|
Error: err.Error(),
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, l1DataFee)
|
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
results[task.index] = &txTraceResult{Error: err.Error()}
|
results[task.index] = &txTraceResult{
|
||||||
|
TxHash: txs[task.index].Hash(),
|
||||||
|
Error: err.Error(),
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
results[task.index] = &txTraceResult{Result: res}
|
results[task.index] = &txTraceResult{
|
||||||
|
TxHash: txs[task.index].Hash(),
|
||||||
|
Result: res,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ type fourByteTracer struct {
|
||||||
|
|
||||||
// newFourByteTracer returns a native go tracer which collects
|
// newFourByteTracer returns a native go tracer which collects
|
||||||
// 4 byte-identifiers of a tx, and implements vm.EVMLogger.
|
// 4 byte-identifiers of a tx, and implements vm.EVMLogger.
|
||||||
func newFourByteTracer() tracers.Tracer {
|
func newFourByteTracer(ctx *tracers.Context) tracers.Tracer {
|
||||||
t := &fourByteTracer{
|
t := &fourByteTracer{
|
||||||
ids: make(map[string]int),
|
ids: make(map[string]int),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ type callTracer struct {
|
||||||
|
|
||||||
// newCallTracer returns a native go tracer which tracks
|
// newCallTracer returns a native go tracer which tracks
|
||||||
// call frames of a tx, and implements vm.EVMLogger.
|
// call frames of a tx, and implements vm.EVMLogger.
|
||||||
func newCallTracer() tracers.Tracer {
|
func newCallTracer(ctx *tracers.Context) tracers.Tracer {
|
||||||
// First callframe contains tx context info
|
// First callframe contains tx context info
|
||||||
// and is populated on start and end.
|
// and is populated on start and end.
|
||||||
t := &callTracer{callstack: make([]callFrame, 1)}
|
t := &callTracer{callstack: make([]callFrame, 1)}
|
||||||
|
|
|
||||||
318
eth/tracers/native/call_flat.go
Normal file
318
eth/tracers/native/call_flat.go
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
// Copyright 2022 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
|
"github.com/scroll-tech/go-ethereum/eth/tracers"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go
|
||||||
|
//go:generate go run github.com/fjl/gencodec -type flatCallResult -field-override flatCallResultMarshaling -out gen_flatcallresult_json.go
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// tracers.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false)
|
||||||
|
register("flatCallTracer", newFlatCallTracer)
|
||||||
|
}
|
||||||
|
|
||||||
|
var parityErrorMapping = map[string]string{
|
||||||
|
"contract creation code storage out of gas": "Out of gas",
|
||||||
|
"out of gas": "Out of gas",
|
||||||
|
"gas uint64 overflow": "Out of gas",
|
||||||
|
"max code size exceeded": "Out of gas",
|
||||||
|
"invalid jump destination": "Bad jump destination",
|
||||||
|
"execution reverted": "Reverted",
|
||||||
|
"return data out of bounds": "Out of bounds",
|
||||||
|
"stack limit reached 1024 (1023)": "Out of stack",
|
||||||
|
"precompiled failed": "Built-in failed",
|
||||||
|
"invalid input length": "Built-in failed",
|
||||||
|
}
|
||||||
|
|
||||||
|
var parityErrorMappingStartingWith = map[string]string{
|
||||||
|
"invalid opcode:": "Bad instruction",
|
||||||
|
"stack underflow": "Stack underflow",
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatCallFrame is a standalone callframe.
|
||||||
|
type flatCallFrame struct {
|
||||||
|
Action flatCallAction `json:"action"`
|
||||||
|
BlockHash *common.Hash `json:"blockHash"`
|
||||||
|
BlockNumber uint64 `json:"blockNumber"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Result *flatCallResult `json:"result,omitempty"`
|
||||||
|
Subtraces int `json:"subtraces"`
|
||||||
|
TraceAddress []int `json:"traceAddress"`
|
||||||
|
TransactionHash *common.Hash `json:"transactionHash"`
|
||||||
|
TransactionPosition uint64 `json:"transactionPosition"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type flatCallAction struct {
|
||||||
|
Author *common.Address `json:"author,omitempty"`
|
||||||
|
RewardType string `json:"rewardType,omitempty"`
|
||||||
|
SelfDestructed *common.Address `json:"address,omitempty"`
|
||||||
|
Balance *big.Int `json:"balance,omitempty"`
|
||||||
|
CallType string `json:"callType,omitempty"`
|
||||||
|
CreationMethod string `json:"creationMethod,omitempty"`
|
||||||
|
From *common.Address `json:"from,omitempty"`
|
||||||
|
Gas *uint64 `json:"gas,omitempty"`
|
||||||
|
Init *[]byte `json:"init,omitempty"`
|
||||||
|
Input *[]byte `json:"input,omitempty"`
|
||||||
|
RefundAddress *common.Address `json:"refundAddress,omitempty"`
|
||||||
|
To *common.Address `json:"to,omitempty"`
|
||||||
|
Value *big.Int `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type flatCallActionMarshaling struct {
|
||||||
|
Balance *hexutil.Big
|
||||||
|
Gas *hexutil.Uint64
|
||||||
|
Init *hexutil.Bytes
|
||||||
|
Input *hexutil.Bytes
|
||||||
|
Value *hexutil.Big
|
||||||
|
}
|
||||||
|
|
||||||
|
type flatCallResult struct {
|
||||||
|
Address *common.Address `json:"address,omitempty"`
|
||||||
|
Code *[]byte `json:"code,omitempty"`
|
||||||
|
GasUsed *uint64 `json:"gasUsed,omitempty"`
|
||||||
|
Output *[]byte `json:"output,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type flatCallResultMarshaling struct {
|
||||||
|
Code *hexutil.Bytes
|
||||||
|
GasUsed *hexutil.Uint64
|
||||||
|
Output *hexutil.Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatCallTracer reports call frame information of a tx in a flat format, i.e.
|
||||||
|
// as opposed to the nested format of `callTracer`.
|
||||||
|
type flatCallTracer struct {
|
||||||
|
ctx *tracers.Context
|
||||||
|
*callTracer
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFlatCallTracer returns a new flatCallTracer.
|
||||||
|
func newFlatCallTracer(ctx *tracers.Context) tracers.Tracer {
|
||||||
|
t := &callTracer{callstack: make([]callFrame, 1)}
|
||||||
|
|
||||||
|
return &flatCallTracer{callTracer: t, ctx: ctx}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||||
|
func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||||
|
t.callTracer.CaptureEnter(typ, from, to, input, gas, value)
|
||||||
|
if len(t.callTracer.callstack) > 0 && t.callTracer.callstack[len(t.callTracer.callstack)-1].Value == "" {
|
||||||
|
t.callTracer.callstack[len(t.callTracer.callstack)-1].Value = "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult returns the json-encoded nested list of call traces, and any
|
||||||
|
// error arising from the encoding or forceful termination (via `Stop`).
|
||||||
|
func (t *flatCallTracer) GetResult() (json.RawMessage, error) {
|
||||||
|
if len(t.callTracer.callstack) < 1 {
|
||||||
|
return nil, errors.New("invalid number of calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
flat, err := flatFromNested(&t.callTracer.callstack[0], []int{}, true, t.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := json.Marshal(flat)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res, t.reason
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *tracers.Context) (output []flatCallFrame, err error) {
|
||||||
|
var frame *flatCallFrame
|
||||||
|
switch vm.StringToOp(input.Type) {
|
||||||
|
case vm.CREATE, vm.CREATE2:
|
||||||
|
frame = newFlatCreate(input)
|
||||||
|
case vm.SELFDESTRUCT:
|
||||||
|
frame = newFlatSuicide(input)
|
||||||
|
case vm.CALL, vm.STATICCALL, vm.CALLCODE, vm.DELEGATECALL:
|
||||||
|
frame = newFlatCall(input)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unrecognized call frame type: %s", input.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.TraceAddress = traceAddress
|
||||||
|
frame.Error = input.Error
|
||||||
|
frame.Subtraces = len(input.Calls)
|
||||||
|
fillCallFrameFromContext(frame, ctx)
|
||||||
|
if convertErrs {
|
||||||
|
convertErrorToParity(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert output contains useful information (revert reason).
|
||||||
|
// Otherwise discard result.
|
||||||
|
if input.Error != "" && input.Error != vm.ErrExecutionReverted.Error() {
|
||||||
|
frame.Result = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
output = append(output, *frame)
|
||||||
|
if len(input.Calls) > 0 {
|
||||||
|
for i, childCall := range input.Calls {
|
||||||
|
childAddr := childTraceAddress(traceAddress, i)
|
||||||
|
childCallCopy := childCall
|
||||||
|
flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
output = append(output, flat...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addressPointer(a string) *common.Address {
|
||||||
|
if a == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
addr := common.HexToAddress(a)
|
||||||
|
return &addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint64Pointer(v string) *uint64 {
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
val, _ := hexutil.DecodeUint64(v)
|
||||||
|
return &val
|
||||||
|
}
|
||||||
|
|
||||||
|
func bigInt(v string) *big.Int {
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
val, _ := hexutil.DecodeBig(v)
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func bytesPointer(v string) *[]byte {
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
val := hexutil.MustDecode(v)
|
||||||
|
return &val
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFlatCreate(input *callFrame) *flatCallFrame {
|
||||||
|
var (
|
||||||
|
actionInit = bytesPointer(input.Input)
|
||||||
|
resultCode = bytesPointer(input.Output)
|
||||||
|
)
|
||||||
|
|
||||||
|
return &flatCallFrame{
|
||||||
|
Type: strings.ToLower(vm.CREATE.String()),
|
||||||
|
Action: flatCallAction{
|
||||||
|
From: addressPointer(input.From),
|
||||||
|
Gas: uint64Pointer(input.Gas),
|
||||||
|
Value: bigInt(input.Value),
|
||||||
|
Init: actionInit,
|
||||||
|
},
|
||||||
|
Result: &flatCallResult{
|
||||||
|
GasUsed: uint64Pointer(input.GasUsed),
|
||||||
|
Address: addressPointer(input.To),
|
||||||
|
Code: resultCode,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFlatCall(input *callFrame) *flatCallFrame {
|
||||||
|
var (
|
||||||
|
actionInput = bytesPointer(input.Input)
|
||||||
|
resultOutput = bytesPointer(input.Output)
|
||||||
|
)
|
||||||
|
|
||||||
|
return &flatCallFrame{
|
||||||
|
Type: strings.ToLower(vm.CALL.String()),
|
||||||
|
Action: flatCallAction{
|
||||||
|
From: addressPointer(input.From),
|
||||||
|
To: addressPointer(input.To),
|
||||||
|
Gas: uint64Pointer(input.Gas),
|
||||||
|
Value: bigInt(input.Value),
|
||||||
|
CallType: strings.ToLower(input.Type),
|
||||||
|
Input: actionInput,
|
||||||
|
},
|
||||||
|
Result: &flatCallResult{
|
||||||
|
GasUsed: uint64Pointer(input.GasUsed),
|
||||||
|
Output: resultOutput,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFlatSuicide(input *callFrame) *flatCallFrame {
|
||||||
|
return &flatCallFrame{
|
||||||
|
Type: "suicide",
|
||||||
|
Action: flatCallAction{
|
||||||
|
SelfDestructed: addressPointer(input.From),
|
||||||
|
Balance: bigInt(input.Value),
|
||||||
|
RefundAddress: addressPointer(input.To),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *tracers.Context) {
|
||||||
|
if ctx.BlockHash != (common.Hash{}) {
|
||||||
|
callFrame.BlockHash = &ctx.BlockHash
|
||||||
|
}
|
||||||
|
if ctx.BlockNumber != 0 {
|
||||||
|
callFrame.BlockNumber = ctx.BlockNumber
|
||||||
|
}
|
||||||
|
if ctx.TxHash != (common.Hash{}) {
|
||||||
|
callFrame.TransactionHash = &ctx.TxHash
|
||||||
|
}
|
||||||
|
callFrame.TransactionPosition = uint64(ctx.TxIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertErrorToParity(call *flatCallFrame) {
|
||||||
|
if call.Error == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if parityError, ok := parityErrorMapping[call.Error]; ok {
|
||||||
|
call.Error = parityError
|
||||||
|
} else {
|
||||||
|
for gethError, parityError := range parityErrorMappingStartingWith {
|
||||||
|
if strings.HasPrefix(call.Error, gethError) {
|
||||||
|
call.Error = parityError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func childTraceAddress(a []int, i int) []int {
|
||||||
|
child := make([]int, 0, len(a)+1)
|
||||||
|
child = append(child, a...)
|
||||||
|
child = append(child, i)
|
||||||
|
return child
|
||||||
|
}
|
||||||
110
eth/tracers/native/gen_flatcallaction_json.go
Normal file
110
eth/tracers/native/gen_flatcallaction_json.go
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||||
|
|
||||||
|
package native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = (*flatCallActionMarshaling)(nil)
|
||||||
|
|
||||||
|
// MarshalJSON marshals as JSON.
|
||||||
|
func (f flatCallAction) MarshalJSON() ([]byte, error) {
|
||||||
|
type flatCallAction struct {
|
||||||
|
Author *common.Address `json:"author,omitempty"`
|
||||||
|
RewardType string `json:"rewardType,omitempty"`
|
||||||
|
SelfDestructed *common.Address `json:"address,omitempty"`
|
||||||
|
Balance *hexutil.Big `json:"balance,omitempty"`
|
||||||
|
CallType string `json:"callType,omitempty"`
|
||||||
|
CreationMethod string `json:"creationMethod,omitempty"`
|
||||||
|
From *common.Address `json:"from,omitempty"`
|
||||||
|
Gas *hexutil.Uint64 `json:"gas,omitempty"`
|
||||||
|
Init *hexutil.Bytes `json:"init,omitempty"`
|
||||||
|
Input *hexutil.Bytes `json:"input,omitempty"`
|
||||||
|
RefundAddress *common.Address `json:"refundAddress,omitempty"`
|
||||||
|
To *common.Address `json:"to,omitempty"`
|
||||||
|
Value *hexutil.Big `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
var enc flatCallAction
|
||||||
|
enc.Author = f.Author
|
||||||
|
enc.RewardType = f.RewardType
|
||||||
|
enc.SelfDestructed = f.SelfDestructed
|
||||||
|
enc.Balance = (*hexutil.Big)(f.Balance)
|
||||||
|
enc.CallType = f.CallType
|
||||||
|
enc.CreationMethod = f.CreationMethod
|
||||||
|
enc.From = f.From
|
||||||
|
enc.Gas = (*hexutil.Uint64)(f.Gas)
|
||||||
|
enc.Init = (*hexutil.Bytes)(f.Init)
|
||||||
|
enc.Input = (*hexutil.Bytes)(f.Input)
|
||||||
|
enc.RefundAddress = f.RefundAddress
|
||||||
|
enc.To = f.To
|
||||||
|
enc.Value = (*hexutil.Big)(f.Value)
|
||||||
|
return json.Marshal(&enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
|
func (f *flatCallAction) UnmarshalJSON(input []byte) error {
|
||||||
|
type flatCallAction struct {
|
||||||
|
Author *common.Address `json:"author,omitempty"`
|
||||||
|
RewardType *string `json:"rewardType,omitempty"`
|
||||||
|
SelfDestructed *common.Address `json:"address,omitempty"`
|
||||||
|
Balance *hexutil.Big `json:"balance,omitempty"`
|
||||||
|
CallType *string `json:"callType,omitempty"`
|
||||||
|
CreationMethod *string `json:"creationMethod,omitempty"`
|
||||||
|
From *common.Address `json:"from,omitempty"`
|
||||||
|
Gas *hexutil.Uint64 `json:"gas,omitempty"`
|
||||||
|
Init *hexutil.Bytes `json:"init,omitempty"`
|
||||||
|
Input *hexutil.Bytes `json:"input,omitempty"`
|
||||||
|
RefundAddress *common.Address `json:"refundAddress,omitempty"`
|
||||||
|
To *common.Address `json:"to,omitempty"`
|
||||||
|
Value *hexutil.Big `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
var dec flatCallAction
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dec.Author != nil {
|
||||||
|
f.Author = dec.Author
|
||||||
|
}
|
||||||
|
if dec.RewardType != nil {
|
||||||
|
f.RewardType = *dec.RewardType
|
||||||
|
}
|
||||||
|
if dec.SelfDestructed != nil {
|
||||||
|
f.SelfDestructed = dec.SelfDestructed
|
||||||
|
}
|
||||||
|
if dec.Balance != nil {
|
||||||
|
f.Balance = (*big.Int)(dec.Balance)
|
||||||
|
}
|
||||||
|
if dec.CallType != nil {
|
||||||
|
f.CallType = *dec.CallType
|
||||||
|
}
|
||||||
|
if dec.CreationMethod != nil {
|
||||||
|
f.CreationMethod = *dec.CreationMethod
|
||||||
|
}
|
||||||
|
if dec.From != nil {
|
||||||
|
f.From = dec.From
|
||||||
|
}
|
||||||
|
if dec.Gas != nil {
|
||||||
|
f.Gas = (*uint64)(dec.Gas)
|
||||||
|
}
|
||||||
|
if dec.Init != nil {
|
||||||
|
f.Init = (*[]byte)(dec.Init)
|
||||||
|
}
|
||||||
|
if dec.Input != nil {
|
||||||
|
f.Input = (*[]byte)(dec.Input)
|
||||||
|
}
|
||||||
|
if dec.RefundAddress != nil {
|
||||||
|
f.RefundAddress = dec.RefundAddress
|
||||||
|
}
|
||||||
|
if dec.To != nil {
|
||||||
|
f.To = dec.To
|
||||||
|
}
|
||||||
|
if dec.Value != nil {
|
||||||
|
f.Value = (*big.Int)(dec.Value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
55
eth/tracers/native/gen_flatcallresult_json.go
Normal file
55
eth/tracers/native/gen_flatcallresult_json.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||||
|
|
||||||
|
package native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = (*flatCallResultMarshaling)(nil)
|
||||||
|
|
||||||
|
// MarshalJSON marshals as JSON.
|
||||||
|
func (f flatCallResult) MarshalJSON() ([]byte, error) {
|
||||||
|
type flatCallResult struct {
|
||||||
|
Address *common.Address `json:"address,omitempty"`
|
||||||
|
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||||
|
GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"`
|
||||||
|
Output *hexutil.Bytes `json:"output,omitempty"`
|
||||||
|
}
|
||||||
|
var enc flatCallResult
|
||||||
|
enc.Address = f.Address
|
||||||
|
enc.Code = (*hexutil.Bytes)(f.Code)
|
||||||
|
enc.GasUsed = (*hexutil.Uint64)(f.GasUsed)
|
||||||
|
enc.Output = (*hexutil.Bytes)(f.Output)
|
||||||
|
return json.Marshal(&enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
|
func (f *flatCallResult) UnmarshalJSON(input []byte) error {
|
||||||
|
type flatCallResult struct {
|
||||||
|
Address *common.Address `json:"address,omitempty"`
|
||||||
|
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||||
|
GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"`
|
||||||
|
Output *hexutil.Bytes `json:"output,omitempty"`
|
||||||
|
}
|
||||||
|
var dec flatCallResult
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dec.Address != nil {
|
||||||
|
f.Address = dec.Address
|
||||||
|
}
|
||||||
|
if dec.Code != nil {
|
||||||
|
f.Code = (*[]byte)(dec.Code)
|
||||||
|
}
|
||||||
|
if dec.GasUsed != nil {
|
||||||
|
f.GasUsed = (*uint64)(dec.GasUsed)
|
||||||
|
}
|
||||||
|
if dec.Output != nil {
|
||||||
|
f.Output = (*[]byte)(dec.Output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -35,7 +35,7 @@ func init() {
|
||||||
type noopTracer struct{}
|
type noopTracer struct{}
|
||||||
|
|
||||||
// newNoopTracer returns a new noop tracer.
|
// newNoopTracer returns a new noop tracer.
|
||||||
func newNoopTracer() tracers.Tracer {
|
func newNoopTracer(ctx *tracers.Context) tracers.Tracer {
|
||||||
return &noopTracer{}
|
return &noopTracer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ type prestateTracer struct {
|
||||||
deleted map[common.Address]bool
|
deleted map[common.Address]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPrestateTracer() tracers.Tracer {
|
func newPrestateTracer(ctx *tracers.Context) tracers.Tracer {
|
||||||
return &prestateTracer{
|
return &prestateTracer{
|
||||||
pre: state{},
|
pre: state{},
|
||||||
post: state{},
|
post: state{},
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,11 @@ Aside from implementing the tracer, it also needs to register itself, using the
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
func init() {
|
|
||||||
register("noopTracerNative", newNoopTracer)
|
func init() {
|
||||||
}
|
register("noopTracerNative", newNoopTracer)
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
package native
|
package native
|
||||||
|
|
@ -57,12 +59,12 @@ The go spec (https://golang.org/ref/spec#Package_initialization) says
|
||||||
|
|
||||||
Hence, we cannot make the map in init, but must make it upon first use.
|
Hence, we cannot make the map in init, but must make it upon first use.
|
||||||
*/
|
*/
|
||||||
var ctors map[string]func() tracers.Tracer
|
var ctors map[string]func(ctx *tracers.Context) tracers.Tracer
|
||||||
|
|
||||||
// register is used by native tracers to register their presence.
|
// register is used by native tracers to register their presence.
|
||||||
func register(name string, ctor func() tracers.Tracer) {
|
func register(name string, ctor func(ctx *tracers.Context) tracers.Tracer) {
|
||||||
if ctors == nil {
|
if ctors == nil {
|
||||||
ctors = make(map[string]func() tracers.Tracer)
|
ctors = make(map[string]func(ctx *tracers.Context) tracers.Tracer)
|
||||||
}
|
}
|
||||||
ctors[name] = ctor
|
ctors[name] = ctor
|
||||||
}
|
}
|
||||||
|
|
@ -70,10 +72,10 @@ func register(name string, ctor func() tracers.Tracer) {
|
||||||
// lookup returns a tracer, if one can be matched to the given name.
|
// lookup returns a tracer, if one can be matched to the given name.
|
||||||
func lookup(name string, ctx *tracers.Context) (tracers.Tracer, error) {
|
func lookup(name string, ctx *tracers.Context) (tracers.Tracer, error) {
|
||||||
if ctors == nil {
|
if ctors == nil {
|
||||||
ctors = make(map[string]func() tracers.Tracer)
|
ctors = make(map[string]func(ctx *tracers.Context) tracers.Tracer)
|
||||||
}
|
}
|
||||||
if ctor, ok := ctors[name]; ok {
|
if ctor, ok := ctors[name]; ok {
|
||||||
return ctor(), nil
|
return ctor(ctx), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("no tracer found")
|
return nil, errors.New("no tracer found")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,10 @@ import (
|
||||||
// Context contains some contextual infos for a transaction execution that is not
|
// Context contains some contextual infos for a transaction execution that is not
|
||||||
// available from within the EVM object.
|
// available from within the EVM object.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call)
|
BlockNumber uint64 // Block number of the block the tx is contained within (zero if dangling tx or call)
|
||||||
TxIndex int // Index of the transaction within a block (zero if dangling tx or call)
|
BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call)
|
||||||
TxHash common.Hash // Hash of the transaction being traced (zero if dangling call)
|
TxIndex int // Index of the transaction within a block (zero if dangling tx or call)
|
||||||
|
TxHash common.Hash // Hash of the transaction being traced (zero if dangling call)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tracer interface extends vm.EVMLogger and additionally
|
// Tracer interface extends vm.EVMLogger and additionally
|
||||||
|
|
|
||||||
|
|
@ -314,9 +314,10 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
||||||
|
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
tracerContext := tracers.Context{
|
tracerContext := tracers.Context{
|
||||||
BlockHash: block.Hash(),
|
BlockNumber: block.NumberU64(),
|
||||||
TxIndex: index,
|
BlockHash: block.Hash(),
|
||||||
TxHash: tx.Hash(),
|
TxIndex: index,
|
||||||
|
TxHash: tx.Hash(),
|
||||||
}
|
}
|
||||||
callTracer, err := tracers.New("callTracer", &tracerContext)
|
callTracer, err := tracers.New("callTracer", &tracerContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue