diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 84dd9a8cf8..6cc68adbba 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -170,11 +170,13 @@ func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber return api.blockByHash(ctx, hash) } -// returns block transactions along with state-sync transaction if present -func (api *API) getAllBlockTransactions(ctx context.Context, block *types.Block) (types.Transactions, bool) { +// getAllBlockTransactions returns all blocks transactions including state-sync transaction if present +// along with a flag and it's hash (which is calculated differently than regular transactions) +func (api *API) getAllBlockTransactions(ctx context.Context, block *types.Block) (types.Transactions, bool, common.Hash) { txs := block.Transactions() stateSyncPresent := false + stateSyncHash := common.Hash{} borReceipt := rawdb.ReadBorReceipt(api.backend.ChainDb(), block.Hash(), block.NumberU64(), api.backend.ChainConfig()) if borReceipt != nil { @@ -183,10 +185,11 @@ func (api *API) getAllBlockTransactions(ctx context.Context, block *types.Block) borTx, _, _, _, _ := api.backend.GetBorBlockTransactionWithBlockHash(ctx, txHash, block.Hash()) txs = append(txs, borTx) stateSyncPresent = true + stateSyncHash = txHash } } - return txs, stateSyncPresent + return txs, stateSyncPresent, stateSyncHash } // TraceConfig holds extra parameters to trace functions. @@ -338,19 +341,23 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) ) // Trace all the transactions contained within - txs, stateSyncPresent := api.getAllBlockTransactions(ctx, task.block) + txs, stateSyncPresent, stateSyncHash := api.getAllBlockTransactions(ctx, task.block) if !*config.BorTraceEnabled && stateSyncPresent { txs = txs[:len(txs)-1] stateSyncPresent = false } - for i, tx := range task.block.Transactions() { + for i, tx := range txs { msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee()) + txHash := tx.Hash() + if stateSyncPresent && i == len(txs)-1 { + txHash = stateSyncHash + } txctx := &Context{ BlockHash: task.block.Hash(), BlockNumber: task.block.Number(), TxIndex: i, - TxHash: tx.Hash(), + TxHash: txHash, } var res interface{} @@ -365,14 +372,14 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed res, err = api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { - task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} - log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) + task.results[i] = &txTraceResult{TxHash: txHash, Error: err.Error()} + log.Warn("Tracing failed", "hash", txHash, "block", task.block.NumberU64(), "err", err) break } // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) - task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} + task.results[i] = &txTraceResult{TxHash: txHash, Result: res} } // Tracing state is used up, queue it for de-referencing. Note the // state is the parent state of trace block, use block.number-1 as @@ -667,7 +674,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) - txs, stateSyncPresent := api.getAllBlockTransactions(ctx, block) + txs, stateSyncPresent, stateSyncHash := api.getAllBlockTransactions(ctx, block) for i, tx := range txs { if err := ctx.Err(); err != nil { return nil, err @@ -679,14 +686,13 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) - statedb.SetTxContext(tx.Hash(), i) //nolint: nestif if stateSyncPresent && i == len(txs)-1 { if *config.BorTraceEnabled { callmsg := prepareCallMessage(*msg) - + statedb.SetTxContext(stateSyncHash, i) if _, err := statefull.ApplyMessage(ctx, callmsg, statedb, block.Header(), api.backend.ChainConfig(), api.chainContext(ctx)); err != nil { - log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) + log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", stateSyncHash, "err", err) // We intentionally don't return the error here: if we do, then the RPC server will not // return the roots. Most likely, the caller already knows that a certain transaction fails to // be included, but still want the intermediate roots that led to that point. @@ -699,6 +705,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config break } } else { + statedb.SetTxContext(tx.Hash(), i) // nolint : contextcheck if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), context.Background()); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) @@ -788,12 +795,12 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // Execute all the transaction contained within the block concurrently var ( - txs, stateSyncPresent = api.getAllBlockTransactions(ctx, block) - blockHash = block.Hash() - blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) - results = make([]*txTraceResult, len(txs)) - pend sync.WaitGroup + txs, stateSyncPresent, stateSyncHash = api.getAllBlockTransactions(ctx, block) + blockHash = block.Hash() + blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) + results = make([]*txTraceResult, len(txs)) + pend sync.WaitGroup ) threads := runtime.NumCPU() @@ -811,11 +818,15 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // Fetch and execute the next transaction trace tasks for task := range jobs { msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee()) + txHash := txs[task.index].Hash() + if stateSyncPresent && task.index == len(txs)-1 { + txHash = stateSyncHash + } txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: task.index, - TxHash: txs[task.index].Hash(), + TxHash: txHash, } var res interface{} @@ -834,10 +845,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } if err != nil { - results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} + results[task.index] = &txTraceResult{TxHash: txHash, Error: err.Error()} continue } - results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Result: res} + results[task.index] = &txTraceResult{TxHash: txHash, Result: res} } }() } @@ -1049,7 +1060,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } - txs, stateSyncPresent := api.getAllBlockTransactions(ctx, block) + txs, stateSyncPresent, stateSyncHash := api.getAllBlockTransactions(ctx, block) if !*config.BorTraceEnabled && stateSyncPresent { txs = txs[:len(txs)-1] stateSyncPresent = false @@ -1066,7 +1077,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block err error ) // If the transaction needs tracing, swap out the configs - if tx.Hash() == txHash || txHash == (common.Hash{}) { + if tx.Hash() == txHash || txHash == (common.Hash{}) || txHash == stateSyncHash { // Generate a unique temporary file to dump it into prefix := fmt.Sprintf("block_%#x-%d-%#x-", block.Hash().Bytes()[:4], i, tx.Hash().Bytes()[:4]) if !canon { @@ -1089,11 +1100,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) - statedb.SetTxContext(tx.Hash(), i) + //nolint: nestif if stateSyncPresent && i == len(txs)-1 { if *config.BorTraceEnabled { callmsg := prepareCallMessage(*msg) + statedb.SetTxContext(stateSyncHash, i) _, err = statefull.ApplyBorMessage(vmenv, callmsg) if writer != nil { @@ -1101,6 +1113,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } } } else { + statedb.SetTxContext(tx.Hash(), i) // nolint : contextcheck _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), context.Background()) @@ -1133,9 +1146,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // containsTx reports whether the transaction with a certain hash // is contained within the specified block. func (api *API) containsTx(ctx context.Context, block *types.Block, hash common.Hash) bool { - txs, _ := api.getAllBlockTransactions(ctx, block) + txs, _, stateSyncHash := api.getAllBlockTransactions(ctx, block) for _, tx := range txs { - if tx.Hash() == hash { + if tx.Hash() == hash || stateSyncHash == hash { return true } } diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go index 565148c384..59250c1e68 100644 --- a/eth/tracers/api_bor.go +++ b/eth/tracers/api_bor.go @@ -68,16 +68,20 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T // Execute all the transaction contained within the block concurrently var ( - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) - txs, stateSyncPresent = api.getAllBlockTransactions(ctx, block) - deleteEmptyObjects = api.backend.ChainConfig().IsEIP158(block.Number()) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) + txs, stateSyncPresent, stateSyncHash = api.getAllBlockTransactions(ctx, block) + deleteEmptyObjects = api.backend.ChainConfig().IsEIP158(block.Number()) ) blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - traceTxn := func(indx int, tx *types.Transaction, borTx bool) *TxTraceResult { + traceTxn := func(indx int, tx *types.Transaction, borTx bool, stateSyncHash common.Hash) *TxTraceResult { message, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txContext := core.NewEVMTxContext(message) + txHash := tx.Hash() + if borTx { + txHash = stateSyncHash + } tracer := logger.NewStructLogger(config.Config) @@ -86,7 +90,7 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T // Call Prepare to clear out the statedb access list // Not sure if we need to do this - statedb.SetTxContext(tx.Hash(), indx) + statedb.SetTxContext(txHash, indx) var execRes *core.ExecutionResult @@ -124,9 +128,9 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T for indx, tx := range txs { if stateSyncPresent && indx == len(txs)-1 { - res.Transactions = append(res.Transactions, traceTxn(indx, tx, true)) + res.Transactions = append(res.Transactions, traceTxn(indx, tx, true, stateSyncHash)) } else { - res.Transactions = append(res.Transactions, traceTxn(indx, tx, false)) + res.Transactions = append(res.Transactions, traceTxn(indx, tx, false, stateSyncHash)) } }