github.com/amazechain/amc@v0.1.3/internal/tracers/api.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The AmazeChain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tracers 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 common2 "github.com/amazechain/amc/common" 26 "github.com/amazechain/amc/common/transaction" 27 "github.com/amazechain/amc/internal/api" 28 "github.com/amazechain/amc/internal/avm/rlp" 29 "github.com/amazechain/amc/internal/vm/evmtypes" 30 "github.com/ledgerwatch/erigon-lib/kv" 31 "time" 32 33 types "github.com/amazechain/amc/common/block" 34 "github.com/amazechain/amc/common/hexutil" 35 common "github.com/amazechain/amc/common/types" 36 core "github.com/amazechain/amc/internal" 37 "github.com/amazechain/amc/internal/consensus" 38 "github.com/amazechain/amc/internal/tracers/logger" 39 "github.com/amazechain/amc/internal/vm" 40 rpc "github.com/amazechain/amc/modules/rpc/jsonrpc" 41 "github.com/amazechain/amc/modules/state" 42 "github.com/amazechain/amc/params" 43 ) 44 45 const ( 46 // defaultTraceTimeout is the amount of time a single transaction can execute 47 // by default before being forcefully aborted. 48 defaultTraceTimeout = 5 * time.Second 49 50 // defaultTraceReexec is the number of blocks the tracer is willing to go back 51 // and reexecute to produce missing historical state necessary to run a specific 52 // trace. 53 defaultTraceReexec = uint64(128) 54 55 // defaultTracechainMemLimit is the size of the triedb, at which traceChain 56 // switches over and tries to use a disk-backed database instead of building 57 // on top of memory. 58 // For non-archive nodes, this limit _will_ be overblown, as disk-backed tries 59 // will only be found every ~15K blocks or so. 60 defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024) 61 62 // maximumPendingTraceStates is the maximum number of states allowed waiting 63 // for tracing. The creation of trace state will be paused if the unused 64 // trace states exceed this limit. 65 maximumPendingTraceStates = 128 66 ) 67 68 var errTxNotFound = errors.New("transaction not found") 69 70 // StateReleaseFunc is used to deallocate resources held by constructing a 71 // historical state for tracing purposes. 72 type StateReleaseFunc func() 73 74 // Backend interface provides the common API services (that are provided by 75 // both full and light clients) with access to necessary functions. 76 type Backend interface { 77 HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) 78 HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) 79 BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) 80 BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) 81 GetTransaction(ctx context.Context, txHash common.Hash) (*transaction.Transaction, common.Hash, uint64, uint64, error) 82 RPCGasCap() uint64 83 ChainConfig() *params.ChainConfig 84 Engine() consensus.Engine 85 ChainDb() kv.RwDB 86 StateAtBlock(ctx context.Context, tx kv.Tx, block *types.Block /*, reexec uint64, base *state.IntraBlockState, readOnly bool, preferDisk bool*/) (*state.IntraBlockState, error) 87 StateAtTransaction(ctx context.Context, tx kv.Tx, block *types.Block, txIndex int /*, reexec uint64*/) (*transaction.Message, evmtypes.BlockContext, *state.IntraBlockState, error) 88 } 89 90 // API is the collection of tracing APIs exposed over the private debugging endpoint. 91 type API struct { 92 backend Backend 93 } 94 95 // NewAPI creates a new API definition for the tracing methods of the Ethereum service. 96 func NewAPI(backend Backend) *API { 97 return &API{backend: backend} 98 } 99 100 type chainContext struct { 101 api *API 102 ctx context.Context 103 } 104 105 func (context *chainContext) Engine() consensus.Engine { 106 return context.api.backend.Engine() 107 } 108 109 func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header { 110 header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number)) 111 if err != nil { 112 return nil 113 } 114 if header.Hash() == hash { 115 return header 116 } 117 header, err = context.api.backend.HeaderByHash(context.ctx, hash) 118 if err != nil { 119 return nil 120 } 121 return header 122 } 123 124 // chainContext constructs the context reader which is used by the evm for reading 125 // the necessary chain context. 126 //func (api *API) chainContext(ctx context.Context) core.ChainContext { 127 // return &chainContext{api: api, ctx: ctx} 128 //} 129 130 // blockByNumber is the wrapper of the chain access function offered by the backend. 131 // It will return an error if the block is not found. 132 func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { 133 block, err := api.backend.BlockByNumber(ctx, number) 134 if err != nil { 135 return nil, err 136 } 137 if block == nil { 138 return nil, fmt.Errorf("block #%d not found", number) 139 } 140 return block, nil 141 } 142 143 // blockByHash is the wrapper of the chain access function offered by the backend. 144 // It will return an error if the block is not found. 145 func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 146 block, err := api.backend.BlockByHash(ctx, hash) 147 if err != nil { 148 return nil, err 149 } 150 if block == nil { 151 return nil, fmt.Errorf("block %s not found", hash.Hex()) 152 } 153 return block, nil 154 } 155 156 // blockByNumberAndHash is the wrapper of the chain access function offered by 157 // the backend. It will return an error if the block is not found. 158 // 159 // Note this function is friendly for the light client which can only retrieve the 160 // historical(before the CHT) header/block by number. 161 func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) { 162 block, err := api.blockByNumber(ctx, number) 163 if err != nil { 164 return nil, err 165 } 166 if block.Hash() == hash { 167 return block, nil 168 } 169 return api.blockByHash(ctx, hash) 170 } 171 172 // TraceConfig holds extra parameters to trace functions. 173 type TraceConfig struct { 174 *logger.Config 175 Tracer *string 176 Timeout *string 177 Reexec *uint64 178 // Config specific to given tracer. Note struct logger 179 // config are historically embedded in main object. 180 TracerConfig json.RawMessage 181 } 182 183 // TraceCallConfig is the config for traceCall API. It holds one more 184 // field to override the state for tracing. 185 type TraceCallConfig struct { 186 TraceConfig 187 StateOverrides *api.StateOverride 188 BlockOverrides *api.BlockOverrides 189 } 190 191 // StdTraceConfig holds extra parameters to standard-json trace functions. 192 type StdTraceConfig struct { 193 logger.Config 194 Reexec *uint64 195 TxHash common.Hash 196 } 197 198 // txTraceResult is the result of a single transaction trace. 199 type txTraceResult struct { 200 Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer 201 Error string `json:"error,omitempty"` // Trace failure produced by the tracer 202 } 203 204 // blockTraceTask represents a single block trace task when an entire chain is 205 // being traced. 206 type blockTraceTask struct { 207 statedb *state.IntraBlockState // Intermediate state prepped for tracing 208 block *types.Block // Block to trace the transactions from 209 release StateReleaseFunc // The function to release the held resource for this task 210 results []*txTraceResult // Trace results produced by the task 211 } 212 213 // blockTraceResult represents the results of tracing a single block when an entire 214 // chain is being traced. 215 type blockTraceResult struct { 216 Block hexutil.Uint64 `json:"block"` // Block number corresponding to this trace 217 Hash common.Hash `json:"hash"` // Block hash corresponding to this trace 218 Traces []*txTraceResult `json:"traces"` // Trace results produced by the task 219 } 220 221 // txTraceTask represents a single transaction trace task when an entire block 222 // is being traced. 223 type txTraceTask struct { 224 statedb *state.IntraBlockState // Intermediate state prepped for tracing 225 index int // Transaction offset in the block 226 } 227 228 // TraceChain returns the structured logs created during the execution of EVM 229 // between two blocks (excluding start) and returns them as a JSON object. 230 //func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) { // Fetch the block interval that we want to trace 231 // from, err := api.blockByNumber(ctx, start) 232 // if err != nil { 233 // return nil, err 234 // } 235 // to, err := api.blockByNumber(ctx, end) 236 // if err != nil { 237 // return nil, err 238 // } 239 // if from.Number64().Cmp(to.Number64()) >= 0 { 240 // return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start) 241 // } 242 // // Tracing a chain is a **long** operation, only do with subscriptions 243 // notifier, supported := rpc.NotifierFromContext(ctx) 244 // if !supported { 245 // return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported 246 // } 247 // sub := notifier.CreateSubscription() 248 // 249 // resCh := api.traceChain(from, to, config, notifier.Closed()) 250 // go func() { 251 // for result := range resCh { 252 // notifier.Notify(sub.ID, result) 253 // } 254 // }() 255 // return sub, nil 256 //} 257 258 // traceChain configures a new tracer according to the provided configuration, and 259 // executes all the transactions contained within. The tracing chain range includes 260 // the end block but excludes the start one. The return value will be one item per 261 // transaction, dependent on the requested tracer. 262 // The tracing procedure should be aborted in case the closed signal is received. 263 //func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult { 264 // reexec := defaultTraceReexec 265 // if config != nil && config.Reexec != nil { 266 // reexec = *config.Reexec 267 // } 268 // blocks := int(end.Number64().Uint64() - start.Number64().Uint64()) 269 // threads := runtime.NumCPU() 270 // if threads > blocks { 271 // threads = blocks 272 // } 273 // var ( 274 // pend = new(sync.WaitGroup) 275 // ctx = context.Background() 276 // taskCh = make(chan *blockTraceTask, threads) 277 // resCh = make(chan *blockTraceTask, threads) 278 // tracker = newStateTracker(maximumPendingTraceStates, start.Number64().Uint64()) 279 // ) 280 // for th := 0; th < threads; th++ { 281 // pend.Add(1) 282 // go func() { 283 // defer pend.Done() 284 // 285 // // Fetch and execute the block trace taskCh 286 // for task := range taskCh { 287 // var ( 288 // signer = transaction.MakeSigner(api.backend.ChainConfig(), task.block.Number64().ToBig()) 289 // blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) 290 // ) 291 // // Trace all the transactions contained within 292 // for i, tx := range task.block.Transactions() { 293 // msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee()) 294 // txctx := &Context{ 295 // BlockHash: task.block.Hash(), 296 // BlockNumber: task.block.Number64().ToBig(), 297 // TxIndex: i, 298 // TxHash: tx.Hash(), 299 // } 300 // res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) 301 // if err != nil { 302 // task.results[i] = &txTraceResult{Error: err.Error()} 303 // log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) 304 // break 305 // } 306 // // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 307 // task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) 308 // task.results[i] = &txTraceResult{Result: res} 309 // } 310 // // Tracing state is used up, queue it for de-referencing. Note the 311 // // state is the parent state of trace block, use block.number-1 as 312 // // the state number. 313 // tracker.releaseState(task.block.NumberU64()-1, task.release) 314 // 315 // // Stream the result back to the result catcher or abort on teardown 316 // select { 317 // case resCh <- task: 318 // case <-closed: 319 // return 320 // } 321 // } 322 // }() 323 // } 324 // // Start a goroutine to feed all the blocks into the tracers 325 // go func() { 326 // var ( 327 // logged time.Time 328 // begin = time.Now() 329 // number uint64 330 // traced uint64 331 // failed error 332 // statedb *state.IntraBlockState 333 // release StateReleaseFunc 334 // ) 335 // // Ensure everything is properly cleaned up on any exit path 336 // defer func() { 337 // close(taskCh) 338 // pend.Wait() 339 // 340 // // Clean out any pending release functions of trace states. 341 // tracker.callReleases() 342 // 343 // // Log the chain result 344 // switch { 345 // case failed != nil: 346 // log.Warn("Chain tracing failed", "start", start.Number64(), "end", end.Number64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed) 347 // case number < end.Number64().Uint64(): 348 // log.Warn("Chain tracing aborted", "start", start.Number64(), "end", end.Number64(), "abort", number, "transactions", traced, "elapsed", time.Since(begin)) 349 // default: 350 // log.Info("Chain tracing finished", "start", start.Number64(), "end", end.Number64(), "transactions", traced, "elapsed", time.Since(begin)) 351 // } 352 // close(resCh) 353 // }() 354 // // Feed all the blocks both into the tracer, as well as fast process concurrently 355 // for number = start.Number64().Uint64(); number < end.Number64().Uint64(); number++ { 356 // // Stop tracing if interruption was requested 357 // select { 358 // case <-closed: 359 // return 360 // default: 361 // } 362 // // Print progress logs if long enough time elapsed 363 // if time.Since(logged) > 8*time.Second { 364 // logged = time.Now() 365 // log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin)) 366 // } 367 // // Retrieve the parent block and target block for tracing. 368 // block, err := api.blockByNumber(ctx, rpc.BlockNumber(number)) 369 // if err != nil { 370 // failed = err 371 // break 372 // } 373 // next, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1)) 374 // if err != nil { 375 // failed = err 376 // break 377 // } 378 // // Make sure the state creator doesn't go too far. Too many unprocessed 379 // // trace state may cause the oldest state to become stale(e.g. in 380 // // path-based scheme). 381 // if err = tracker.wait(number); err != nil { 382 // failed = err 383 // break 384 // } 385 // // Prepare the statedb for tracing. Don't use the live database for 386 // // tracing to avoid persisting state junks into the database. Switch 387 // // over to `preferDisk` mode only if the memory usage exceeds the 388 // // limit, the trie database will be reconstructed from scratch only 389 // // if the relevant state is available in disk. 390 // var preferDisk bool 391 // if statedb != nil { 392 // s1, s2 := statedb.Database().TrieDB().Size() 393 // preferDisk = s1+s2 > defaultTracechainMemLimit 394 // } 395 // statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk) 396 // if err != nil { 397 // failed = err 398 // break 399 // } 400 // // Clean out any pending release functions of trace state. Note this 401 // // step must be done after constructing tracing state, because the 402 // // tracing state of block next depends on the parent state and construction 403 // // may fail if we release too early. 404 // tracker.callReleases() 405 // 406 // // Send the block over to the concurrent tracers (if not in the fast-forward phase) 407 // txs := next.Transactions() 408 // select { 409 // case taskCh <- &blockTraceTask{statedb: statedb.copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}: 410 // case <-closed: 411 // tracker.releaseState(number, release) 412 // return 413 // } 414 // traced += uint64(len(txs)) 415 // } 416 // }() 417 // 418 // // Keep reading the trace results and stream them to result channel. 419 // retCh := make(chan *blockTraceResult) 420 // go func() { 421 // defer close(retCh) 422 // var ( 423 // next = start.Number64().Uint64() + 1 424 // done = make(map[uint64]*blockTraceResult) 425 // ) 426 // for res := range resCh { 427 // // Queue up next received result 428 // result := &blockTraceResult{ 429 // Block: hexutil.Uint64(res.block.Number64().Uint64()), 430 // Hash: res.block.Hash(), 431 // Traces: res.results, 432 // } 433 // done[uint64(result.Block)] = result 434 // 435 // // Stream completed traces to the result channel 436 // for result, ok := done[next]; ok; result, ok = done[next] { 437 // if len(result.Traces) > 0 || next == end.Number64().Uint64() { 438 // // It will be blocked in case the channel consumer doesn't take the 439 // // tracing result in time(e.g. the websocket connect is not stable) 440 // // which will eventually block the entire chain tracer. It's the 441 // // expected behavior to not waste node resources for a non-active user. 442 // retCh <- result 443 // } 444 // delete(done, next) 445 // next++ 446 // } 447 // } 448 // }() 449 // return retCh 450 //} 451 452 // TraceBlockByNumber returns the structured logs created during the execution of 453 // EVM and returns them as a JSON object. 454 func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) { 455 block, err := api.blockByNumber(ctx, number) 456 if err != nil { 457 return nil, err 458 } 459 return api.traceBlock(ctx, block, config) 460 } 461 462 // TraceBlockByHash returns the structured logs created during the execution of 463 // EVM and returns them as a JSON object. 464 func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) { 465 block, err := api.blockByHash(ctx, hash) 466 if err != nil { 467 return nil, err 468 } 469 return api.traceBlock(ctx, block, config) 470 } 471 472 // TraceBlock returns the structured logs created during the execution of EVM 473 // and returns them as a JSON object. 474 func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) { 475 block := new(types.Block) 476 if err := rlp.Decode(bytes.NewReader(blob), block); err != nil { 477 return nil, fmt.Errorf("could not decode block: %v", err) 478 } 479 return api.traceBlock(ctx, block, config) 480 } 481 482 // TraceBlockFromFile returns the structured logs created during the execution of 483 // EVM and returns them as a JSON object. 484 //func (api *API) TraceBlockFromFile(ctx context.Context, file string, config *TraceConfig) ([]*txTraceResult, error) { 485 // blob, err := os.ReadFile(file) 486 // if err != nil { 487 // return nil, fmt.Errorf("could not read file: %v", err) 488 // } 489 // return api.TraceBlock(ctx, blob, config) 490 //} 491 492 // TraceBadBlock returns the structured logs created during the execution of 493 // EVM against a block pulled from the pool of bad ones and returns them as a JSON 494 // object. 495 //func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) { 496 // block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash) 497 // if block == nil { 498 // return nil, fmt.Errorf("bad block %#x not found", hash) 499 // } 500 // return api.traceBlock(ctx, block, config) 501 //} 502 503 // StandardTraceBlockToFile dumps the structured logs created during the 504 // execution of EVM to the local file system and returns a list of files 505 // to the caller. 506 //func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) { 507 // block, err := api.blockByHash(ctx, hash) 508 // if err != nil { 509 // return nil, err 510 // } 511 // return api.standardTraceBlockToFile(ctx, block, config) 512 //} 513 514 // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list 515 // of intermediate roots: the stateroot after each transaction. 516 //func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) { 517 // block, _ := api.blockByHash(ctx, hash) 518 // if block == nil { 519 // // Check in the bad blocks 520 // block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash) 521 // } 522 // if block == nil { 523 // return nil, fmt.Errorf("block %#x not found", hash) 524 // } 525 // if block.NumberU64() == 0 { 526 // return nil, errors.New("genesis is not traceable") 527 // } 528 // parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) 529 // if err != nil { 530 // return nil, err 531 // } 532 // reexec := defaultTraceReexec 533 // if config != nil && config.Reexec != nil { 534 // reexec = *config.Reexec 535 // } 536 // statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) 537 // if err != nil { 538 // return nil, err 539 // } 540 // defer release() 541 // 542 // var ( 543 // roots []common.Hash 544 // signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) 545 // chainConfig = api.backend.ChainConfig() 546 // vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) 547 // deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) 548 // ) 549 // for i, tx := range block.Transactions() { 550 // if err := ctx.Err(); err != nil { 551 // return nil, err 552 // } 553 // var ( 554 // msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) 555 // txContext = core.NewEVMTxContext(msg) 556 // vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) 557 // ) 558 // statedb.SetTxContext(tx.Hash(), i) 559 // if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { 560 // log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) 561 // // We intentionally don't return the error here: if we do, then the RPC server will not 562 // // return the roots. Most likely, the caller already knows that a certain transaction fails to 563 // // be included, but still want the intermediate roots that led to that point. 564 // // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be 565 // // executable. 566 // // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. 567 // return roots, nil 568 // } 569 // // calling IntermediateRoot will internally call Finalize on the state 570 // // so any modifications are written to the trie 571 // roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) 572 // } 573 // return roots, nil 574 //} 575 576 // StandardTraceBadBlockToFile dumps the structured logs created during the 577 // execution of EVM against a block pulled from the pool of bad ones to the 578 // local file system and returns a list of files to the caller. 579 //func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) { 580 // block := rawdb.ReadBadBlock(api.backend.ChainDb(), hash) 581 // if block == nil { 582 // return nil, fmt.Errorf("bad block %#x not found", hash) 583 // } 584 // return api.standardTraceBlockToFile(ctx, block, config) 585 //} 586 587 // traceBlock configures a new tracer according to the provided configuration, and 588 // executes all the transactions contained within. The return value will be one item 589 // per transaction, dependent on the requested tracer. 590 func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { 591 if block.Number64().Uint64() == 0 { 592 return nil, errors.New("genesis is not traceable") 593 } 594 // Prepare base state 595 parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.Number64().Uint64()-1), block.ParentHash()) 596 if err != nil { 597 return nil, err 598 } 599 //reexec := defaultTraceReexec 600 //if config != nil && config.Reexec != nil { 601 // reexec = *config.Reexec 602 //} 603 604 rtx, err := api.backend.ChainDb().BeginRo(ctx) 605 if nil != err { 606 return nil, err 607 } 608 defer rtx.Rollback() 609 610 statedb, err := api.backend.StateAtBlock(ctx, rtx, parent /*, reexec, nil, true, false*/) 611 if err != nil { 612 return nil, err 613 } 614 // defer release() 615 616 // JS tracers have high overhead. In this case run a parallel 617 // process that generates states in one thread and traces txes 618 // in separate worker threads. 619 //if config != nil && config.Tracer != nil && *config.Tracer != "" { 620 // if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS { 621 // return api.traceBlockParallel(ctx, block, statedb, config) 622 // } 623 //} 624 625 // Native tracers have low overhead 626 var ( 627 txs = block.Transactions() 628 blockHash = block.Hash() 629 //is158 = api.backend.ChainConfig().IsSpuriousDragon(block.Number64().Uint64()) 630 blockCtx = core.NewEVMBlockContext(block.Header().(*types.Header), core.GetHashFn(block.Header().(*types.Header), api.chainContext(ctx).GetHeader), api.chainContext(ctx).Engine(), nil) 631 signer = transaction.MakeSigner(api.backend.ChainConfig(), block.Number64().ToBig()) 632 results = make([]*txTraceResult, len(txs)) 633 ) 634 for i, tx := range txs { 635 // Generate the next state snapshot fast without tracing 636 msg, _ := tx.AsMessage(signer, block.BaseFee64()) 637 txctx := &Context{ 638 BlockHash: blockHash, 639 BlockNumber: block.Number64().ToBig(), 640 TxIndex: i, 641 TxHash: tx.Hash(), 642 } 643 res, err := api.traceTx(ctx, &msg, txctx, blockCtx, statedb, config) 644 if err != nil { 645 return nil, err 646 } 647 results[i] = &txTraceResult{Result: res} 648 // Finalize the state so any modifications are written to the trie 649 // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 650 //statedb.SoftFinalise(is158) 651 statedb.FinalizeTx(api.backend.ChainConfig().Rules(block.Number64().Uint64()), state.NewNoopWriter()) 652 } 653 return results, nil 654 } 655 656 // chainContext constructs the context reader which is used by the evm for reading 657 // the necessary chain context. 658 func (api *API) chainContext(ctx context.Context) core.ChainContext { 659 return &chainContext{api: api, ctx: ctx} 660 } 661 662 // traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread 663 // runs along and executes txes without tracing enabled to generate their prestate. 664 // Worker threads take the tasks and the prestate and trace them. 665 //func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.IntraBlockState, config *TraceConfig) ([]*txTraceResult, error) { 666 // // Execute all the transaction contained within the block concurrently 667 // var ( 668 // txs = block.Transactions() 669 // blockHash = block.Hash() 670 // blockCtx = core.NewEVMBlockContext(block.Header().(*types.Header), core.GetHashFn(block.Header().(*types.Header), api.chainContext(ctx).GetHeader), api.chainContext(ctx).Engine(), nil) 671 // signer = transaction.MakeSigner(api.backend.ChainConfig(), block.Number64().ToBig()) 672 // results = make([]*txTraceResult, len(txs)) 673 // pend sync.WaitGroup 674 // ) 675 // threads := runtime.NumCPU() 676 // if threads > len(txs) { 677 // threads = len(txs) 678 // } 679 // jobs := make(chan *txTraceTask, threads) 680 // for th := 0; th < threads; th++ { 681 // pend.Add(1) 682 // go func() { 683 // defer pend.Done() 684 // // Fetch and execute the next transaction trace tasks 685 // for task := range jobs { 686 // msg, _ := txs[task.index].AsMessage(signer, block.BaseFee64()) 687 // txctx := &Context{ 688 // BlockHash: blockHash, 689 // BlockNumber: block.Number64().ToBig(), 690 // TxIndex: task.index, 691 // TxHash: txs[task.index].Hash(), 692 // } 693 // res, err := api.traceTx(ctx, &msg, txctx, blockCtx, task.statedb, config) 694 // if err != nil { 695 // results[task.index] = &txTraceResult{Error: err.Error()} 696 // continue 697 // } 698 // results[task.index] = &txTraceResult{Result: res} 699 // } 700 // }() 701 // } 702 // 703 // // Feed the transactions into the tracers and return 704 // var failed error 705 //txloop: 706 // for i, tx := range txs { 707 // // Send the trace task over for execution 708 // task := &txTraceTask{statedb: statedb.Copy(), index: i} 709 // select { 710 // case <-ctx.Done(): 711 // failed = ctx.Err() 712 // break txloop 713 // case jobs <- task: 714 // } 715 // 716 // // Generate the next state snapshot fast without tracing 717 // msg, _ := tx.AsMessage(signer, block.BaseFee64()) 718 // statedb.Prepare(tx.Hash(), blockHash, i) 719 // vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) 720 // if _, err := core.ApplyMessage(vmenv, msg, new(common2.GasPool).AddGas(msg.Gas())); err != nil { 721 // failed = err 722 // break txloop 723 // } 724 // // Finalize the state so any modifications are written to the trie 725 // // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 726 // statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) 727 // } 728 // 729 // close(jobs) 730 // pend.Wait() 731 // 732 // // If execution failed in between, abort 733 // if failed != nil { 734 // return nil, failed 735 // } 736 // return results, nil 737 //} 738 739 // standardTraceBlockToFile configures a new tracer which uses standard JSON output, 740 // and traces either a full block or an individual transaction. The return value will 741 // be one filename per transaction traced. 742 //func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) { 743 // // If we're tracing a single transaction, make sure it's present 744 // if config != nil && config.TxHash != (common.Hash{}) { 745 // if !containsTx(block, config.TxHash) { 746 // return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash) 747 // } 748 // } 749 // if block.NumberU64() == 0 { 750 // return nil, errors.New("genesis is not traceable") 751 // } 752 // parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) 753 // if err != nil { 754 // return nil, err 755 // } 756 // reexec := defaultTraceReexec 757 // if config != nil && config.Reexec != nil { 758 // reexec = *config.Reexec 759 // } 760 // statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) 761 // if err != nil { 762 // return nil, err 763 // } 764 // defer release() 765 // 766 // // Retrieve the tracing configurations, or use default values 767 // var ( 768 // logConfig logger.Config 769 // txHash common.Hash 770 // ) 771 // if config != nil { 772 // logConfig = config.Config 773 // txHash = config.TxHash 774 // } 775 // logConfig.Debug = true 776 // 777 // // Execute transaction, either tracing all or just the requested one 778 // var ( 779 // dumps []string 780 // signer = transaction.MakeSigner(api.backend.ChainConfig(), block.Number64().ToBig()) 781 // chainConfig = api.backend.ChainConfig() 782 // vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) 783 // canon = true 784 // ) 785 // // Check if there are any overrides: the caller may wish to enable a future 786 // // fork when executing this block. Note, such overrides are only applicable to the 787 // // actual specified block, not any preceding blocks that we have to go through 788 // // in order to obtain the state. 789 // // Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork` 790 // if config != nil && config.Overrides != nil { 791 // // Note: This copies the config, to not screw up the main config 792 // chainConfig, canon = overrideConfig(chainConfig, config.Overrides) 793 // } 794 // for i, tx := range block.Transactions() { 795 // // Prepare the transaction for un-traced execution 796 // var ( 797 // msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) 798 // txContext = core.NewEVMTxContext(msg) 799 // vmConf vm.Config 800 // dump *os.File 801 // writer *bufio.Writer 802 // err error 803 // ) 804 // // If the transaction needs tracing, swap out the configs 805 // if tx.Hash() == txHash || txHash == (common.Hash{}) { 806 // // Generate a unique temporary file to dump it into 807 // prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4]) 808 // if !canon { 809 // prefix = fmt.Sprintf("%valt-", prefix) 810 // } 811 // dump, err = os.CreateTemp(os.TempDir(), prefix) 812 // if err != nil { 813 // return nil, err 814 // } 815 // dumps = append(dumps, dump.Name()) 816 // 817 // // Swap out the noop logger to the standard tracer 818 // writer = bufio.NewWriter(dump) 819 // vmConf = vm.Config{ 820 // Debug: true, 821 // Tracer: logger.NewJSONLogger(&logConfig, writer), 822 // EnablePreimageRecording: true, 823 // } 824 // } 825 // // Execute the transaction and flush any traces to disk 826 // vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) 827 // statedb.SetTxContext(tx.Hash(), i) 828 // _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) 829 // if writer != nil { 830 // writer.Flush() 831 // } 832 // if dump != nil { 833 // dump.Close() 834 // log.Info("Wrote standard trace", "file", dump.Name()) 835 // } 836 // if err != nil { 837 // return dumps, err 838 // } 839 // // Finalize the state so any modifications are written to the trie 840 // // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 841 // statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) 842 // 843 // // If we've traced the transaction we were looking for, abort 844 // if tx.Hash() == txHash { 845 // break 846 // } 847 // } 848 // return dumps, nil 849 //} 850 851 // containsTx reports whether the transaction with a certain hash 852 // is contained within the specified block. 853 func containsTx(block *types.Block, hash common.Hash) bool { 854 for _, tx := range block.Transactions() { 855 if tx.Hash() == hash { 856 return true 857 } 858 } 859 return false 860 } 861 862 // TraceTransaction returns the structured logs created during the execution of EVM 863 // and returns them as a JSON object. 864 func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { 865 tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) 866 if err != nil { 867 return nil, err 868 } 869 // Only mined txes are supported 870 if tx == nil { 871 return nil, errTxNotFound 872 } 873 // It shouldn't happen in practice. 874 if blockNumber == 0 { 875 return nil, errors.New("genesis is not traceable") 876 } 877 //reexec := defaultTraceReexec 878 //if config != nil && config.Reexec != nil { 879 // reexec = *config.Reexec 880 //} 881 block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash) 882 if err != nil { 883 return nil, err 884 } 885 886 dbTx, err := api.backend.ChainDb().BeginRo(ctx) 887 if nil != err { 888 return nil, err 889 } 890 defer dbTx.Rollback() 891 892 msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, dbTx, block, int(index)) 893 if err != nil { 894 return nil, err 895 } 896 //defer release() 897 898 txctx := &Context{ 899 BlockHash: blockHash, 900 BlockNumber: block.Number64().ToBig(), 901 TxIndex: int(index), 902 TxHash: hash, 903 } 904 return api.traceTx(ctx, msg, txctx, vmctx, statedb, config) 905 } 906 907 // TraceCall lets you trace a given eth_call. It collects the structured logs 908 // created during the execution of EVM if the given transaction was added on 909 // top of the provided block and returns them as a JSON object. 910 func (api *API) TraceCall(ctx context.Context, args api.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) { 911 // Try to retrieve the specified block 912 var ( 913 err error 914 block *types.Block 915 ) 916 if hash, ok := blockNrOrHash.Hash(); ok { 917 block, err = api.blockByHash(ctx, hash) 918 } else if number, ok := blockNrOrHash.Number(); ok { 919 if number == rpc.PendingBlockNumber { 920 // We don't have access to the miner here. For tracing 'future' transactions, 921 // it can be done with block- and state-overrides instead, which offers 922 // more flexibility and stability than trying to trace on 'pending', since 923 // the contents of 'pending' is unstable and probably not a true representation 924 // of what the next actual block is likely to contain. 925 return nil, errors.New("tracing on top of pending is not supported") 926 } 927 block, err = api.blockByNumber(ctx, number) 928 } else { 929 return nil, errors.New("invalid arguments; neither block nor hash specified") 930 } 931 if err != nil { 932 return nil, err 933 } 934 // try to recompute the state 935 //reexec := defaultTraceReexec 936 //if config != nil && config.Reexec != nil { 937 // reexec = *config.Reexec 938 //} 939 940 rtx, err := api.backend.ChainDb().BeginRo(ctx) 941 if nil != err { 942 return nil, err 943 } 944 defer rtx.Rollback() 945 946 statedb, err := api.backend.StateAtBlock(ctx, rtx, block /*, reexec, nil, true, false*/) 947 if err != nil { 948 return nil, err 949 } 950 951 vmctx := core.NewEVMBlockContext(block.Header().(*types.Header), core.GetHashFn(block.Header().(*types.Header), api.chainContext(ctx).GetHeader), api.backend.Engine(), nil) 952 // Apply the customization rules if required. 953 if config != nil { 954 if err := config.StateOverrides.Apply(statedb); err != nil { 955 return nil, err 956 } 957 config.BlockOverrides.Apply(&vmctx) 958 } 959 // Execute the trace 960 msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee64().ToBig()) 961 if err != nil { 962 return nil, err 963 } 964 965 var traceConfig *TraceConfig 966 if config != nil { 967 traceConfig = &config.TraceConfig 968 } 969 return api.traceTx(ctx, &msg, new(Context), vmctx, statedb, traceConfig) 970 } 971 972 // traceTx configures a new tracer according to the provided configuration, and 973 // executes the given message in the provided environment. The return value will 974 // be tracer dependent. 975 func (api *API) traceTx(ctx context.Context, message *transaction.Message, txctx *Context, vmctx evmtypes.BlockContext, statedb *state.IntraBlockState, config *TraceConfig) (interface{}, error) { 976 var ( 977 tracer Tracer 978 err error 979 timeout = defaultTraceTimeout 980 txContext = core.NewEVMTxContext(message) 981 ) 982 if config == nil { 983 config = &TraceConfig{} 984 } 985 // Default tracer is the struct logger 986 tracer = logger.NewStructLogger(config.Config) 987 if config.Tracer != nil { 988 tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) 989 if err != nil { 990 return nil, err 991 } 992 } 993 //Debug: true, Tracer: logger.NewMarkdownLogger(nil, os.Stdout) 994 vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) 995 996 // Define a meaningful timeout of a single transaction trace 997 if config.Timeout != nil { 998 if timeout, err = time.ParseDuration(*config.Timeout); err != nil { 999 return nil, err 1000 } 1001 } 1002 deadlineCtx, cancel := context.WithTimeout(ctx, timeout) 1003 go func() { 1004 <-deadlineCtx.Done() 1005 if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { 1006 tracer.Stop(errors.New("execution timeout")) 1007 // Stop evm execution. Note cancellation is not necessarily immediate. 1008 vmenv.Cancel() 1009 } 1010 }() 1011 defer cancel() 1012 1013 // Call Prepare to clear out the statedb access list 1014 statedb.Prepare(txctx.TxHash, txctx.BlockHash, txctx.TxIndex) 1015 if _, err = core.ApplyMessage(vmenv, message, new(common2.GasPool).AddGas(message.Gas()), true, false); err != nil { 1016 return nil, fmt.Errorf("tracing failed: %w", err) 1017 } 1018 return tracer.GetResult() 1019 } 1020 1021 // APIs return the collection of RPC services the tracer package offers. 1022 func APIs(backend Backend) []rpc.API { 1023 // Append all the local APIs and return 1024 return []rpc.API{ 1025 { 1026 Namespace: "debug", 1027 Service: NewAPI(backend), 1028 }, 1029 } 1030 } 1031 1032 // overrideConfig returns a copy of original with forks enabled by override enabled, 1033 // along with a boolean that indicates whether the copy is canonical (equivalent to the original). 1034 // Note: the Clique-part is _not_ deep copied 1035 func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) (*params.ChainConfig, bool) { 1036 copy := new(params.ChainConfig) 1037 *copy = *original 1038 canon := true 1039 1040 // Apply forks (after Berlin) to the copy. 1041 if block := override.BerlinBlock; block != nil { 1042 copy.BerlinBlock = block 1043 canon = false 1044 } 1045 if block := override.LondonBlock; block != nil { 1046 copy.LondonBlock = block 1047 canon = false 1048 } 1049 if block := override.ArrowGlacierBlock; block != nil { 1050 copy.ArrowGlacierBlock = block 1051 canon = false 1052 } 1053 if block := override.GrayGlacierBlock; block != nil { 1054 copy.GrayGlacierBlock = block 1055 canon = false 1056 } 1057 if block := override.MergeNetsplitBlock; block != nil { 1058 copy.MergeNetsplitBlock = block 1059 canon = false 1060 } 1061 if timestamp := override.ShanghaiBlock; timestamp != nil { 1062 copy.ShanghaiBlock = timestamp 1063 canon = false 1064 } 1065 if timestamp := override.CancunBlock; timestamp != nil { 1066 copy.CancunBlock = timestamp 1067 canon = false 1068 } 1069 if timestamp := override.PragueTime; timestamp != nil { 1070 copy.PragueTime = timestamp 1071 canon = false 1072 } 1073 1074 return copy, canon 1075 }