From 13e88030eb432b970355cf3009fb301c204ff0c2 Mon Sep 17 00:00:00 2001 From: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Date: Tue, 29 Oct 2024 02:44:51 +0100 Subject: [PATCH 1/4] e2: don't reopen files when new created (#12514) Cherry pick #12375 into `release/2.60` Co-authored-by: Alex Sharov --- .../freezeblocks/block_snapshots.go | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/turbo/snapshotsync/freezeblocks/block_snapshots.go b/turbo/snapshotsync/freezeblocks/block_snapshots.go index aa31f6077ab..addaace2cac 100644 --- a/turbo/snapshotsync/freezeblocks/block_snapshots.go +++ b/turbo/snapshotsync/freezeblocks/block_snapshots.go @@ -115,7 +115,9 @@ func (s Segment) FileInfo(dir string) snaptype.FileInfo { } func (s *Segment) reopenSeg(dir string) (err error) { - s.closeSeg() + if s.Decompressor != nil { + return nil + } s.Decompressor, err = seg.NewDecompressor(filepath.Join(dir, s.FileName())) if err != nil { return fmt.Errorf("%w, fileName: %s", err, s.FileName()) @@ -160,12 +162,7 @@ func (s *Segment) openFiles() []string { } func (s *Segment) reopenIdxIfNeed(dir string, optimistic bool) (err error) { - if len(s.Type().IdxFileNames(s.version, s.from, s.to)) == 0 { - return nil - } - err = s.reopenIdx(dir) - if err != nil { if !errors.Is(err, os.ErrNotExist) { if optimistic { @@ -180,19 +177,25 @@ func (s *Segment) reopenIdxIfNeed(dir string, optimistic bool) (err error) { } func (s *Segment) reopenIdx(dir string) (err error) { - s.closeIdx() if s.Decompressor == nil { return nil } + for len(s.indexes) < len(s.Type().Indexes()) { + s.indexes = append(s.indexes, nil) + } + + for i, fileName := range s.Type().IdxFileNames(s.version, s.from, s.to) { + if s.indexes[i] != nil { + continue + } - for _, fileName := range s.Type().IdxFileNames(s.version, s.from, s.to) { index, err := recsplit.OpenIndex(filepath.Join(dir, fileName)) if err != nil { return fmt.Errorf("%w, fileName: %s", err, fileName) } - s.indexes = append(s.indexes, index) + s.indexes[i] = index } return nil @@ -2152,6 +2155,7 @@ func (v *View) HeadersSegment(blockNum uint64) (*Segment, bool) { func (v *View) BodiesSegment(blockNum uint64) (*Segment, bool) { return v.Segment(coresnaptype.Bodies, blockNum) } + func (v *View) TxsSegment(blockNum uint64) (*Segment, bool) { return v.Segment(coresnaptype.Transactions, blockNum) } From fa452c52aeb82cf798715ee272210332d09cb359 Mon Sep 17 00:00:00 2001 From: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:06:05 +0100 Subject: [PATCH 2/4] trace API: commit state changes from InitializeBlockExecution (#12559) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this PR in `callManyTransactions` (invoked by `trace_block`) changes made by `InitializeBlockExecution` were discarded, leading to issues like #12432. That was immaterial before since no much was happening at the beginning of a block. But that changed in Dencun with [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) – see `(s *Merge) Initialize`. --- turbo/jsonrpc/trace_adhoc.go | 64 ++++++++++++++++++-------------- turbo/jsonrpc/trace_filtering.go | 34 ++++++++++------- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/turbo/jsonrpc/trace_adhoc.go b/turbo/jsonrpc/trace_adhoc.go index 519437796de..959e5d1b79a 100644 --- a/turbo/jsonrpc/trace_adhoc.go +++ b/turbo/jsonrpc/trace_adhoc.go @@ -1123,17 +1123,33 @@ func (api *TraceAPIImpl) CallMany(ctx context.Context, calls json.RawMessage, pa return nil, fmt.Errorf("convert callParam to msg: %w", err) } } - results, _, err := api.doCallMany(ctx, dbtx, msgs, callParams, parentNrOrHash, nil, true /* gasBailout */, -1 /* all tx indices */, traceConfig) - return results, err + + chainConfig, err := api.chainConfig(ctx, dbtx) + if err != nil { + return nil, err + } + stateReader, err := rpchelper.CreateStateReader(ctx, dbtx, *parentNrOrHash, 0, api.filters, api.stateCache, api.historyV3(dbtx), chainConfig.ChainName) + if err != nil { + return nil, err + } + stateCache := shards.NewStateCache(32, 0 /* no limit */) // this cache living only during current RPC call, but required to store state writes + cachedReader := state.NewCachedReader(stateReader, stateCache) + noop := state.NewNoopWriter() + cachedWriter := state.NewCachedWriter(noop, stateCache) + ibs := state.New(cachedReader) + + return api.doCallMany(ctx, dbtx, stateReader, stateCache, cachedWriter, ibs, + msgs, callParams, parentNrOrHash, nil, true /* gasBailout */, -1 /* all tx indices */, traceConfig) } -func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []types.Message, callParams []TraceCallParam, - parentNrOrHash *rpc.BlockNumberOrHash, header *types.Header, gasBailout bool, txIndexNeeded int, - traceConfig *tracers.TraceConfig, -) ([]*TraceCallResult, *state.IntraBlockState, error) { +func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, stateReader state.StateReader, + stateCache *shards.StateCache, cachedWriter state.StateWriter, ibs *state.IntraBlockState, + msgs []types.Message, callParams []TraceCallParam, parentNrOrHash *rpc.BlockNumberOrHash, header *types.Header, + gasBailout bool, txIndexNeeded int, traceConfig *tracers.TraceConfig, +) ([]*TraceCallResult, error) { chainConfig, err := api.chainConfig(ctx, dbtx) if err != nil { - return nil, nil, err + return nil, err } engine := api.engine() @@ -1143,29 +1159,21 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type } blockNumber, hash, _, err := rpchelper.GetBlockNumber(*parentNrOrHash, dbtx, api.filters) if err != nil { - return nil, nil, err - } - stateReader, err := rpchelper.CreateStateReader(ctx, dbtx, *parentNrOrHash, 0, api.filters, api.stateCache, api.historyV3(dbtx), chainConfig.ChainName) - if err != nil { - return nil, nil, err + return nil, err } - stateCache := shards.NewStateCache(32, 0 /* no limit */) // this cache living only during current RPC call, but required to store state writes - cachedReader := state.NewCachedReader(stateReader, stateCache) noop := state.NewNoopWriter() - cachedWriter := state.NewCachedWriter(noop, stateCache) - ibs := state.New(cachedReader) // TODO: can read here only parent header parentBlock, err := api.blockWithSenders(ctx, dbtx, hash, blockNumber) if err != nil { - return nil, nil, err + return nil, err } if parentBlock == nil { - return nil, nil, fmt.Errorf("parent block %d(%x) not found", blockNumber, hash) + return nil, fmt.Errorf("parent block %d(%x) not found", blockNumber, hash) } parentHeader := parentBlock.Header() if parentHeader == nil { - return nil, nil, fmt.Errorf("parent header %d(%x) not found", blockNumber, hash) + return nil, fmt.Errorf("parent header %d(%x) not found", blockNumber, hash) } // Setup context so it may be cancelled the call has completed @@ -1190,7 +1198,7 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type for txIndex, msg := range msgs { if err := libcommon.Stopped(ctx.Done()); err != nil { - return nil, nil, err + return nil, err } var traceTypeTrace, traceTypeStateDiff, traceTypeVmTrace bool @@ -1204,7 +1212,7 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type case TraceTypeVmTrace: traceTypeVmTrace = true default: - return nil, nil, fmt.Errorf("unrecognized trace type: %s", traceType) + return nil, fmt.Errorf("unrecognized trace type: %s", traceType) } } @@ -1214,7 +1222,7 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type var ot OeTracer ot.config, err = parseOeTracerConfig(traceConfig) if err != nil { - return nil, nil, err + return nil, err } ot.compat = api.compatibility ot.r = traceResult @@ -1287,7 +1295,7 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type execResult, err = core.ApplyMessage(evm, msg, gp, true /* refunds */, gasBailout /* gasBailout */) } if err != nil { - return nil, nil, fmt.Errorf("first run for txIndex %d error: %w", txIndex, err) + return nil, fmt.Errorf("first run for txIndex %d error: %w", txIndex, err) } chainRules := chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Time) @@ -1296,21 +1304,21 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type initialIbs := state.New(cloneReader) if !txFinalized { if err = ibs.FinalizeTx(chainRules, sd); err != nil { - return nil, nil, err + return nil, err } } sd.CompareStates(initialIbs, ibs) if err = ibs.CommitBlock(chainRules, cachedWriter); err != nil { - return nil, nil, err + return nil, err } } else { if !txFinalized { if err = ibs.FinalizeTx(chainRules, noop); err != nil { - return nil, nil, err + return nil, err } } if err = ibs.CommitBlock(chainRules, cachedWriter); err != nil { - return nil, nil, err + return nil, err } } if !traceTypeTrace { @@ -1324,7 +1332,7 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type } } - return results, ibs, nil + return results, nil } // RawTransaction implements trace_rawTransaction. diff --git a/turbo/jsonrpc/trace_filtering.go b/turbo/jsonrpc/trace_filtering.go index 29dd9d22852..b33610fb030 100644 --- a/turbo/jsonrpc/trace_filtering.go +++ b/turbo/jsonrpc/trace_filtering.go @@ -930,23 +930,34 @@ func (api *TraceAPIImpl) callManyTransactions( } callParams := make([]TraceCallParam, 0, len(txs)) - reader, err := rpchelper.CreateHistoryStateReader(dbtx, blockNumber, txIndex, api.historyV3(dbtx), cfg.ChainName) - if err != nil { - return nil, nil, err + + parentHash := block.ParentHash() + parentNrOrHash := rpc.BlockNumberOrHash{ + BlockNumber: &parentNo, + BlockHash: &parentHash, + RequireCanonical: true, } - initialState := state.New(reader) + stateReader, err := rpchelper.CreateStateReader(ctx, dbtx, parentNrOrHash, 0, api.filters, api.stateCache, api.historyV3(dbtx), cfg.ChainName) if err != nil { return nil, nil, err } + stateCache := shards.NewStateCache(32, 0 /* no limit */) // this cache living only during current RPC call, but required to store state writes + cachedReader := state.NewCachedReader(stateReader, stateCache) + noop := state.NewNoopWriter() + cachedWriter := state.NewCachedWriter(noop, stateCache) + ibs := state.New(cachedReader) engine := api.engine() consensusHeaderReader := stagedsync.NewChainReaderImpl(cfg, dbtx, nil, nil) logger := log.New("trace_filtering") - err = core.InitializeBlockExecution(engine.(consensus.Engine), consensusHeaderReader, block.HeaderNoCopy(), cfg, initialState, logger) + err = core.InitializeBlockExecution(engine.(consensus.Engine), consensusHeaderReader, block.HeaderNoCopy(), cfg, ibs, logger) if err != nil { return nil, nil, err } + if err = ibs.CommitBlock(rules, cachedWriter); err != nil { + return nil, nil, err + } msgs := make([]types.Message, len(txs)) for i, tx := range txs { @@ -967,7 +978,7 @@ func (api *TraceAPIImpl) callManyTransactions( // gnosis might have a fee free account here if msg.FeeCap().IsZero() && engine != nil { syscall := func(contract common.Address, data []byte) ([]byte, error) { - return core.SysCallContract(contract, data, cfg, initialState, header, engine, true /* constCall */) + return core.SysCallContract(contract, data, cfg, ibs, header, engine, true /* constCall */) } msg.SetIsFree(engine.IsServiceTransaction(msg.From(), syscall)) } @@ -982,20 +993,15 @@ func (api *TraceAPIImpl) callManyTransactions( msgs[i] = msg } - parentHash := block.ParentHash() - - traces, lastState, cmErr := api.doCallMany(ctx, dbtx, msgs, callParams, &rpc.BlockNumberOrHash{ - BlockNumber: &parentNo, - BlockHash: &parentHash, - RequireCanonical: true, - }, header, gasBailOut /* gasBailout */, txIndex, traceConfig) + traces, cmErr := api.doCallMany(ctx, dbtx, stateReader, stateCache, cachedWriter, ibs, msgs, callParams, + &parentNrOrHash, header, gasBailOut /* gasBailout */, txIndex, traceConfig) if cmErr != nil { return nil, nil, cmErr } syscall := func(contract common.Address, data []byte) ([]byte, error) { - return core.SysCallContract(contract, data, cfg, lastState, header, engine, false /* constCall */) + return core.SysCallContract(contract, data, cfg, ibs, header, engine, false /* constCall */) } return traces, syscall, nil From 679e16b59a7b6856f359c3c1110d957f5fe593e7 Mon Sep 17 00:00:00 2001 From: Michelangelo Riccobene Date: Fri, 1 Nov 2024 06:23:36 +0100 Subject: [PATCH 3/4] qa-tests: handle Erigon2 json rpc api improvements regarding the error reason (#12547) Erigon2 v2.6x add correct **error reason** to some json rpc api responses. Previously, the expected reason for the error was "{}". Affected apis are `debug_traceCall`, `debug_traceCallMany`, `debug_traceTransaction`. This PR uses a new branch of the rpc-tests repo that has been updated with these changes. --- .github/workflows/qa-rpc-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa-rpc-integration-tests.yml b/.github/workflows/qa-rpc-integration-tests.yml index 37be7802e6e..ffa3aecefd4 100644 --- a/.github/workflows/qa-rpc-integration-tests.yml +++ b/.github/workflows/qa-rpc-integration-tests.yml @@ -28,7 +28,7 @@ jobs: - name: Checkout RPC Tests Repository & Install Requirements run: | rm -rf ${{ runner.workspace }}/rpc-tests - git -c advice.detachedHead=false clone --depth 1 --branch v0.52.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests + git -c advice.detachedHead=false clone --depth 1 --branch erigon_v2.6x https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests cd ${{ runner.workspace }}/rpc-tests pip3 install -r requirements.txt From 3afee08bfff043a731485e0a92dd8650823d8884 Mon Sep 17 00:00:00 2001 From: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:35:49 +0100 Subject: [PATCH 4/4] v2.60.10: update changelog & version (#12628) --- ChangeLog.md | 22 ++++++++++++++-------- params/version.go | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 54542b9e8b2..a827d68f56d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,12 +1,18 @@ ChangeLog -## v2.60.10 (in development) +## v2.60.10 -### TODO - -Acknowledgements: - -New features: - -Fixes: +**Bugfixes:** +- Trace API: commit state changes from InitializeBlockExecution @yperbasis in [#12559](https://github.com/erigontech/erigon/pull/12559). +Prior to this PR in `callManyTransactions` (invoked by `trace_block`) +changes made by `InitializeBlockExecution` were discarded. That was immaterial before since no much was +happening at the beginning of a block. But that changed in Dencun with +[EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). +Fixes Issues +[#11871](https://github.com/erigontech/erigon/issues/11871), +[#12092](https://github.com/erigontech/erigon/issues/12092), +[#12242](https://github.com/erigontech/erigon/issues/12242), +[#12432](https://github.com/erigontech/erigon/issues/12432), +[#12473](https://github.com/erigontech/erigon/issues/12473), +and [#12525](https://github.com/erigontech/erigon/issues/12525). diff --git a/params/version.go b/params/version.go index 7bc4b261ff3..4c446f970a5 100644 --- a/params/version.go +++ b/params/version.go @@ -33,7 +33,7 @@ var ( const ( VersionMajor = 2 // Major version component of the current release VersionMinor = 60 // Minor version component of the current release - VersionMicro = 9 // Patch version component of the current release + VersionMicro = 10 // Patch version component of the current release VersionModifier = "" // Modifier component of the current release VersionKeyCreated = "ErigonVersionCreated" VersionKeyFinished = "ErigonVersionFinished"