New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
eth/tracers: use non-threaded traceBlock for native tracers #24283
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -593,6 +593,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac | |
if block.NumberU64() == 0 { | ||
return nil, errors.New("genesis is not traceable") | ||
} | ||
// Prepare base state | ||
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) | ||
if err != nil { | ||
return nil, err | ||
|
@@ -606,24 +607,68 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac | |
return nil, err | ||
} | ||
defer release() | ||
// JS tracers have high overhead. In this case run a parallel | ||
// process that generates states in one thread and traces txes | ||
// in separate worker threads. | ||
if config != nil && config.Tracer != nil && *config.Tracer != "" { | ||
t, err := New(*config.Tracer, nil, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if _, ok := t.(JSTracer); ok { | ||
return api.traceBlockParallel(ctx, block, statedb, config) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This whole thing is a bit wonky, but I guess we can live with it. The alternative would be that they register with some special attribute, and then you can query I'm fine with it as is, though There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that I've seen that you also needed to add that wonky interface just to distinguish the type, I think a less hacky solution would be to change the registration phase, so they register with some attriubute. if config != nil && config.Tracer != nil{
if err, ok := IsInterpreted(config.Tracer); err != nil {
return nil, err
}else if ok{
return api.traceBlockParallel(ctx, block, statedb, config)
}
} |
||
// Native tracers have low overhead | ||
var ( | ||
txs = block.Transactions() | ||
blockHash = block.Hash() | ||
is158 = api.backend.ChainConfig().IsEIP158(block.Number()) | ||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) | ||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) | ||
results = make([]*txTraceResult, len(txs)) | ||
) | ||
for i, tx := range txs { | ||
// Generate the next state snapshot fast without tracing | ||
msg, _ := tx.AsMessage(signer, block.BaseFee()) | ||
txctx := &Context{ | ||
BlockHash: blockHash, | ||
TxIndex: i, | ||
TxHash: tx.Hash(), | ||
} | ||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
results[i] = &txTraceResult{Result: res} | ||
// Finalize the state so any modifications are written to the trie | ||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect | ||
statedb.Finalise(is158) | ||
} | ||
return results, nil | ||
} | ||
|
||
// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread | ||
// runs along and executes txes without tracing enabled to generate their prestate. | ||
// Worker threads take the tasks and the prestate and trace them. | ||
func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.StateDB, config *TraceConfig) ([]*txTraceResult, error) { | ||
// Execute all the transaction contained within the block concurrently | ||
var ( | ||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) | ||
txs = block.Transactions() | ||
results = make([]*txTraceResult, len(txs)) | ||
pend sync.WaitGroup | ||
txs = block.Transactions() | ||
blockHash = block.Hash() | ||
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) | ||
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) | ||
results = make([]*txTraceResult, len(txs)) | ||
pend sync.WaitGroup | ||
) | ||
threads := runtime.NumCPU() | ||
if threads > len(txs) { | ||
threads = len(txs) | ||
} | ||
jobs := make(chan *txTraceTask, threads) | ||
blockHash := block.Hash() | ||
for th := 0; th < threads; th++ { | ||
pend.Add(1) | ||
go func() { | ||
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) | ||
defer pend.Done() | ||
// Fetch and execute the next transaction trace tasks | ||
for task := range jobs { | ||
|
@@ -645,7 +690,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac | |
|
||
// Feed the transactions into the tracers and return | ||
var failed error | ||
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) | ||
txloop: | ||
for i, tx := range txs { | ||
// Send the trace task over for execution | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,12 @@ type Tracer interface { | |
Stop(err error) | ||
} | ||
|
||
// JSTracer is implemented by tracers evaluating JS code. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I use this trick to detect JS tracers. It's not very elegant. I thought about adding a Type() method which is more general, or Name(), or something. But not sure realistically where else this logic would be required. |
||
type JSTracer interface { | ||
Tracer | ||
IsJS() bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Funky interface. |
||
} | ||
|
||
type lookupFunc func(string, *Context, json.RawMessage) (Tracer, error) | ||
|
||
var ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick, please add a blank line afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok done