package commands import ( "context" "sync" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/consensus/ethash" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/turbo/shards" "github.com/ledgerwatch/log/v3" ) func (api *OtterscanAPIImpl) searchTraceBlock(ctx context.Context, wg *sync.WaitGroup, addr common.Address, chainConfig *params.ChainConfig, idx int, bNum uint64, results []*TransactionsWithReceipts) { wg.Done() // Trace block for Txs newdbtx, err := api.db.BeginRo(ctx) if err != nil { log.Error("Search trace error", "err", err) results[idx] = nil return } defer newdbtx.Rollback() _, result, err := api.traceBlock(newdbtx, ctx, bNum, addr, chainConfig) if err != nil { log.Error("Search trace error", "err", err) results[idx] = nil return } results[idx] = result } func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNum uint64, searchAddr common.Address, chainConfig *params.ChainConfig) (bool, *TransactionsWithReceipts, error) { rpcTxs := make([]*commands.RPCTransaction, 0) receipts := make([]map[string]interface{}, 0) // Retrieve the transaction and assemble its EVM context blockHash, err := rawdb.ReadCanonicalHash(dbtx, blockNum) if err != nil { return false, nil, err } block, senders, err := api._blockReader.BlockWithSenders(ctx, dbtx, blockHash, blockNum) if err != nil { return false, nil, err } reader := state.NewPlainState(dbtx, blockNum) stateCache := shards.NewStateCache(32, 0 /* no limit */) cachedReader := state.NewCachedReader(reader, stateCache) noop := state.NewNoopWriter() cachedWriter := state.NewCachedWriter(noop, stateCache) ibs := state.New(cachedReader) signer := types.MakeSigner(chainConfig, blockNum) getHeader := func(hash common.Hash, number uint64) *types.Header { h, e := api._blockReader.Header(ctx, dbtx, hash, number) if e != nil { log.Error("getHeader error", "number", number, "hash", hash, "err", e) } return h } engine := ethash.NewFaker() blockReceipts := rawdb.ReadReceipts(dbtx, block, senders) header := block.Header() rules := chainConfig.Rules(block.NumberU64()) found := false for idx, tx := range block.Transactions() { ibs.Prepare(tx.Hash(), block.Hash(), idx) msg, _ := tx.AsMessage(*signer, header.BaseFee, rules) tracer := NewTouchTracer(searchAddr) BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) TxContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.GetGas()), true /* refunds */, false /* gasBailout */); err != nil { return false, nil, err } _ = ibs.FinalizeTx(vmenv.ChainConfig().Rules(block.NumberU64()), cachedWriter) if tracer.Found { rpcTx := newRPCTransaction(tx, block.Hash(), blockNum, uint64(idx), block.BaseFee()) mReceipt := marshalReceipt(blockReceipts[idx], tx, chainConfig, block, tx.Hash(), true) mReceipt["timestamp"] = block.Time() rpcTxs = append(rpcTxs, rpcTx) receipts = append(receipts, mReceipt) found = true } } return found, &TransactionsWithReceipts{rpcTxs, receipts, false, false}, nil }