@@ -19,10 +19,12 @@ package gethclient
1919
2020import (
2121 "context"
22+ "encoding/json"
2223 "fmt"
2324 "math/big"
2425 "runtime"
2526 "runtime/debug"
27+ "time"
2628
2729 ethereum "github.com/XinFinOrg/XDPoSChain"
2830 "github.com/XinFinOrg/XDPoSChain/common"
@@ -168,6 +170,124 @@ func (ec *Client) TraceBlock(ctx context.Context, hash common.Hash, config *trac
168170 return result , nil
169171}
170172
173+ // CallTracerConfig configures the call tracer for
174+ // TraceTransactionWithCallTracer and TraceCallWithCallTracer.
175+ type CallTracerConfig struct {
176+ // OnlyTopCall, when true, limits tracing to the main (top-level) call only.
177+ OnlyTopCall bool
178+ // WithLog, when true, includes log emissions in the trace output.
179+ WithLog bool
180+ // Timeout is the maximum duration the tracer may run.
181+ // Zero means the server default (5s).
182+ Timeout time.Duration
183+ }
184+
185+ //go:generate go run github.com/fjl/gencodec -type CallLog -field-override callLogMarshaling -out gen_calllog_json.go
186+
187+ // CallLog represents a log emitted during a traced call.
188+ type CallLog struct {
189+ Address common.Address `json:"address"`
190+ Topics []common.Hash `json:"topics"`
191+ Data []byte `json:"data"`
192+ Index uint `json:"index"`
193+ Position uint `json:"position"`
194+ }
195+
196+ type callLogMarshaling struct {
197+ Data hexutil.Bytes
198+ Index hexutil.Uint
199+ Position hexutil.Uint
200+ }
201+
202+ //go:generate go run github.com/fjl/gencodec -type CallFrame -field-override callFrameMarshaling -out gen_callframe_json.go
203+
204+ // CallFrame contains the result of a call tracer run.
205+ type CallFrame struct {
206+ Type string `json:"type"`
207+ From common.Address `json:"from"`
208+ Gas uint64 `json:"gas"`
209+ GasUsed uint64 `json:"gasUsed"`
210+ To * common.Address `json:"to,omitempty"`
211+ Input []byte `json:"input"`
212+ Output []byte `json:"output,omitempty"`
213+ Error string `json:"error,omitempty"`
214+ RevertReason string `json:"revertReason,omitempty"`
215+ Calls []CallFrame `json:"calls,omitempty"`
216+ Logs []CallLog `json:"logs,omitempty"`
217+ Value * big.Int `json:"value,omitempty"`
218+ }
219+
220+ type callFrameMarshaling struct {
221+ Gas hexutil.Uint64
222+ GasUsed hexutil.Uint64
223+ Input hexutil.Bytes
224+ Output hexutil.Bytes
225+ Value * hexutil.Big
226+ }
227+
228+ // TraceTransactionWithCallTracer traces a transaction with the call tracer
229+ // and returns a typed CallFrame. If config is nil, defaults are used.
230+ func (ec * Client ) TraceTransactionWithCallTracer (ctx context.Context , txHash common.Hash , config * CallTracerConfig ) (* CallFrame , error ) {
231+ var result CallFrame
232+ err := ec .c .CallContext (ctx , & result , "debug_traceTransaction" , txHash , callTracerConfig (config ))
233+ if err != nil {
234+ return nil , err
235+ }
236+ return & result , nil
237+ }
238+
239+ // TraceCallWithCallTracer executes a call with the call tracer and returns
240+ // a typed CallFrame. blockNrOrHash selects the block context for the call.
241+ // overrides specifies state overrides (nil for none), blockOverrides specifies
242+ // block header overrides (nil for none), and config configures the tracer
243+ // (nil for defaults).
244+ func (ec * Client ) TraceCallWithCallTracer (ctx context.Context , msg ethereum.CallMsg , blockNrOrHash rpc.BlockNumberOrHash , overrides map [common.Address ]OverrideAccount , blockOverrides * BlockOverrides , config * CallTracerConfig ) (* CallFrame , error ) {
245+ var result CallFrame
246+ err := ec .c .CallContext (ctx , & result , "debug_traceCall" , toCallArg (msg ), blockNrOrHash , callTraceCallConfig (config , overrides , blockOverrides ))
247+ if err != nil {
248+ return nil , err
249+ }
250+ return & result , nil
251+ }
252+
253+ // callTracerConfig converts a CallTracerConfig to the wire-format TraceConfig.
254+ func callTracerConfig (config * CallTracerConfig ) * tracers.TraceConfig {
255+ tracer := "callTracer"
256+ tc := & tracers.TraceConfig {Tracer : & tracer }
257+ if config != nil {
258+ if config .OnlyTopCall || config .WithLog {
259+ cfg , _ := json .Marshal (struct {
260+ OnlyTopCall bool `json:"onlyTopCall"`
261+ WithLog bool `json:"withLog"`
262+ }{config .OnlyTopCall , config .WithLog })
263+ tc .TracerConfig = cfg
264+ }
265+ if config .Timeout != 0 {
266+ s := config .Timeout .String ()
267+ tc .Timeout = & s
268+ }
269+ }
270+ return tc
271+ }
272+
273+ // callTraceCallConfig builds the wire-format TraceCallConfig for debug_traceCall,
274+ // bundling tracer settings with optional state and block overrides.
275+ func callTraceCallConfig (config * CallTracerConfig , overrides map [common.Address ]OverrideAccount , blockOverrides * BlockOverrides ) interface {} {
276+ tc := callTracerConfig (config )
277+ // debug_traceCall expects a single config object that includes both
278+ // tracer settings and any state/block overrides.
279+ type traceCallConfig struct {
280+ * tracers.TraceConfig
281+ StateOverrides map [common.Address ]OverrideAccount `json:"stateOverrides,omitempty"`
282+ BlockOverrides * BlockOverrides `json:"blockOverrides,omitempty"`
283+ }
284+ return & traceCallConfig {
285+ TraceConfig : tc ,
286+ StateOverrides : overrides ,
287+ BlockOverrides : blockOverrides ,
288+ }
289+ }
290+
171291func toBlockNumArg (number * big.Int ) string {
172292 if number == nil {
173293 return "latest"
0 commit comments