Skip to content

Commit f53ff0f

Browse files
fjls1na
andauthored
eth/filters, eth/tracers: add request cancellation checks (ethereum#26320)
This ensures that RPC method handlers will react to a timeout or cancelled request soon after the event occurs. Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
1 parent f51f6ed commit f53ff0f

File tree

5 files changed

+33
-12
lines changed

5 files changed

+33
-12
lines changed

eth/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,13 +405,13 @@ type storageEntry struct {
405405
}
406406

407407
// StorageRangeAt returns the storage at the given block height and transaction index.
408-
func (api *DebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
408+
func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
409409
// Retrieve the block
410410
block := api.eth.blockchain.GetBlockByHash(blockHash)
411411
if block == nil {
412412
return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash)
413413
}
414-
_, _, statedb, release, err := api.eth.stateAtTransaction(block, txIndex, 0)
414+
_, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0)
415415
if err != nil {
416416
return StorageRangeResult{}, err
417417
}

eth/api_backend.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,9 @@ func (b *EthAPIBackend) StartMining(threads int) error {
365365
}
366366

367367
func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
368-
return b.eth.StateAtBlock(block, reexec, base, readOnly, preferDisk)
368+
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
369369
}
370370

371371
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
372-
return b.eth.stateAtTransaction(block, txIndex, reexec)
372+
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
373373
}

eth/filters/filter.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e
234234
var logs []*types.Log
235235

236236
for ; f.begin <= int64(end); f.begin++ {
237+
if f.begin%10 == 0 && ctx.Err() != nil {
238+
return logs, ctx.Err()
239+
}
237240
header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
238241
if header == nil || err != nil {
239242
return logs, err

eth/state_accessor.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package eth
1818

1919
import (
20+
"context"
2021
"errors"
2122
"fmt"
2223
"time"
@@ -56,7 +57,7 @@ var noopReleaser = tracers.StateReleaseFunc(func() {})
5657
// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is
5758
// provided, it would be preferable to start from a fresh state, if we have it
5859
// on disk.
59-
func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
60+
func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
6061
var (
6162
current *types.Block
6263
database state.Database
@@ -111,6 +112,9 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state
111112
}
112113
// Database does not have the state for the given block, try to regenerate
113114
for i := uint64(0); i < reexec; i++ {
115+
if err := ctx.Err(); err != nil {
116+
return nil, nil, err
117+
}
114118
if current.NumberU64() == 0 {
115119
return nil, nil, errors.New("genesis state is missing")
116120
}
@@ -142,6 +146,9 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state
142146
parent common.Hash
143147
)
144148
for current.NumberU64() < origin {
149+
if err := ctx.Err(); err != nil {
150+
return nil, nil, err
151+
}
145152
// Print progress logs if long enough time elapsed
146153
if time.Since(logged) > 8*time.Second && report {
147154
log.Info("Regenerating historical state", "block", current.NumberU64()+1, "target", origin, "remaining", origin-current.NumberU64()-1, "elapsed", time.Since(start))
@@ -182,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state
182189
}
183190

184191
// stateAtTransaction returns the execution environment of a certain transaction.
185-
func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
192+
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
186193
// Short circuit if it's genesis block.
187194
if block.NumberU64() == 0 {
188195
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
@@ -194,7 +201,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
194201
}
195202
// Lookup the statedb of parent block from the live database,
196203
// otherwise regenerate it on the flight.
197-
statedb, release, err := eth.StateAtBlock(parent, reexec, nil, true, false)
204+
statedb, release, err := eth.StateAtBlock(ctx, parent, reexec, nil, true, false)
198205
if err != nil {
199206
return nil, vm.BlockContext{}, nil, nil, err
200207
}

eth/tracers/api.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
549549
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
550550
)
551551
for i, tx := range block.Transactions() {
552+
if err := ctx.Err(); err != nil {
553+
return nil, err
554+
}
552555
var (
553556
msg, _ = tx.AsMessage(signer, block.BaseFee())
554557
txContext = core.NewEVMTxContext(msg)
@@ -609,14 +612,13 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
609612
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
610613
txs = block.Transactions()
611614
results = make([]*txTraceResult, len(txs))
612-
613-
pend = new(sync.WaitGroup)
614-
jobs = make(chan *txTraceTask, len(txs))
615+
pend sync.WaitGroup
615616
)
616617
threads := runtime.NumCPU()
617618
if threads > len(txs) {
618619
threads = len(txs)
619620
}
621+
jobs := make(chan *txTraceTask, threads)
620622
blockHash := block.Hash()
621623
for th := 0; th < threads; th++ {
622624
pend.Add(1)
@@ -640,25 +642,34 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
640642
}
641643
}()
642644
}
645+
643646
// Feed the transactions into the tracers and return
644647
var failed error
645648
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
649+
txloop:
646650
for i, tx := range txs {
647651
// Send the trace task over for execution
648-
jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
652+
task := &txTraceTask{statedb: statedb.Copy(), index: i}
653+
select {
654+
case <-ctx.Done():
655+
failed = ctx.Err()
656+
break txloop
657+
case jobs <- task:
658+
}
649659

650660
// Generate the next state snapshot fast without tracing
651661
msg, _ := tx.AsMessage(signer, block.BaseFee())
652662
statedb.SetTxContext(tx.Hash(), i)
653663
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
654664
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
655665
failed = err
656-
break
666+
break txloop
657667
}
658668
// Finalize the state so any modifications are written to the trie
659669
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
660670
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
661671
}
672+
662673
close(jobs)
663674
pend.Wait()
664675

0 commit comments

Comments
 (0)