From c142a59eb68ce813bbde9f8500262988ae707eaa Mon Sep 17 00:00:00 2001 From: HonzaDajc Date: Tue, 31 Oct 2023 11:24:42 +0100 Subject: [PATCH 1/3] Remove parallel procesing for debug_traceBlock Because of preparing data for replaying transaction with EVM which is slower with javascript tracer execution, deep copy of stateDB is created and every transaction is replayed twice. So this is contra productive. --- ethapi/api.go | 71 ++++++++++----------------------------------------- 1 file changed, 14 insertions(+), 57 deletions(-) diff --git a/ethapi/api.go b/ethapi/api.go index 3149c6700..4165a47ac 100644 --- a/ethapi/api.go +++ b/ethapi/api.go @@ -22,9 +22,7 @@ import ( "fmt" "math/big" "math/rand" - "runtime" "strings" - "sync" "time" "github.com/Fantom-foundation/lachesis-base/hash" @@ -2180,6 +2178,9 @@ func (api *PublicDebugAPI) traceTx(ctx context.Context, message evmcore.Message, return nil, fmt.Errorf("tracing failed: %w", err) } + // Finalize the state so any modifications are written to the trie + statedb.Finalise(vmenv.ChainConfig().IsByzantium(vmctx.BlockNumber) || vmenv.ChainConfig().IsEIP158(vmctx.BlockNumber)) + // Depending on the tracer type, format and return the output. switch tracer := tracer.(type) { case *vm.StructLogger: @@ -2222,13 +2223,6 @@ type txTraceResult struct { Error string `json:"error,omitempty"` // Trace failure produced by the tracer } -// txTraceTask represents a single transaction trace task when an entire block -// is being traced. -type txTraceTask struct { - statedb *state.StateDB // Intermediate state prepped for tracing - index int // Transaction offset in the block -} - // TraceBlockByNumber returns the structured logs created during the execution of // EVM and returns them as a JSON object. func (api *PublicDebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) { @@ -2291,64 +2285,27 @@ func (api *PublicDebugAPI) traceBlock(ctx context.Context, block *evmcore.EvmBlo signer = types.MakeSigner(api.b.ChainConfig(), block.Number) txs = block.Transactions results = make([]*txTraceResult, len(txs)) - - pend = new(sync.WaitGroup) - jobs = make(chan *txTraceTask, len(txs)) ) - threads := runtime.NumCPU() - if threads > len(txs) { - threads = len(txs) - } blockHeader := block.Header() blockHash := block.Hash - for th := 0; th < threads; th++ { - pend.Add(1) - go func() { - defer pend.Done() - blockCtx := api.b.GetBlockContext(blockHeader) - - // Fetch and execute the next transaction trace tasks - for task := range jobs { - msg, _ := txs[task.index].AsMessage(signer, block.BaseFee) - txctx := &tracers.Context{ - BlockHash: blockHash, - TxIndex: task.index, - TxHash: txs[task.index].Hash(), - } - res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) - if err != nil { - results[task.index] = &txTraceResult{Error: err.Error()} - continue - } - results[task.index] = &txTraceResult{Result: res} - } - }() - } + // Feed the transactions into the tracers and return blockCtx := api.b.GetBlockContext(blockHeader) - var failed error for i, tx := range txs { - // Send the trace task over for execution - jobs <- &txTraceTask{statedb: statedb.Copy(), index: i} - // Generate the next state snapshot fast without tracing + txctx := &tracers.Context{ + BlockHash: blockHash, + TxIndex: i, + TxHash: txs[i].Hash(), + } msg, _ := tx.AsMessage(signer, block.BaseFee) - statedb.Prepare(tx.Hash(), i) - vmenv := vm.NewEVM(blockCtx, evmcore.NewEVMTxContext(msg), statedb, api.b.ChainConfig(), opera.DefaultVMConfig) - if _, err := evmcore.ApplyMessage(vmenv, msg, new(evmcore.GasPool).AddGas(msg.Gas())); err != nil { - failed = err - break + res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) + if err != nil { + results[i] = &txTraceResult{Error: err.Error()} + continue } - // Finalize the state so any modifications are written to the trie - statedb.Finalise(vmenv.ChainConfig().IsByzantium(block.Number) || vmenv.ChainConfig().IsEIP158(block.Number)) - } - close(jobs) - pend.Wait() - - // If execution failed in between, abort - if failed != nil { - return nil, failed + results[i] = &txTraceResult{Result: res} } return results, nil } From 95c6da086d421632d8941692ca1059ebc39f7936 Mon Sep 17 00:00:00 2001 From: HonzaDajc Date: Tue, 31 Oct 2023 11:36:45 +0100 Subject: [PATCH 2/3] Change creation of tx message to cover internal tx --- ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethapi/api.go b/ethapi/api.go index 4165a47ac..3df11fa9c 100644 --- a/ethapi/api.go +++ b/ethapi/api.go @@ -2299,7 +2299,7 @@ func (api *PublicDebugAPI) traceBlock(ctx context.Context, block *evmcore.EvmBlo TxIndex: i, TxHash: txs[i].Hash(), } - msg, _ := tx.AsMessage(signer, block.BaseFee) + msg, _ := evmcore.TxAsMessage(tx, signer, block.BaseFee) res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) if err != nil { results[i] = &txTraceResult{Error: err.Error()} @@ -2329,7 +2329,7 @@ func (api *PublicDebugAPI) stateAtTransaction(ctx context.Context, block *evmcor signer := gsignercache.Wrap(types.MakeSigner(api.b.ChainConfig(), block.Number)) for idx, tx := range block.Transactions { // Assemble the transaction call message and return if the requested offset - msg, _ := tx.AsMessage(signer, block.BaseFee) + msg, _ := evmcore.TxAsMessage(tx, signer, block.BaseFee) txContext := evmcore.NewEVMTxContext(msg) context := api.b.GetBlockContext(block.Header()) if idx == txIndex { From d6ccc6ee8845a9a855252bdc4ed02027ee400765 Mon Sep 17 00:00:00 2001 From: HonzaDajc Date: Tue, 31 Oct 2023 12:22:21 +0100 Subject: [PATCH 3/3] Use signer cache wrapper to get signer --- ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethapi/api.go b/ethapi/api.go index 3df11fa9c..45ea9a76f 100644 --- a/ethapi/api.go +++ b/ethapi/api.go @@ -2282,7 +2282,7 @@ func (api *PublicDebugAPI) traceBlock(ctx context.Context, block *evmcore.EvmBlo } // Execute all the transaction contained within the block concurrently var ( - signer = types.MakeSigner(api.b.ChainConfig(), block.Number) + signer = gsignercache.Wrap(types.MakeSigner(api.b.ChainConfig(), block.Number)) txs = block.Transactions results = make([]*txTraceResult, len(txs)) )