Skip to content

Commit afc2028

Browse files
gzliudans1na
andauthored
eth: add request cancellation checks ethereum#26320 (#1314)
This ensures that RPC method handlers will react to a timeout or cancelled request soon after the event occurs. Co-authored-by: Sina Mahmoodi <[email protected]>
1 parent dee4c98 commit afc2028

File tree

4 files changed

+30
-11
lines changed

4 files changed

+30
-11
lines changed

eth/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash,
404404
if block == nil {
405405
return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash)
406406
}
407-
_, _, statedb, release, err := api.eth.stateAtTransaction(block, txIndex, 0)
407+
_, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0)
408408
if err != nil {
409409
return StorageRangeResult{}, err
410410
}

eth/api_backend.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,11 +415,11 @@ func (b *EthAPIBackend) Miner() *miner.Miner {
415415
}
416416

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

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

425425
func (b *EthAPIBackend) GetIPCClient() (bind.ContractBackend, error) {

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
"math/big"
@@ -57,7 +58,7 @@ var noopReleaser = tracers.StateReleaseFunc(func() {})
5758
// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is
5859
// provided, it would be preferable to start from a fresh state, if we have it
5960
// on disk.
60-
func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
61+
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) {
6162
var (
6263
current *types.Block
6364
database state.Database
@@ -112,6 +113,9 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state
112113
}
113114
// Database does not have the state for the given block, try to regenerate
114115
for i := uint64(0); i < reexec; i++ {
116+
if err := ctx.Err(); err != nil {
117+
return nil, nil, err
118+
}
115119
if current.NumberU64() == 0 {
116120
return nil, nil, errors.New("genesis state is missing")
117121
}
@@ -143,6 +147,9 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state
143147
parent common.Hash
144148
)
145149
for current.NumberU64() < origin {
150+
if err := ctx.Err(); err != nil {
151+
return nil, nil, err
152+
}
146153
// Print progress logs if long enough time elapsed
147154
if time.Since(logged) > 8*time.Second && report {
148155
log.Info("Regenerating historical state", "block", current.NumberU64()+1, "target", origin, "remaining", origin-current.NumberU64()-1, "elapsed", time.Since(start))
@@ -183,7 +190,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state
183190
}
184191

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

eth/tracers/api.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
526526
)
527527
feeCapacity := state.GetTRC21FeeCapacityFromState(statedb)
528528
for i, tx := range block.Transactions() {
529+
if err := ctx.Err(); err != nil {
530+
return nil, err
531+
}
529532
var balance *big.Int
530533
if tx.To() != nil {
531534
// Bypass the validation for trading and lending transactions as their nonce are not incremented
@@ -590,14 +593,13 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
590593
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
591594
txs = block.Transactions()
592595
results = make([]*txTraceResult, len(txs))
593-
594-
pend = new(sync.WaitGroup)
595-
jobs = make(chan *txTraceTask, len(txs))
596+
pend sync.WaitGroup
596597
)
597598
threads := runtime.NumCPU()
598599
if threads > len(txs) {
599600
threads = len(txs)
600601
}
602+
jobs := make(chan *txTraceTask, threads)
601603
blockHash := block.Hash()
602604
for th := 0; th < threads; th++ {
603605
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
@@ -629,13 +631,22 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
629631
}
630632
}()
631633
}
634+
632635
// Feed the transactions into the tracers and return
633636
feeCapacity := state.GetTRC21FeeCapacityFromState(statedb)
634637
var failed error
635638
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
639+
txloop:
636640
for i, tx := range txs {
637641
// Send the trace task over for execution
638-
jobs <- &txTraceTask{statedb: statedb.Copy(), index: i}
642+
task := &txTraceTask{statedb: statedb.Copy(), index: i}
643+
select {
644+
case <-ctx.Done():
645+
failed = ctx.Err()
646+
break txloop
647+
case jobs <- task:
648+
}
649+
639650
var balance *big.Int
640651
if tx.To() != nil {
641652
// Bypass the validation for trading and lending transactions as their nonce are not incremented
@@ -654,12 +665,13 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
654665
owner := common.Address{}
655666
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), owner); err != nil {
656667
failed = err
657-
break
668+
break txloop
658669
}
659670
// Finalize the state so any modifications are written to the trie
660671
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
661672
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
662673
}
674+
663675
close(jobs)
664676
pend.Wait()
665677

0 commit comments

Comments
 (0)