Skip to content

Commit

Permalink
eth/tracers: use correct state-sync tx hash in tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
manav2401 committed Mar 12, 2024
1 parent 753c57e commit 9e9bf39
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 34 deletions.
67 changes: 40 additions & 27 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down Expand Up @@ -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{}
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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{}
Expand All @@ -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}
}
}()
}
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -1089,18 +1100,20 @@ 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 {
writer.Flush()
}
}
} else {
statedb.SetTxContext(tx.Hash(), i)
// nolint : contextcheck
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit), context.Background())

Expand Down Expand Up @@ -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
}
}
Expand Down
18 changes: 11 additions & 7 deletions eth/tracers/api_bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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

Expand Down Expand Up @@ -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))
}
}

Expand Down

1 comment on commit 9e9bf39

@cffls
Copy link
Contributor

@cffls cffls commented on 9e9bf39 Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably add a unit test for this to prevent similar issue from happening in the future.

Please sign in to comment.