From 5f45f826a2d604abaa401ff4a135bc50bff0492b Mon Sep 17 00:00:00 2001 From: Zhang Guyu Date: Wed, 5 Jul 2023 18:07:15 +0800 Subject: [PATCH] eth/traces,core: add support to record flat call traces when evm processing transcation --- cmd/geth/main.go | 2 ++ cmd/utils/flags.go | 41 ++++++++++++++++++++++++++++++++++ common/json_compare.go | 40 +++++++++++++++++++++++++++++++++ core/rawdb/accessors_trace.go | 42 +++++++++++++++++++++++++++++++++++ core/rawdb/database.go | 4 ++++ core/rawdb/schema.go | 7 ++++++ core/state_processor.go | 29 ++++++++++++++++++++++++ core/vm/interpreter.go | 7 ++++++ core/vm/logger.go | 17 ++++++++++++++ eth/api_backend.go | 20 +++++++++++++++++ eth/backend.go | 17 ++++++++++++++ eth/ethconfig/config.go | 7 ++++++ eth/ethconfig/gen_config.go | 21 ++++++++++++++---- eth/tracers/api.go | 11 +++++++++ eth/tracers/api_test.go | 15 +++++++++++++ les/api_backend.go | 4 ++++ 16 files changed, 280 insertions(+), 4 deletions(-) create mode 100644 common/json_compare.go create mode 100644 core/rawdb/accessors_trace.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 42a05f4d1a9d..208aa5fc5099 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -84,6 +84,8 @@ var ( utils.GCModeFlag, utils.SnapshotFlag, utils.TxLookupLimitFlag, + utils.TxTraceEnabledFlag, + utils.TxTraceConfigPathFlag, utils.LightServeFlag, utils.LightIngressFlag, utils.LightEgressFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 525abf042ded..aa67529860ef 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -22,6 +22,7 @@ import ( "context" "crypto/ecdsa" "encoding/hex" + "encoding/json" "errors" "fmt" "math" @@ -243,6 +244,17 @@ var ( Value: ethconfig.Defaults.TxLookupLimit, Category: flags.EthCategory, } + TxTraceEnabledFlag = &cli.BoolFlag{ + Name: "txtrace", + Usage: "Enable record transaction trace while evm processing", + Category: flags.EthCategory, + } + TxTraceConfigPathFlag = &cli.PathFlag{ + Name: "txtrace.cfg", + Usage: "Path to txtrace config file, if not set, use openEthereum's style as default config", + TakesFile: true, + Category: flags.EthCategory, + } LightKDFFlag = &cli.BoolFlag{ Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", @@ -1849,6 +1861,10 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil { Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err) } + if ctx.IsSet(TxTraceEnabledFlag.Name) { + cfg.EnableTxTraceRecording = true + cfg.TxTraceConfig = MakeTxTraceConfig(ctx) + } } // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if @@ -2166,3 +2182,28 @@ func MakeConsolePreloads(ctx *cli.Context) []string { } return preloads } + +// MakeTxtraceConfig reads the txtrace config file (the same traceconfig format as the debug_traceXXX APIs) +// and returns the TraceConfig specified by the global --txtrace.cfg flag. +func MakeTxTraceConfig(ctx *cli.Context) tracers.TraceConfig { + path := ctx.Path(TxTraceConfigPathFlag.Name) + var traceConfig tracers.TraceConfig + if path == "" { + tracer := "flatCallTracer" + tracerConfigdata, _ := json.Marshal(map[string]interface{}{ + "convertParityErrors": true, + "includePrecompiles": true, + }) + traceConfig.Tracer = &tracer + traceConfig.TracerConfig = tracerConfigdata + return traceConfig + } + data, err := os.ReadFile(path) + if err != nil { + Fatalf("Failed to read txtrace file: %v", err) + } + if err := json.Unmarshal(data, &traceConfig); err != nil { + Fatalf("Failed to parse txtrace config file: %v", err) + } + return traceConfig +} diff --git a/common/json_compare.go b/common/json_compare.go new file mode 100644 index 000000000000..7a4ce835b102 --- /dev/null +++ b/common/json_compare.go @@ -0,0 +1,40 @@ +// Copyright 2023 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 . + +package common + +import ( + "encoding/json" + "reflect" +) + +// CmpJson compares the JSON in two byte slices. +func CmpJson(a, b []byte) bool { + if a == nil { + return b == nil + } + if b == nil { + return false + } + var j1, j2 interface{} + if err := json.Unmarshal(a, &j1); err != nil { + return false + } + if err := json.Unmarshal(b, &j2); err != nil { + return false + } + return reflect.DeepEqual(j1, j2) +} diff --git a/core/rawdb/accessors_trace.go b/core/rawdb/accessors_trace.go new file mode 100644 index 000000000000..af874bbcb8cc --- /dev/null +++ b/core/rawdb/accessors_trace.go @@ -0,0 +1,42 @@ +// Copyright 2023 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 . + +package rawdb + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" +) + +// ReadTxTrace retrieves the transaction trace for the given hash from the database. +func ReadTxTrace(db ethdb.KeyValueReader, hash common.Hash) ([]byte, error) { + return db.Get(txTraceKey(hash)) +} + +// WriteTxTrace stores the transaction trace for the given hash to the database. +func WriteTxTrace(db ethdb.KeyValueWriter, hash common.Hash, trace []byte) { + if err := db.Put(txTraceKey(hash), trace); err != nil { + log.Crit("Failed to store transaction trace", "err", err) + } +} + +// DeleteTxTrace deletes the transaction trace for the given hash from the database. +func DeleteTxTrace(db ethdb.KeyValueWriter, hash common.Hash) { + if err := db.Delete(txTraceKey(hash)); err != nil { + log.Crit("Failed to delete transaction trace", "err", err) + } +} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index e864bcb2e88e..9037748fb5a9 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -472,6 +472,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bloomBits stat beaconHeaders stat cliqueSnaps stat + txtraces stat // Les statistic chtTrieNodes stat @@ -536,6 +537,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bytes.HasPrefix(key, BloomTrieIndexPrefix) || bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub bloomTrieNodes.Add(size) + case bytes.HasPrefix(key, TracePrefix) && len(key) == (len(TracePrefix)+common.HashLength): + txtraces.Add(size) default: var accounted bool for _, meta := range [][]byte{ @@ -569,6 +572,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Block number->hash", numHashPairings.Size(), numHashPairings.Count()}, {"Key-Value store", "Block hash->number", hashNumPairings.Size(), hashNumPairings.Count()}, {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, + {"Key-Value store", "Transaction traces", txtraces.Size(), txtraces.Count()}, {"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, {"Key-Value store", "Trie nodes", tries.Size(), tries.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 18722ed5d4cb..697802228606 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -122,6 +122,8 @@ var ( CliqueSnapshotPrefix = []byte("clique-") + TracePrefix = []byte("tr-") + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) ) @@ -181,6 +183,11 @@ func txLookupKey(hash common.Hash) []byte { return append(txLookupPrefix, hash.Bytes()...) } +// txTraceKey = TracePrefix + hash +func txTraceKey(hash common.Hash) []byte { + return append(TracePrefix, hash.Bytes()...) +} + // accountSnapshotKey = SnapshotAccountPrefix + hash func accountSnapshotKey(hash common.Hash) []byte { return append(SnapshotAccountPrefix, hash.Bytes()...) diff --git a/core/state_processor.go b/core/state_processor.go index 4837628e6602..fb4f39117016 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -24,10 +24,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -78,6 +80,20 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { + if cfg.EnableTxTraceRecording { + txctx := &vm.TraceContext{ + BlockHash: blockHash, + BlockNumber: blockNumber, + TxIndex: i, + TxHash: tx.Hash(), + } + tracer, err := cfg.TxTracerCreateFn(cfg.TxTracerName, txctx, cfg.TxTracerConfig) + if err != nil { + return nil, nil, 0, fmt.Errorf("could not create txtracer: %w", err) + } + cfg.Tracer = tracer + vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) + } msg, err := TransactionToMessage(tx, signer, header.BaseFee) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) @@ -89,6 +105,19 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) + if cfg.EnableTxTraceRecording { + tracer := (cfg.Tracer).(vm.EVMLoggerWithResult) + if tracer != nil { + res, err := tracer.GetResult() + if err != nil { + log.Error("could not get result from tracer", "err", err) + } else { + if res != nil { + rawdb.WriteTxTrace(p.bc.db, tx.Hash(), res) + } + } + } + } } // Fail if Shanghai not enabled and len(withdrawals) is non-zero. withdrawals := block.Withdrawals() diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 873337850e6f..06b468abec4e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,6 +17,8 @@ package vm import ( + "encoding/json" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" @@ -29,6 +31,11 @@ type Config struct { NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled + + EnableTxTraceRecording bool // Enables recording trace of tranascations while evm processing + TxTracerName *string // Name of the tracer + TxTracerConfig json.RawMessage // Json config of the tracer + TxTracerCreateFn func(*string, *TraceContext, json.RawMessage) (EVMLoggerWithResult, error) // fn for create tracer } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/core/vm/logger.go b/core/vm/logger.go index 2667908a84d1..dff59e9219b6 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -17,6 +17,7 @@ package vm import ( + "encoding/json" "math/big" "github.com/ethereum/go-ethereum/common" @@ -41,3 +42,19 @@ type EVMLogger interface { CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) } + +// TraceContext contains some contextual infos for a transaction execution that is not +// available from within the EVM object. +type TraceContext struct { + BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call) + BlockNumber *big.Int // 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) + TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) +} + +// EVMLoggerWithResult interface extends vm.EVMLogger and additionally +// allows collecting the tracing result. +type EVMLoggerWithResult interface { + EVMLogger + GetResult() (json.RawMessage, error) +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 02d1946e8e42..1b4540f53e2f 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -18,7 +18,9 @@ package eth import ( "context" + "encoding/json" "errors" + "fmt" "math/big" "time" @@ -318,6 +320,24 @@ func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) return tx, blockHash, blockNumber, index, nil } +func (b *EthAPIBackend) GetTransactionTrace(ctx context.Context, traceCfg *tracers.TraceConfig, txHash common.Hash) (json.RawMessage, error) { + vmCfg := b.eth.BlockChain().GetVMConfig() + if vmCfg.EnableTxTraceRecording && + *vmCfg.TxTracerName == *traceCfg.Tracer && + common.CmpJson(vmCfg.TxTracerConfig, traceCfg.TracerConfig) { + data, err := rawdb.ReadTxTrace(b.eth.ChainDb(), txHash) + if err != nil { + return nil, err + } + if len(data) == 0 { + return nil, fmt.Errorf("transaction trace %s not found", txHash.Hex()) + } + return data, nil + } + + return nil, fmt.Errorf("transaction trace config not support") +} + func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { return b.eth.txPool.Nonce(addr), nil } diff --git a/eth/backend.go b/eth/backend.go index 63bd864b21eb..b4bf1c4f8cd3 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -18,6 +18,7 @@ package eth import ( + "encoding/json" "errors" "fmt" "math/big" @@ -43,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -181,6 +183,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { var ( vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, + EnableTxTraceRecording: config.EnableTxTraceRecording, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, @@ -192,6 +195,20 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Preimages: config.Preimages, } ) + if vmConfig.EnableTxTraceRecording { + vmConfig.TxTracerName = config.TxTraceConfig.Tracer + vmConfig.TxTracerConfig = config.TxTraceConfig.TracerConfig + // If TxTraceRecording is enabled, we need to create a tracer for each transaction. + vmConfig.TxTracerCreateFn = func(name *string, tc *vm.TraceContext, config json.RawMessage) (vm.EVMLoggerWithResult, error) { + return tracers.DefaultDirectory.New(*name, &tracers.Context{ + BlockHash: tc.BlockHash, + BlockNumber: tc.BlockNumber, + TxIndex: tc.TxIndex, + TxHash: tc.TxHash, + }, config) + } + } + // Override the chain config with provided settings. var overrides core.ChainOverrides if config.OverrideCancun != nil { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index dc798ec196f3..a40299fe9280 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" @@ -161,6 +162,12 @@ type Config struct { // OverrideVerkle (TODO: remove after the fork) OverrideVerkle *uint64 `toml:",omitempty"` + + // EnableTxTraceRecording enables recording trace of VM operations. + EnableTxTraceRecording bool `toml:",omitempty"` + + // TxTraceConfig is the configuration for tx trace recording. + TxTraceConfig tracers.TraceConfig `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain config. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 8f4846723609..fcbf981c6375 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/miner" ) @@ -52,8 +53,10 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCGasCap uint64 RPCEVMTimeout time.Duration RPCTxFeeCap float64 - OverrideCancun *uint64 `toml:",omitempty"` - OverrideVerkle *uint64 `toml:",omitempty"` + OverrideCancun *uint64 `toml:",omitempty"` + OverrideVerkle *uint64 `toml:",omitempty"` + EnableTxTraceRecording bool `toml:",omitempty"` + TxTraceConfig tracers.TraceConfig `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -94,6 +97,8 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCTxFeeCap = c.RPCTxFeeCap enc.OverrideCancun = c.OverrideCancun enc.OverrideVerkle = c.OverrideVerkle + enc.EnableTxTraceRecording = c.EnableTxTraceRecording + enc.TxTraceConfig = c.TxTraceConfig return &enc, nil } @@ -136,8 +141,10 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCGasCap *uint64 RPCEVMTimeout *time.Duration RPCTxFeeCap *float64 - OverrideCancun *uint64 `toml:",omitempty"` - OverrideVerkle *uint64 `toml:",omitempty"` + OverrideCancun *uint64 `toml:",omitempty"` + OverrideVerkle *uint64 `toml:",omitempty"` + EnableTxTraceRecording *bool `toml:",omitempty"` + TxTraceConfig *tracers.TraceConfig `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -257,5 +264,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideVerkle != nil { c.OverrideVerkle = dec.OverrideVerkle } + if dec.EnableTxTraceRecording != nil { + c.EnableTxTraceRecording = *dec.EnableTxTraceRecording + } + if dec.TxTraceConfig != nil { + c.TxTraceConfig = *dec.TxTraceConfig + } return nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 740a38ab9fbf..867d82cb760e 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -82,6 +82,7 @@ type Backend interface { BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) + GetTransactionTrace(ctx context.Context, traceCfg *TraceConfig, txHash common.Hash) (json.RawMessage, error) RPCGasCap() uint64 ChainConfig() *params.ChainConfig Engine() consensus.Engine @@ -838,6 +839,16 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if blockNumber == 0 { return nil, errors.New("genesis is not traceable") } + // if txtrace is enabled, try to get the trace from the database + data, err := api.backend.GetTransactionTrace(ctx, config, hash) + if err == nil && len(data) > 0 { + result := make([]interface{}, 0) + err = json.Unmarshal(data, &result) + if err == nil { + log.Debug("TraceTransaction: trace found in database", "hash", hash) + return result, nil + } + } reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 11d7ff4b694e..ec0d842b81d7 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -118,6 +118,21 @@ func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (* return tx, hash, blockNumber, index, nil } +func (b *testBackend) GetTransactionTrace(ctx context.Context, traceCfg *TraceConfig, txHash common.Hash) (json.RawMessage, error) { + vmCfg := b.chain.GetVMConfig() + if vmCfg.EnableTxTraceRecording && *vmCfg.TxTracerName == *traceCfg.Tracer && common.CmpJson(vmCfg.TxTracerConfig, traceCfg.TracerConfig) { + data, err := rawdb.ReadTxTrace(b.chaindb, txHash) + if err != nil { + return nil, err + } + if len(data) == 0 { + return nil, fmt.Errorf("transaction trace %s not found", txHash.Hex()) + } + return data, nil + } + return nil, fmt.Errorf("transaction trace config not support") +} + func (b *testBackend) RPCGasCap() uint64 { return 25000000 } diff --git a/les/api_backend.go b/les/api_backend.go index dee3e3bfd93c..61769fbca4d5 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -18,6 +18,7 @@ package les import ( "context" + "encoding/json" "errors" "math/big" "time" @@ -215,6 +216,9 @@ func (b *LesApiBackend) GetPoolTransaction(txHash common.Hash) *types.Transactio func (b *LesApiBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { return light.GetTransaction(ctx, b.eth.odr, txHash) } +func (b *LesApiBackend) GetTransactionTrace(ctx context.Context, traceCfg *tracers.TraceConfig, txHash common.Hash) (json.RawMessage, error) { + return nil, errors.New("trace transaction not supported") +} func (b *LesApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { return b.eth.txPool.GetNonce(ctx, addr)