@@ -190,6 +190,8 @@ type (
190
190
Track (ctx context.Context , start time.Time , method string , size int64 , success bool )
191
191
// BlobSidecarsByHeight returns blob sidecars by height
192
192
BlobSidecarsByHeight (height uint64 ) ([]* apitypes.BlobSidecarResult , error )
193
+ // TraceBlockByNumber returns the trace result of a block by its height
194
+ TraceBlockByNumber (ctx context.Context , height uint64 , config * tracers.TraceConfig ) ([][]byte , []* action.Receipt , any , error )
193
195
194
196
// Historical methods
195
197
BalanceAt (ctx context.Context , addr address.Address , height uint64 ) (string , error )
@@ -2139,6 +2141,14 @@ func (core *coreService) TraceCall(ctx context.Context,
2139
2141
})
2140
2142
}
2141
2143
2144
+ func (core * coreService ) TraceBlockByNumber (ctx context.Context , height uint64 , config * tracers.TraceConfig ) ([][]byte , []* action.Receipt , any , error ) {
2145
+ blk , err := core .dao .GetBlockByHeight (height )
2146
+ if err != nil {
2147
+ return nil , nil , nil , err
2148
+ }
2149
+ return core .traceBlock (ctx , blk , config )
2150
+ }
2151
+
2142
2152
// Track tracks the api call
2143
2153
func (core * coreService ) Track (ctx context.Context , start time.Time , method string , size int64 , success bool ) {
2144
2154
if core .apiStats == nil {
@@ -2154,44 +2164,21 @@ func (core *coreService) Track(ctx context.Context, start time.Time, method stri
2154
2164
}
2155
2165
2156
2166
func (core * coreService ) traceTx (ctx context.Context , txctx * tracers.Context , config * tracers.TraceConfig , simulateFn func (ctx context.Context ) ([]byte , * action.Receipt , error )) ([]byte , * action.Receipt , any , error ) {
2157
- var (
2158
- tracer vm.EVMLogger
2159
- err error
2160
- )
2161
- switch {
2162
- case config == nil :
2163
- tracer = logger .NewStructLogger (nil )
2164
- case config .Tracer != nil :
2165
- // Define a meaningful timeout of a single transaction trace
2166
- timeout := defaultTraceTimeout
2167
- if config .Timeout != nil {
2168
- if timeout , err = time .ParseDuration (* config .Timeout ); err != nil {
2169
- return nil , nil , nil , err
2170
- }
2171
- }
2172
- t , err := tracers .DefaultDirectory .New (* config .Tracer , txctx , config .TracerConfig )
2173
- if err != nil {
2174
- return nil , nil , nil , err
2175
- }
2176
- deadlineCtx , cancel := context .WithTimeout (ctx , timeout )
2177
- defer cancel ()
2178
- go func () {
2179
- <- deadlineCtx .Done ()
2180
- if errors .Is (deadlineCtx .Err (), context .DeadlineExceeded ) {
2181
- t .Stop (errors .New ("execution timeout" ))
2182
- }
2183
- }()
2184
- tracer = t
2167
+ ctx , tracer , err := core .traceContext (ctx , txctx , config )
2168
+ retval , receipt , err := simulateFn (ctx )
2169
+ return retval , receipt , tracer , err
2170
+ }
2185
2171
2186
- default :
2187
- tracer = logger .NewStructLogger (config .Config )
2172
+ func (core * coreService ) traceContext (ctx context.Context , txctx * tracers.Context , config * tracers.TraceConfig ) (context.Context , * evmTracer , error ) {
2173
+ tracer := newEVMTracer (txctx , config )
2174
+ if err := tracer .Reset (); err != nil {
2175
+ return nil , nil , status .Error (codes .InvalidArgument , fmt .Sprintf ("failed to reset tracer: %v" , err ))
2188
2176
}
2189
2177
ctx = protocol .WithVMConfigCtx (ctx , vm.Config {
2190
2178
Tracer : tracer ,
2191
2179
NoBaseFee : true ,
2192
2180
})
2193
- retval , receipt , err := simulateFn (ctx )
2194
- return retval , receipt , tracer , err
2181
+ return ctx , tracer , nil
2195
2182
}
2196
2183
2197
2184
func (core * coreService ) simulateExecution (
@@ -2262,6 +2249,67 @@ func (core *coreService) getStateManager(ctx context.Context, height uint64) (co
2262
2249
return ctx , ws , err
2263
2250
}
2264
2251
2252
+ func (core * coreService ) traceBlock (ctx context.Context , blk * block.Block , config * tracers.TraceConfig ) ([][]byte , []* action.Receipt , any , error ) {
2253
+ ctx , err := core .bc .ContextAtHeight (ctx , blk .Height ())
2254
+ if err != nil {
2255
+ return nil , nil , nil , err
2256
+ }
2257
+ g := core .bc .Genesis ()
2258
+ ctx = protocol .WithBlockCtx (ctx , protocol.BlockCtx {
2259
+ BlockHeight : blk .Height (),
2260
+ BlockTimeStamp : blk .Timestamp (),
2261
+ GasLimit : g .BlockGasLimitByHeight (blk .Height ()),
2262
+ Producer : blk .PublicKey ().Address (),
2263
+ })
2264
+ ctx = protocol .WithRegistry (ctx , core .registry )
2265
+ ctx = protocol .WithFeatureCtx (ctx )
2266
+ retvals := make ([][]byte , 0 )
2267
+ receipts := make ([]* action.Receipt , 0 )
2268
+ results := make ([]* blockTraceResult , 0 )
2269
+ ctx , tracer , err := core .traceContext (ctx , new (tracers.Context ), config )
2270
+ if err != nil {
2271
+ return nil , nil , nil , err
2272
+ }
2273
+ ctx = evm .WithTracerCtx (ctx , evm.TracerContext {
2274
+ CaptureTx : func (retval []byte , receipt * action.Receipt ) {
2275
+ defer tracer .Reset ()
2276
+ var res any
2277
+ switch innerTracer := tracer .EVMLogger .(type ) {
2278
+ case * logger.StructLogger :
2279
+ res = & debugTraceTransactionResult {
2280
+ Failed : receipt .Status != uint64 (iotextypes .ReceiptStatus_Success ),
2281
+ Revert : receipt .ExecutionRevertMsg (),
2282
+ ReturnValue : byteToHex (retval ),
2283
+ StructLogs : fromLoggerStructLogs (innerTracer .StructLogs ()),
2284
+ Gas : receipt .GasConsumed ,
2285
+ }
2286
+ case tracers.Tracer :
2287
+ res , err = innerTracer .GetResult ()
2288
+ if err != nil {
2289
+ log .L ().Error ("failed to get tracer result" , zap .Error (err ))
2290
+ return
2291
+ }
2292
+ default :
2293
+ log .L ().Error ("unknown tracer type" , zap .Any ("tracer" , innerTracer ))
2294
+ return
2295
+ }
2296
+ results = append (results , & blockTraceResult {
2297
+ TxHash : receipt .ActionHash ,
2298
+ Result : res ,
2299
+ })
2300
+ retvals = append (retvals , retval )
2301
+ receipts = append (receipts , receipt )
2302
+ },
2303
+ })
2304
+ ws , err := core .sf .WorkingSetAtHeight (ctx , blk .Height ()- 1 , blk .Actions ... )
2305
+ if err != nil {
2306
+ return nil , nil , nil , err
2307
+ }
2308
+ defer ws .Close ()
2309
+
2310
+ return retvals , receipts , results , nil
2311
+ }
2312
+
2265
2313
func filterReceipts (receipts []* action.Receipt , actHash hash.Hash256 ) * action.Receipt {
2266
2314
for _ , r := range receipts {
2267
2315
if r .ActionHash == actHash {
0 commit comments