bal-devnet-7_warmup: refresh onto bal-devnet-7 (pulls in deep-storage-fold fix #21945) - #22129
Merged
AskAlexSharov merged 89 commits intoJul 1, 2026
Merged
Conversation
…Fulu+ (#21842) ## Problem `block_importing_latency` (Caplin) reads a **flat 0 for hours** in Grafana — it's effectively never recorded. It's a gauge set only by `ObserveBlockImportingLatency`, whose **only** caller (`collectOnBlockLatencyToUnixTime`) was nested inside the **Deneb-only blob data-availability branch** of `OnBlock`, behind: `checkDataAvaiability && BlobKzgCommitments.Len() > 0 && !elHasBlobs && version is Deneb/Electra (not Fulu) && highestSeen < slot`. Two of those gates kill it: - **Fulu+** (current mainnet) takes the Fulu/PeerDAS branch, which never calls it → the gauge stays at its `0` default. This is the flat line. - Even pre-Fulu it only fired for a current-slot block carrying blobs the EL didn't already have — a rare race at tip — and skipped blob-less blocks entirely. So the panel value is not a real "0 ms"; the setter just isn't reached. ## Fix Move the single call to the **fork-agnostic `highestSeen` tip-advance** in `OnBlock`, which runs for every new head block on all forks (Fulu/Gloas included). The helper's existing `slot == GetCurrentSlot()` guard still skips backfill/sync blocks, so the gauge measures head-arrival latency rather than block age. ```go if block.Block.Slot > f.highestSeen.Load() { f.highestSeen.Store(block.Block.Slot) f.highestSeenRoot.Store(common.Hash(blockRoot)) collectOnBlockLatencyToUnixTime(f.ethClock, block.Block.Slot) // fork-agnostic } ``` Net effect: `block_importing_latency` now populates every slot the node imports a current-slot head block, on all forks. ## Tests `TestCollectOnBlockLatency` covers the helper's contract (records for a current-slot block, skips a past/backfill slot). This change is a one-call relocation — the emitting helper itself is unchanged. A full cross-fork `OnBlock` integration test was intentionally not added, as exercising it requires substantial fork-choice/engine/PeerDAS scaffolding to make a test block "current"; flagging per the repo's TDD-pragmatism guidance. `make lint` and `make erigon` clean. ## Scope Affects `release/3.4`, `release/3.5`, and `main` (the call placement is identical on all three). Will cherry-pick to the release branches. --------- Co-authored-by: kewei <kewei.train@gmail.com>
…#21252) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 3.1.1 to 3.2.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's releases</a>.</em></p> <blockquote> <h2>v3.2.0</h2> <h2><a href="https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0">3.2.0</a> (2026-05-12)</h2> <h3>Features</h3> <ul> <li>add support for enterprise-level GitHub Apps (<a href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>) (<a href="https://github.com/actions/create-github-app-token/commit/952a2a7073df6bfa5f49bc469ec895b6ec1acea4">952a2a7</a>)</li> <li>support full repository names in <code>repositories</code> input (<a href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>) (<a href="https://github.com/actions/create-github-app-token/commit/85eb8dd41472213aed25d1a126460e0069138ab6">85eb8dd</a>)</li> </ul> <h3>Bug Fixes</h3> <ul> <li><strong>deps:</strong> bump <code>@actions/core</code> from 3.0.0 to 3.0.1 in the production-dependencies group (<a href="https://redirect.github.com/actions/create-github-app-token/issues/364">#364</a>) (<a href="https://github.com/actions/create-github-app-token/commit/43e5c345bfd4d4f3ecea019ad0042001a09dd857">43e5c34</a>)</li> <li>validate private-key input (<a href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>) (<a href="https://github.com/actions/create-github-app-token/commit/f24bbd89643991c0de27ae823c01791b2c6bafdd">f24bbd8</a>)</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/actions/create-github-app-token/blob/main/CHANGELOG.md">actions/create-github-app-token's changelog</a>.</em></p> <blockquote> <h1>Changelog</h1> <h2><a href="https://github.com/actions/create-github-app-token/compare/v3.1.1...v3.2.0">3.2.0</a> (2026-05-12)</h2> <h3>Features</h3> <ul> <li>add support for enterprise-level GitHub Apps (<a href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>) (<a href="https://github.com/actions/create-github-app-token/commit/952a2a7073df6bfa5f49bc469ec895b6ec1acea4">952a2a7</a>)</li> <li>support full repository names in <code>repositories</code> input (<a href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>) (<a href="https://github.com/actions/create-github-app-token/commit/85eb8dd41472213aed25d1a126460e0069138ab6">85eb8dd</a>)</li> </ul> <h3>Bug Fixes</h3> <ul> <li><strong>deps:</strong> bump <code>@actions/core</code> from 3.0.0 to 3.0.1 in the production-dependencies group (<a href="https://redirect.github.com/actions/create-github-app-token/issues/364">#364</a>) (<a href="https://github.com/actions/create-github-app-token/commit/43e5c345bfd4d4f3ecea019ad0042001a09dd857">43e5c34</a>)</li> <li>validate private-key input (<a href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>) (<a href="https://github.com/actions/create-github-app-token/commit/f24bbd89643991c0de27ae823c01791b2c6bafdd">f24bbd8</a>)</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/actions/create-github-app-token/commit/bcd2ba49218906704ab6c1aa796996da409d3eb1"><code>bcd2ba4</code></a> chore(main): release 3.2.0 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/370">#370</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/f24bbd89643991c0de27ae823c01791b2c6bafdd"><code>f24bbd8</code></a> fix: validate private-key input (<a href="https://redirect.github.com/actions/create-github-app-token/issues/376">#376</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/363531b6d972a60a00b3f1e6bb139e5e6c764cd9"><code>363531b</code></a> docs: capitalize Git as a proper noun in README (<a href="https://redirect.github.com/actions/create-github-app-token/issues/374">#374</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/fd2801133e469d2950f2c5af5e591d6b2ad833c8"><code>fd28011</code></a> docs: update procedure to configure Git (<a href="https://redirect.github.com/actions/create-github-app-token/issues/287">#287</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/85eb8dd41472213aed25d1a126460e0069138ab6"><code>85eb8dd</code></a> feat: support full repository names in <code>repositories</code> input (<a href="https://redirect.github.com/actions/create-github-app-token/issues/372">#372</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/c9aabb83728c3bd519212fa657ebc07e1f2a5dec"><code>c9aabb8</code></a> build(deps-dev): bump yaml from 2.8.3 to 2.8.4 in the development-dependencie...</li> <li><a href="https://github.com/actions/create-github-app-token/commit/e02e816e5591415258a53bf735aff57977dcd5e2"><code>e02e816</code></a> build(deps-dev): bump undici from 7.24.6 to 8.2.0 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/366">#366</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/8d835bfd37aa48fcb8e709925115857568d98bc4"><code>8d835bf</code></a> build(deps-dev): bump esbuild from 0.27.4 to 0.28.0 in the development-depend...</li> <li><a href="https://github.com/actions/create-github-app-token/commit/952a2a7073df6bfa5f49bc469ec895b6ec1acea4"><code>952a2a7</code></a> feat: add support for enterprise-level GitHub Apps (<a href="https://redirect.github.com/actions/create-github-app-token/issues/263">#263</a>)</li> <li><a href="https://github.com/actions/create-github-app-token/commit/43e5c345bfd4d4f3ecea019ad0042001a09dd857"><code>43e5c34</code></a> fix(deps): bump <code>@actions/core</code> from 3.0.0 to 3.0.1 in the production-dependenc...</li> <li>Additional commits viewable in <a href="https://github.com/actions/create-github-app-token/compare/1b10c78c7865c340bc4f6099eb2f838309f1e8c3...bcd2ba49218906704ab6c1aa796996da409d3eb1">compare view</a></li> </ul> </details> <br /> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Co-authored-by: lystopad <oleksandr.lystopad@erigon.tech>
`Signal()` was called without holding `queueMutex`, creating a window where the signal fires after the inner goroutine checked `waitCtx.Err() == nil` but before it called `queueCond.Wait()`. The signal is silently consumed and the inner goroutine blocks forever — manifesting as `TestTipEventsNewBlockHashesEmitsEvent` timing out after 1h in CI. Fix: acquire the mutex before `Signal()`. `sync.Cond.Signal` does not require the mutex, but calling it under the lock prevents the race: the outer goroutine blocks until the inner is either inside `Wait()` (where it will be woken up) or has already exited the loop.
…#21774) ## Summary - `request_generator.go`: replace `base64.StdEncoding.EncodeToString` with `hexutil.Encode` for the `start` parameter — the server expects a `0x`-prefixed hex string, not base64 - `bench1.go`, `bench3.go`, `bench9.go`, `account_range_verify.go`: replace the initial page cursor from `common.Hash{}[:]` (32 bytes, rejected by the server) to `common.Address{}[:]` (20 bytes) - `request_generator_test.go`: update test cases to use 20-byte addresses and hex-encoded expected strings ## Test plan - [ ] `go test ./cmd/rpctest/rpctest/... -run TestRequestGenerator_accountRange` passes - [ ] `go test ./rpc/jsonrpc/... -run TestAccountRange` passes - [ ] `make lint` clean
This is **PR #1 of a 3-PR perf stack**. It consolidates state caching across all modes — sync, tip-tracking, integration and testing — so the state cache is either **on and completely trustworthy**, or **off to measure** — never off because it unexpectedly breaks things. The caches (the account/storage `StateCache` and the commitment `BranchCache`) are an **internal implementation detail of `SharedDomains`**. No external entity accesses or mutates them directly: callers drive state through `Flush` / `Commit` / `GetLatest` / `DomainPut`, and the full cache lifecycle (population, invalidation, commit-gating) is owned inside `SharedDomains`. ## What this PR contains ### `BranchCache` — single aggregator-scope commitment cache - Aggregator-lifetime cache: pinned root slot + bounded LRU tail, behind the `sd.mem` chain so unwinds and fork-validations see consistent state. - Wired into the trie read + encoder write paths. - Tx-precise unwind invalidation: entries are stamped with their per-key write `txNum`; `sd.Unwind` evicts everything above the unwind watermark (`BranchCache.UnwindTo`). ### One switch for all caches The `BranchCache` is a *type of* state cache, so it rides the existing `USE_STATE_CACHE` toggle rather than getting its own env. One operator switch turns **all** caching off — the relevant operation when bisecting a state-root mismatch, where an operator shouldn't have to reason about the interaction of several independent caches. (This is a deliberate deviation from the review's "add a separate `BranchCache` kill-switch" suggestion — flagged for confirmation.) ### The BranchCache reflects only committed state — by construction The BranchCache can never hold a value a failed commit rolled back: `SharedDomains.Commit` flushes the in-memory batch into the tx, commits, and **only then** applies the flushed commitment branches to the cache (the flush is implicit in committing; a failed commit applies nothing). Plain `Flush` — callers that own their own commit, e.g. offline tools — never touches the cache; read-through populates from committed files. The caches are an internal detail of `SharedDomains`; nothing else writes to them. > **StateCache no-poisoning is #21386, not this PR.** Unlike the BranchCache, the account/storage StateCache is an *in-flight, cross-transaction* cache — it holds prior txs' not-yet-committed writes within a batch, and later txs read them from it. So it can't be made commit-safe by simply invalidating on write (that breaks cross-tx reads in serial exec). Its no-poisoning is the txNum/epoch rework in #21386; this PR keeps its existing ValidateAndPrepare/unwind invalidation. ### BUG #21138 — parallel-exec from-0 wrong trie root `ResetExec` wipes the commitment DB table; the aggregator's in-memory `BranchCache` could still reference the just-deleted trie nodes, so a from-0 re-exec served stale entries when computing block 0's commitment → wrong root, dropping genesis-allocated balances no later block touched (mainnet block 46147, `0xA1E4380A3B1f749673E270229993eE55F35663b4`). Fix: `ResetExec` clears the aggregator's `BranchCache`. `TestFromZero_GenesisAllocPreservedAfterResetReExec` passes on current `main`; the test's value here is keeping *this PR's* cache safe across reset, not fixing a live `main` bug. ## Follow-ups (the rest of the stack) - **#21386 (PR #2 of the stack) — StateCache LRU + Mode rework:** consistency + no performance drop-off at a 1 GB cache for long-running nodes; re-adds the warm StateCache repopulation deferred above, under its `txNum`/`epoch` model. - **Pinning** (the stack's third step) — **no PR yet**; in progress and under test on branch [`mh/branch-cache-trunk-pin`](https://github.com/erigontech/erigon/tree/mh/branch-cache-trunk-pin), to be **re-benchmarked before merge**. - **#21739** — interface-unification follow-up: collapse the duck-typed `GetLatest` variants into a single metered, `txNum`-returning `GetLatest`. ## Testing Behaves identically across parallel and serial exec — confirmed in CI across both exec modes. Unit coverage for the BranchCache (tiers, tx-precise `UnwindTo`, commit-gated population) plus the engine/exec-module FCU commit paths. Given today's changes (the commit-gating of both caches), we will do another A/B performance run before merging. --------- Co-authored-by: Mark Holt <erigon@dev-bm-e3-ethmainnet-n4.erigon.io> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## What `erigon seg rm-state --step` now accepts an `N+` form meaning "from step N to the latest available step": - `--step 5+` — remove everything from step 5 to the latest - `--step 5-10` — unchanged Previously the only way to express "from step N to the end" was an arbitrarily large upper bound like `--step 5-9999999`. ## How The `--step` parsing is extracted into `parseStepRange(stepRange, maxAvailableStep)`. For the `N+` form it parses the prefix as `from` and sets `to` to the highest `toStep` among the state files already scanned by `DeleteStateSnapshots` (respecting any `--domain` filter). The `from-to` form is unchanged. Only the range parsing changed — the file-removal logic is untouched. ## Tests - `Test_parseStepRange` — table-driven unit test covering both formats and error cases (empty, `+` only, bad prefix, non-numeric). - `Test_DeleteStateSnaps_StepRange_FromPlus` — end-to-end: `192+` removes the `192-224` merged file plus its sub-ranges and keeps `0-128` / `128-192`, identical to `192-224` since 224 is the highest step. `make lint` clean; `go test ./cmd/utils/app/` passing. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…ng round-trip failure (#21839) ## Summary - Fixes FuzzRLP encode-decode round-trip failure for nested RLP lists (input `c2c23030` decoded and re-encoded as `c0`) - Root cause: `Stream.Kind()` read `listLimit` before `readKind()` consumed header bytes via `willRead()`, leaving a stale (too-large) limit that masked `ErrElemTooLarge` checks - Fix: re-read `listLimit` after `readKind()` so the size check uses the correct post-consumption remaining bytes ## Test plan - [x] `go test -run=FuzzRLP/29859ba08ac1b7a2 ./execution/types/` passes - [x] `go test -count=3 -race ./execution/types/...` passes all 3 runs - [x] `go build ./...` compiles without errors - [x] No test files modified Co-authored-by: erigon-copilot[bot] <erigon-copilot[bot]@users.noreply.github.com> Co-authored-by: Giulio Rebuffo <giulio.rebuffo@gmail.com>
## Summary Fixes the data column sidecar miss path so expected misses no longer produce noisy download logs, while keeping the wire behavior compatible with peers that signal an empty multi-chunk response by closing without a response code. Closes #21670 ## Details - Return structured req/resp `resource unavailable` responses for by-root misses and valid pre-Fulu by-root requests, while validating malformed pre-Fulu by-root requests first so they return `invalid request`. - Restore by-range empty-success responses to a zero-byte close, including zero-count, all-pre-Fulu, all-future, and missing-sidecar ranges. - In the httpreqresp client bridge, synthesize success code 0 with an empty body when a negotiated multi-chunk protocol returns `io.EOF` before any response-code byte. Single-chunk EOFs, partial reads, and stream errors still surface as HTTP 400. - Keep handler `responseErr` propagation for real storage/write errors. Across the Sentinel HTTP/gRPC boundary those transport failures can still be flattened by gRPC, while structured peer response codes are surfaced as typed `PeerResponseError` values. - Bound peer error-message decoding to a 10-byte varint prefix and a 256-byte decoded message. - Downgrade expected data column sidecar misses to trace while keeping other download errors at debug. ## Validation - `go test ./cl/sentinel/httpreqresp ./cl/sentinel/service ./cl/sentinel/handlers ./cl/das -count=1` - `make lint`
…21861) ## Problem `PruneAncientBlocks` calls `rawdb.PruneBlocks(tx, canDeleteTo, 1)` in a loop up to `limit` times — and `limit` is **10,000** during the initial sync cycle. Each call: - opens a fresh `kv.Headers` cursor (one Go-heap cursor allocation per pruned block), and - allocates an 8-byte seek key via `hexutil.EncodeTs(1)`. Inside the loop body, `common.Copy(k)` and `make([]byte, 8)` allocate **once per pruned block** — tens of millions of allocations over a full initial sync, independent of call count. ## Change - **`db/rawdb` (`PruneBlocks`)**: reuse a single `keyBuf` for the four point-deletes (instead of `common.Copy(k)` per block), hoist `txIDBytes` above the loop, and replace `EncodeTs(1)` with a local seek buffer. The loop body now allocates **0 per pruned block**. - **`snapshotsync/freezeblocks` (`PruneAncientBlocks`)**: batch up to `pruneBlocksBatch` (1000) blocks per `PruneBlocks`/`PruneHeimdall` call (one cursor + one seek per batch), with an early `!progressed` break so it stops as soon as there's nothing left rather than spinning to `limit`. `timeout` is still checked between batches. `canDeleteTo` is fixed for the duration of the call, so batching deletes exactly the same `[blockFrom, min(canDeleteTo, blockFrom+N))` range the per-block loop did. ## Effect (initial cycle, limit=10000) - cursor opens + per-call seek/`EncodeTs` allocs: ~10,000 → ~10 per `PruneAncientBlocks` call - per-block allocations during pruning: ~2/block → 0/block ## Status WIP — wiring up an allocation benchmark to quantify the win.
based on: #21777 - `.bt` file format change - backwards compatible In PR: - reduce .Build() RAM usage by building `ef_offsets` eagerly off-heap and streaming `nodes` straight to the file (no big in-mem structs) - Add `M` inside file metadata - Removed `di` from file (node `i` has `di = i*M`, recomputed on read) - metadata stored in `Footer` of file - only the `EF` section is 4kb-aligned (for mmap/SIMD-friendly reads); `nodes` are byte-parsed, so left unaligned; footer is 8-byte aligned - completely removed `ETL` usage: because now `AddKey()` can write directly to file, also `Footer` written at the end (when all required fields calculated). - but keep 1 leading byte - just for legacy format detection ----- I realized that for building `.bt` we don't really need ETL (keys already always sorted, keys_count we know from decompressor, etc...). And I realized more - maybe other places in Erigon also can be more streaming-friendly (can build without ETL - in 1-pass). To generalize idea we need move "header metadata" to "footer" - then if metadata storing `keys_count` we can write it at the end: - Store metadata at `Footer`: wins at write-once by append-only use-cases. - Store metadata at `Header`: wins at forward-stream consumers (sockets, tar to tape), mutable page-addressed files (SQLite, Postgres, InnoDB — when mutate/extend file Footer will change its offset). `Footer` style file `.bt`: ``` [ leading_byte:u8 ] # 1 byte: legacy-format detection [ nodes: (key_len:u16 | key)* ] # variable length. unaligned (byte-parsed) [ EF: elias-fano of all key offsets ] # variable length. 4kb-aligned [ footer: keys_count:u64 | M:u64 | ef_offset:u64 ] # 24 bytes. 8-byte-aligned [ ANCHOR: footer_len:u32 | flags:u16 | format_version:u16 | magic:u64 ] # 16 bytes. Fixed length ``` Build such files will be much more streaming-style-friendly. Don't need `etl` all incoming keys only to calculate `keys_count` (like we do now in `.bt`). On file open: - Validate the `magic` first (right format + not truncated) -> fail-fast. Not u16 - because probability of collision is high. - `format_version` is next to the `magic` - then it will allow change ANCHOR format/len in the future. (yes, exactly in our case: EF inside .bt requires to know key_count in advance - but we already have it - and maybe in future we can change it). Also `Footer` allowing easy to add `checksum` to metadata fields in future, etc...
…ecution unwind (#21848) Forward-port of #21847 to `main` (which carries #21825). Same change as #21847: in `UnwindExecutionStage`, prune the in-RAM overlay to the **committed** boundary (`Min(s.BlockNumber+1)`) on the no-op-disk-unwind path instead of `Min(u.UnwindPoint+1)`, and restructure into an explicit `disk-unwind` / `overlay-only` `if`/`else` with a shared tail. See #21847 for the full rationale (yperbasis #1 boundary, AskAlexSharov structure, yperbasis #2 state-cache note). ## main-specific adaptation (and a latent bug this surfaced) `main`'s disk-unwind path calls `doms.ResetPendingUpdates()` (discards deferred commitment updates from the failed execution — `release/3.4` has no such call). The pre-refactor `u.UnwindPoint >= s.BlockNumber` **early return skipped it** — exactly the "the early return skips important biz-logic" failure mode @AskAlexSharov flagged. The restructure **hoists `ResetPendingUpdates()` ahead of the branch so it runs on both paths**, so a block that failed its gas check mid-batch no longer leaks deferred commitment updates into the re-execution. The test file is `main`-only here (the release/3.4 `TestFindExecutedDiffsetAtHeight…` test was never forward-ported), and `common.Address`/`common.Hash` are raw arrays on `main`, so the test slices them with `[:]`. ## Verification on main + this patch - red→green: with the merged `Min(u.UnwindPoint+1)` boundary the test fails (the `(committed, unwindPoint]` write `0x1122` survives); with this PR it passes. - `go build ./execution/stagedsync/...` — clean - `go test ./execution/stagedsync/ -run TestUnwindExecutionStage_PrunesUncommittedOverlayWrite` — pass - `gofmt` / `golangci-lint run ./execution/stagedsync/` — 0 issues Relates to #21681. Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: JkLondon <me@ilyamikheev.com> Co-authored-by: Claude <noreply@anthropic.com>
…ts in execution witness (#21854) Fixes #21810. `debug_executionWitness` omitted the exclusion proof for a storage slot read during a block that resolves to zero, when the slot's path diverges at a folded extension. The diverging extension was emitted with a bare hash child, so a strict stateless verifier cannot descend it to prove the slot absent. Erigon's own stateless verifier accepts such a witness, which is why this went unnoticed. ## Fix Materialize the branch behind the extension in `toWitnessTrie` (`witnessMaterializeBranch`). The branch hashes to the same value, so the witness root is unchanged — the witness just carries the previously-missing branch node, guarded by a `subRoot == cell.hash` check. ## Test `Test_WitnessTrie_GenerateWitness/AbsentStorageSlotDivergingAtFoldedExtension` builds a storage trie with an extension and witnesses an absent slot diverging inside it. A strict sparse-trie walk over the witness rejects it before the fix and accepts it after. ## Validation Verified on mainnet blocks 25302399 (the one in the issue), 25302398/400, 25310000, 25315000, 25320000: the witness now passes external stateless validation. Witness node count for 25302399: 10789 -> 10806; commitment root unchanged.
…ng trie root regression (#21867) **[SharovBot]** ## Summary Reverts the `listLimit` re-read introduced in #21839 (cecf3ad) which caused `invalid block: wrong trie root` regressions across all CI stage-exec-test jobs. ## Root cause of regression After `readKind()` calls `willRead()` to consume the 1-byte type header, `listLimit` drops by 1. The re-read then compares the declared element `s.size` against `(original - 1 byte)`, causing the `ErrElemTooLarge` guard to fire spuriously for elements that exactly fill the remaining list space. This aborted block execution with corrupted state and produced wrong trie roots. ## Failing CI jobs (commit cecf3ad) - `stage-exec-test (from-0, serial)` — `invalid block: wrong trie root, block=513814` - `stage-exec-test (from-0, parallel)` — `invalid block: wrong trie root, block=263641` - `stage-exec-test (resume-nonchaintip, serial)` — `invalid block: wrong trie root, block=25314648` - `RPC Integration Tests - nethermind` — `eth_call` diff mismatches on all test cases ## Fix Revert `decode.go` to read `listLimit` before `readKind()` (original behaviour). The pre-`readKind()` read is correct: the `ErrElemTooLarge` guard compares the *declared* element size against the *available* space before any consumption. The fuzz corpus entry (`29859ba08ac1b7a2`) is kept so the edge case is preserved for future investigation. ## Test plan - [x] `go build ./...` passes - [x] `go test -count=3 -race ./execution/rlp/... ./execution/types/...` passes all 3 runs - [x] No test files modified Closes regression introduced by #21839. Co-authored-by: erigon-copilot[bot] <erigon-copilot[bot]@users.noreply.github.com> Co-authored-by: Giulio Rebuffo <giulio.rebuffo@gmail.com>
… fence tags (#21841) Weekly docs maintenance (w25) — prose-quality pass on `main`. Doc-only, no code touched. Companion to #21840 (same fixes on `release/3.4`, per the dual-commit rule), plus two `main`-only fence fixes for pages that don't exist on `release/3.4`. ### Changes - **docker-compose.md** — "shared between **erigon** and RPC Daemon" → **Erigon** (mid-sentence proper noun). - **tls-authentication.md**, **installation/index.mdx** — "RPC daemon" → **RPC Daemon** (prose form of the module name). - **how-to-run-a-polygon-node.md** — fix a mashed flag value: `--bor.heimdall=https://heimdall-api.polygon.technologyspecifies` → `…polygon.technology`. - **ethereum-with-an-external-cl.mdx** — expand **EL** → **Execution Layer (EL)** on first use. - **architecture.md**, **database.md** (`main`-only) — tag untyped code fences as ` ```text ` (Block-STM pipeline diagram, datadir tree). - Regenerated `llms.txt` / `llms-full.txt` bundles to match. ### Verification - `npm run build` (Docusaurus, `onBrokenLinks: 'throw'`) — green. - `generate-llms.py --check` — OK (4 bundles match, 74 pages). - Editorial-artifact scan — clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Bloxster <gianni.morselli@erigon.tech> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com>
… (#21871) Cherry-pick of #21830 to `main`. Switch `RecSplit.bucketCollector` from `LargeSortableBuffers` to `SmallSortableBuffers` to reduce peak memory usage during `.bt` index builds. The original squash diff also added an unused `newIndexFromMemory` helper that depends on the `Index.readers` `sync.Pool` field present only on the `performance` branch; it is omitted here so the change builds on `main`.
…y, no reflection) (#21858) On Bloatnet i noticed "GC stop-the-world spike" The win is from **not using `[]any` casting and not using reflection**: - the old `Hash()` built a `[]any{...}` of the tx fields (slice alloc + boxing each `uint64`/pointer into an interface), then - handed it to the **reflection-based** `rlp.Encode`, which walks the values dynamically and allocates as it goes. ### Applied to `LegacyTx`, `AccessListTx`, `DynamicFeeTransaction`, `BlobTx`, `SetCodeTransaction`, `AccountAbstractionTransaction` — every tx type that already has an `encodePayload`. ### Results (`BenchmarkTxHash`, M4 Max — allocs/op) | type | before | after | |---|---|---| | legacy | 8 | 1 | | accesslist | 9 | 1 | | dynamicfee | 9 | 1 | | blob | 10 | 1 | | setcode | 22 | 1 | | aa | 13 | 1 | ### Two behavioral notes - **`BlobTx.encodePayload`** previously dereferenced `To` unconditionally (it had a non-nil-`To` precondition enforced by the `ErrNilToFieldTx` guards in `MarshalBinary`/`EncodeRLP`). It now encodes `To` via `EncodeOptionalAddress` — **byte-identical** for the always-present `To` of a valid blob tx, and consistent with its own `payloadSize` (which already sizes `To` optionally). `MarshalBinary`/`EncodeRLP` keep their `ErrNilToFieldTx` guards, so their external contract is unchanged. - **`AccountAbstractionTransaction`'s hash value changes.** Its old `[]any` path encoded `SenderAddress` (`accounts.Address` = `unique.Handle`, which has unexported fields) through reflection, which silently **dropped the sender from the hash**. `Hash()` now goes through `encodePayload` and equals `keccak256` of the canonical `MarshalBinary` bytes. AA (RIP-7560) is not live, so this is a latent-bug fix rather than a consensus change.
…e GLOAS head (#21694) ## Summary Compute the GLOAS fork-choice head (`getHeadGloas`) from the incremental `indexedWeightStore` instead of the full-scan `weightStore`. The index is maintained on every GLOAS attestation (see #21698) but was not previously read for head selection. Because that maintenance is GLOAS-gated, the index is cold at the pre-GLOAS→GLOAS transition; `getHeadGloas` seeds it from `latestMessages` on first use so it is not missing votes cast before activation. **Scoped to GLOAS only — pre-GLOAS fork choice is unchanged.** ## Changes - `getHeadGloas` scores via `headWeightStore(cs)` (the index), fetching the justified checkpoint state before acquiring `f.mu` (a nil state degrades to zero attestation weight, as before — same pattern as pre-GLOAS `getHead`). - `indexedWeightStore` is now **structural**: it stores only `(validator, slot, payloadPresent)` per target root and reads balance + active/slashed status **fresh** from the per-query justified checkpoint state in `GetAttestationScore`, instead of caching balances that go stale when the checkpoint advances. `IndexVote` no longer does a per-vote `getCheckpointState` lookup. - `RemoveVote` is now **allocation-free** (in-place compaction). It runs per attestation on the GLOAS vote path, so the previous fresh-slice-per-call was a CPU/GC hotspot under the fork-choice lock on high-validator-count networks. - `onNewFinalized` drops indexed votes for finalized-away roots. - On the first `getHeadGloas`, `headWeightStore` seeds the index once from the full `latestMessages` snapshot (`seedFromLatestMessages`, clear-then-rebuild). Index maintenance only begins at GLOAS activation, so without the seed the head would undercount attestation weight at the transition until validators re-attest. - Removed dead index API: the unused `GetIndexedWeightStore` accessor, `GetWeightStore` (orphaned once `getHeadGloas` switched to `headWeightStore`; `NewWeightStore` stays for `isHeadWeak`), `Invalidate` (cleared votes but left `seeded` set, so any future caller would silently undercount weights), and the write-only `version` counter. ## Testing - `TestIndexedWeightStoreMatchesFullScan`: starts from a **cold** index, has `headWeightStore` seed it, then asserts it returns the same `GetWeight` / `GetAttestationScore` as the trusted full-scan `weightStore` for every node in the filtered tree (non-vacuous) — exercising the real seed path. - `TestSeedFromLatestMessagesIsIdempotent`: the seed mirrors `latestMessages` once and is a no-op thereafter (no double-counting). - `TestRemoveVoteCompactsInPlace`: removal keeps the other voters and drops the root once empty. - `TestPruneFinalizedDropsFinalizedAndUnknownRoots`: votes targeting roots at or below the finalized slot, or missing from the fork graph, are dropped; votes for live roots above it survive. - `TestOnNewFinalizedPrunesIndexedVotes`: the `onNewFinalized` wiring empties the index once finalization passes every indexed root. Both pruning tests were mutation-checked: they fail against a no-op `pruneFinalized`. - Existing fork-choice tests and #21698's GLOAS/pre-GLOAS maintenance tests pass; `go test ./cl/phase1/forkchoice/...` and scoped `golangci-lint` clean. ## Follow-up The indexed store and its transition seed are superseded by the delta-propagation rework tracked in #21704 (the canonical proto-array model both Prysm and Lighthouse ship). --------- Co-authored-by: noop <noop@noop> Co-authored-by: kewei <kewei.train@gmail.com>
… input (#21877) Fixes an OSS-Fuzz report (issue 525088104, target `fuzz_ef32_double`, crash type Overwrites-const-input). The EliasFano fuzzers grew the input with `in = append(in, in...)`. The fuzzing engine passes the input as a read-only buffer (often with spare capacity), so the first append could write into it — ASAN flags this as "Overwrites-const-input". Cloning the input with `bytes.Clone` before growing keeps all appends on our own buffer. Applied to all four EliasFano fuzzers (ef16/ef32 × single/double), which share the pattern. **Scope:** fuzz-target only. The EliasFano implementation is unaffected (it decodes freshly-allocated cumKeys/position slices, not the input), so there is no runtime/consensus impact and nothing ships in any released binary.
…21862) ## What `erigon seg ls` now works even when chaindata is unavailable (e.g. snapshot-only datadirs, cold storage, post-mortem analysis). ## How One `doLS` path with graceful degradation — no branching into two code paths: - `tryOpenChaindata` replaces panicking `MustOpen()`, returns nil if chaindata missing/locked - Block + bor snaps opened directly from filesystem (always works) - State aggregator opened via new `tryOpenAgg` — skipped with a log message if unavailable (e.g. no salt files) - Caplin snaps only opened when chain name is known - `openAgg` refactored into panic wrapper over `tryOpenAgg` — existing callers unchanged ## Test `TestSegLS_NoChaindata` — asserts no panic/error on empty datadir. ## Verified - `make lint` clean (×2) - `make erigon integration` builds - `erigon seg ls --datadir=/tmp/empty` logs degradation messages, exits 0
…run CDN download (#21882) ## Problem `test-hive-eest`'s `eels` simulators download the fixtures tarball from the GitHub release CDN **inside the image build** (`consume cache --input <url>`). With hive's `--docker.nocache`, that download repeats on **every run** — slow, exposed to transient release-CDN 504s, and bypassing the hardened `tools/test-fixtures.sh` entirely. ## Change Feed the fixtures from cache + a hardened fetch, and hand them to the sim locally: - **Restore** the EEST tarballs from the base-branch cache warmed by `cache-warming-eest-fixtures.yml` — **restore-only** (the warmer owns saving, so no per-ref duplicates). - **Fallback** on a cache miss: the hardened `tools/test-fixtures.sh` (5-min exponential backoff). - **Stage** the matrix tarball into the eels sim build context and pass `--sim.buildarg fixtures=/fixtures`, so the sim's `consume` reads a local directory instead of downloading. The `branch` build-arg (devnet `consume`/execution-specs selection) is unchanged. ## Hive dependency (now merged) The local-fixtures eels Dockerfiles landed in **erigontech/hive#2** (merged into `yperbasis/client-pool`). The hive `ref` is pinned to that merge commit (`9afe5f15`). ## Validation End-to-end verified on a real runner via `workflow_dispatch` (run 27152648786): exact-key **cache hit** (no CDN download), staged tarball picked up by the eels build, and `consume engine` ran the full `paris+shanghai` shard — **3573 tests, 0 failed**. The fixtures-directory layout was also confirmed against `execution-specs`/`consume` locally (it accepts the extracted dir and recursively builds its index).
#21883) Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.4 to 5.2.5. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/webpack/webpack-dev-server/releases">webpack-dev-server's releases</a>.</em></p> <blockquote> <h2>v5.2.5</h2> <h3>Patch Changes</h3> <ul> <li>Skip the HMR WebSocket path when forwarding upgrade requests to user-defined proxies, so custom proxy WebSocket upgrades are no longer intercepted by the dev server. (by <a href="https://github.com/bjohansebas"><code>@bjohansebas</code></a> in <a href="https://redirect.github.com/webpack/webpack-dev-server/pull/5680">#5680</a>)</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/webpack/webpack-dev-server/blob/main/CHANGELOG.md">webpack-dev-server's changelog</a>.</em></p> <blockquote> <h2>5.2.5</h2> <h3>Patch Changes</h3> <ul> <li>Skip the HMR WebSocket path when forwarding upgrade requests to user-defined proxies, so custom proxy WebSocket upgrades are no longer intercepted by the dev server. (by <a href="https://github.com/bjohansebas"><code>@bjohansebas</code></a> in <a href="https://redirect.github.com/webpack/webpack-dev-server/pull/5680">#5680</a>)</li> </ul> <p>All notable changes to this project will be documented in this file. See <a href="https://github.com/conventional-changelog/standard-version">standard-version</a> for commit guidelines.</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/webpack/webpack-dev-server/commit/c3ee325819f64ceb77f85dcf727b6b5ede85cbc4"><code>c3ee325</code></a> chore(release): new release (<a href="https://redirect.github.com/webpack/webpack-dev-server/issues/5682">#5682</a>)</li> <li><a href="https://github.com/webpack/webpack-dev-server/commit/60173be90873b187b41fc2009a4de253732988a1"><code>60173be</code></a> feat: add changeset validation and release workflow (<a href="https://redirect.github.com/webpack/webpack-dev-server/issues/5680">#5680</a>)</li> <li><a href="https://github.com/webpack/webpack-dev-server/commit/948d5e6089bebcd801dac2cbe3ed4f80b64f117a"><code>948d5e6</code></a> fix(proxy): match the HMR upgrade path exactly like the ws server (<a href="https://redirect.github.com/webpack/webpack-dev-server/issues/5678">#5678</a>)</li> <li><a href="https://github.com/webpack/webpack-dev-server/commit/93e8996124332a6c94c4d3e0f8e5f2cf95321c67"><code>93e8996</code></a> fix: skip HMR websocket path when forwarding upgrades to user-defined proxies...</li> <li>See full diff in <a href="https://github.com/webpack/webpack-dev-server/compare/v5.2.4...v5.2.5">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for webpack-dev-server since your current version.</p> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/erigontech/erigon/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [undici](https://github.com/nodejs/undici) from 7.25.0 to 7.28.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/nodejs/undici/releases">undici's releases</a>.</em></p> <blockquote> <h2>v7.28.0</h2> <h1>⚠️ Security Release</h1> <p>This release line addresses <strong>7 security advisories</strong>, all shipped in <strong>v7.28.0</strong>.</p> <blockquote> <p><strong>Action required:</strong> Upgrade to <strong>undici 7.28.0</strong> or later.</p> <pre lang="sh"><code>npm install undici@^7.28.0 </code></pre> </blockquote> <p>The v7 line is <strong>not</strong> affected by GHSA-38rv-x7px-6hhq (CVE-2026-9675), which is an 8.x-only regression.</p> <blockquote> <p><strong>Note on GHSA-hm92-r4w5-c3mj:</strong> this fix shipped in <strong>v7.28.0</strong>, not the earlier 7.2x line — the vulnerable single-pool code was still present through <code>v7.27.2</code>. The per-origin pool fix is <a href="https://github.com/nodejs/undici/commit/3805b8f8"><code>3805b8f8</code></a> (<a href="https://redirect.github.com/nodejs/undici/pull/5041">#5041</a>).</p> </blockquote> <h2>Summary</h2> <table> <thead> <tr> <th>Advisory</th> <th>CVE</th> <th>Severity (CVSS)</th> <th>Fixed in</th> <th>Fix commit</th> </tr> </thead> <tbody> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-vxpw-j846-p89q">GHSA-vxpw-j846-p89q</a></td> <td>CVE-2026-12151</td> <td>High (7.5)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/8cb10f98"><code>8cb10f98</code></a></td> </tr> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-vmh5-mc38-953g">GHSA-vmh5-mc38-953g</a></td> <td>CVE-2026-9697</td> <td>High (7.4)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/04201f89"><code>04201f89</code></a></td> </tr> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-hm92-r4w5-c3mj">GHSA-hm92-r4w5-c3mj</a></td> <td>CVE-2026-6734</td> <td>High (7.5)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/3805b8f8"><code>3805b8f8</code></a></td> </tr> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-pr7r-676h-xcf6">GHSA-pr7r-676h-xcf6</a></td> <td>CVE-2026-9678</td> <td>Moderate (5.9)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/85a24055"><code>85a24055</code></a></td> </tr> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-p88m-4jfj-68fv">GHSA-p88m-4jfj-68fv</a></td> <td>CVE-2026-9679</td> <td>Moderate (5.9)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/d0574cc4"><code>d0574cc4</code></a></td> </tr> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-g8m3-5g58-fq7m">GHSA-g8m3-5g58-fq7m</a></td> <td>CVE-2026-11525</td> <td>Low (3.7)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/d0574cc4"><code>d0574cc4</code></a></td> </tr> <tr> <td><a href="https://github.com/nodejs/undici/security/advisories/GHSA-35p6-xmwp-9g52">GHSA-35p6-xmwp-9g52</a></td> <td>CVE-2026-6733</td> <td>Low (3.7)</td> <td>7.28.0</td> <td><a href="https://github.com/nodejs/undici/commit/ea8930cf"><code>ea8930cf</code></a></td> </tr> </tbody> </table> <hr /> <h2>High severity</h2> <h3>WebSocket DoS via fragment count bypass — CVE-2026-12151</h3> <p><strong><a href="https://github.com/nodejs/undici/security/advisories/GHSA-vxpw-j846-p89q">GHSA-vxpw-j846-p89q</a></strong> · CWE-400, CWE-770 <strong>Fix:</strong> <a href="https://github.com/nodejs/undici/commit/8cb10f98"><code>8cb10f98</code></a> <em>websocket: limit the number of fragments in a message</em> (part of backport <a href="https://github.com/nodejs/undici/commit/a027a4a0"><code>a027a4a0</code></a> <em>Backport WebSocket maxPayloadSize fixes to v7.x</em>, <a href="https://redirect.github.com/nodejs/undici/pull/5423">#5423</a>)</p> <p>A malicious WebSocket server can stream a large number of small or empty continuation frames. Undici enforced a limit on cumulative payload size but did not limit the <em>number</em> of fragments per message, leading to unbounded memory growth and denial of service.</p> <ul> <li><strong>Affected:</strong> applications using <code>new WebSocket(...)</code> or <code>WebSocketStream</code> against untrusted endpoints.</li> <li><strong>Workaround:</strong> none — upgrade is required.</li> </ul> <h3>TLS certificate validation bypass in SOCKS5 ProxyAgent — CVE-2026-9697</h3> <p><strong><a href="https://github.com/nodejs/undici/security/advisories/GHSA-vmh5-mc38-953g">GHSA-vmh5-mc38-953g</a></strong> · CWE-295</p> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/nodejs/undici/commit/f9eba0ad9134e1c0977848476bba9d49734696e4"><code>f9eba0a</code></a> Bumped v7.28.0 (<a href="https://redirect.github.com/nodejs/undici/issues/5430">#5430</a>)</li> <li><a href="https://github.com/nodejs/undici/commit/a027a4a04c6c055877d1abaf5f60ee4917e7e01f"><code>a027a4a</code></a> Backport WebSocket maxPayloadSize fixes to v7.x (<a href="https://redirect.github.com/nodejs/undici/issues/5423">#5423</a>)</li> <li><a href="https://github.com/nodejs/undici/commit/8cb10f983eb6005dd53f3744d95d3b6d7dbcee0f"><code>8cb10f9</code></a> websocket: limit the number of fragments in a message</li> <li><a href="https://github.com/nodejs/undici/commit/04201f8947041f0f4f2ac865dbdb1677e46a8844"><code>04201f8</code></a> fix: honor requestTls when proxy is SOCKS5</li> <li><a href="https://github.com/nodejs/undici/commit/fcd642ff613ea9030dec87cf622e68d4b1ae9847"><code>fcd642f</code></a> fix(socks5): preserve dispatch backpressure return value (<a href="https://redirect.github.com/nodejs/undici/issues/5166">#5166</a>)</li> <li><a href="https://github.com/nodejs/undici/commit/bc98c97906abf26fa1e959b2f6111b53ade0e18f"><code>bc98c97</code></a> fix(socks5): use configured connector in Socks5ProxyAgent (<a href="https://redirect.github.com/nodejs/undici/issues/5168">#5168</a>)</li> <li><a href="https://github.com/nodejs/undici/commit/9e1c74372a2b27cacd92d27c13a83a6d84f10e0e"><code>9e1c743</code></a> fix(socks5): encode embedded IPv4 tails in IPv6 literals correctly (<a href="https://redirect.github.com/nodejs/undici/issues/5099">#5099</a>)</li> <li><a href="https://github.com/nodejs/undici/commit/376c8be27cb40cc17ccaad6b6ebb317fa7148d65"><code>376c8be</code></a> fix(socks5): enforce authenticated state before CONNECT (<a href="https://redirect.github.com/nodejs/undici/issues/5097">#5097</a>)</li> <li><a href="https://github.com/nodejs/undici/commit/3805b8f8518882991044048c256e005dc3c10a85"><code>3805b8f</code></a> fix(socks5-proxy-agent): use per-origin pools to prevent cross-origin routing...</li> <li><a href="https://github.com/nodejs/undici/commit/85a240551c9feb8b8a0ecc56c84b2b3015add8a9"><code>85a2405</code></a> fix(cache): trim qualified field names</li> <li>Additional commits viewable in <a href="https://github.com/nodejs/undici/compare/v7.25.0...v7.28.0">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/erigontech/erigon/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…sTrie (#21892) `debug_executionWitness` blinded the surviving sibling of a collapsing storage branch on a zero-value write (#21869). On a slot delete from a two-child branch, `toWitnessTrie` emitted the sibling extension but left the branch it points to a bare `HashNode`. reth's `stateless` verifier can't re-form the collapsed branch from a blinded node, so it returns `BlindedNode` and the post-state root diverges. Repro: mainnet block 25335936, zero-write to slot `0x43cb…`, sibling `0x43cd` blinded → `SparseTrieError(BlindedNode(Nibbles(0x43cd)))`. Fix: in exclusion-proof (legacy) mode, materialize that branch via `witnessMaterializeBranch` with a subtrie-root check instead of a `HashNode`. Same hash, witness root unchanged; canonical mode stays minimal. The absent-slot path and this one now share `witnessMaterializeBranchChild`. Test: `Test_WitnessTrie_GenerateWitness/CollapseSiblingExtensionMustBeMaterialized` — two-child storage branch, sibling is an extension over a sub-branch, delete the other child, assert the sub-branch is a `FullNode` not a `HashNode`. End-to-end: block 25335936 witness passes reth `stateless` (VALID; state nodes 16395 → 16396). Fixes #21869
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.2.3 to 5.2.4. <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/go-chi/chi/commit/6eb35881c0e438ffb663ddbad3a61babaa5e5d8a"><code>6eb3588</code></a> middleware: harden RedirectSlashes handler (<a href="https://redirect.github.com/go-chi/chi/issues/1044">#1044</a>)</li> <li><a href="https://github.com/go-chi/chi/commit/de0d16e6d23092aeef0b6e78f146799369160651"><code>de0d16e</code></a> Update comment about min Go version (<a href="https://redirect.github.com/go-chi/chi/issues/1023">#1023</a>)</li> <li><a href="https://github.com/go-chi/chi/commit/9fb4a15daa6d4ccd5e7286c1227d58872f89f4cb"><code>9fb4a15</code></a> update reverseMethodMap in RegisterMethod (<a href="https://redirect.github.com/go-chi/chi/issues/1022">#1022</a>)</li> <li><a href="https://github.com/go-chi/chi/commit/51c977c2da872d16d05531d5bc49ccd027599ce2"><code>51c977c</code></a> Refactor to use atomic type (<a href="https://redirect.github.com/go-chi/chi/issues/1019">#1019</a>)</li> <li><a href="https://github.com/go-chi/chi/commit/563ab118626b47810852303c3a60c2106a6bc23c"><code>563ab11</code></a> Refactor graceful shutdown example (<a href="https://redirect.github.com/go-chi/chi/issues/994">#994</a>)</li> <li><a href="https://github.com/go-chi/chi/commit/a52c582b532cd261dbedc4c811d809d6e024c1ff"><code>a52c582</code></a> Bump minimum Go and use new features (<a href="https://redirect.github.com/go-chi/chi/issues/1017">#1017</a>)</li> <li>See full diff in <a href="https://github.com/go-chi/chi/compare/v5.2.3...v5.2.4">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/erigontech/erigon/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.4.10 to 3.4.11. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/cure53/DOMPurify/releases">dompurify's releases</a>.</em></p> <blockquote> <h2>DOMPurify 3.4.11</h2> <ul> <li>Fixed an issue with a leaky config for hooks via <code>setConfig</code>, thanks <a href="https://github.com/trace37labs"><code>@trace37labs</code></a></li> <li>Bumped vulnerable development dependencies to arrive at plain 0 with <code>npm audit</code></li> <li>Updated the <code>osv-scanner</code> suppression list as no vulnerable dependencies are left for now</li> <li>Updated up the linting tool-chain and removed now-redundant lint directives</li> <li>Updated the documentation is several spots, README, wiki, etc.</li> <li>Bumped several dependencies where possible</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/cure53/DOMPurify/commit/0cae5187403132f96a6d357649e4b15633fc210a"><code>0cae518</code></a> release: 3.4.11 (<a href="https://redirect.github.com/cure53/DOMPurify/issues/1494">#1494</a>)</li> <li>See full diff in <a href="https://github.com/cure53/DOMPurify/compare/3.4.10...3.4.11">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/erigontech/erigon/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…s) (#21875) ## Problem The only heap-resident structure of an open `.bt` is `BpsTree`'s pivot-key cache. On a mainnet node it was ~1.3 GB (`btindex.decodeListNodes` in heap profiles): ~44M pivots × 32 B/node (`Node{key []byte (24B), di uint64 (8B)}`), dominated by the storage domain. The pivot keys already point into mmap (no heap copy) — the cost was purely the per-node struct. ## Change Replace `mx []Node` with: - `keysBlob []byte` — the `[keyLen:u16][key]` records; mmap-backed for on-disk files (zero heap), heap only in `WarmUp`. - `nodeOfft []uint64` — byte offset of each pivot record (the only per-node heap cost). - `nodeStride uint64` — `di` is derived as `nodeDi(i) = i*nodeStride`, not stored. Net: **32 B → 8 B per node (~4×)**, i.e. ~1.3 GB → ~340 MB. No on-disk format change — `decodeNodes`/`decodeListNodesV0` now return offsets into the existing mmap'd nodes section instead of materializing structs. `uint64` (not `uint32`) offsets: a single `.bt`'s nodes section is bounded by its file size, and the largest storage file is already ~3.5 GB — near the uint32 4 GB ceiling and growing. `di` is uniformly `i*M` for all real files (footer and released-3.4 legacy). For legacy v0 files the stride is recovered from the on-disk `di` so a file opened with a different `M` than it was written with stays correct. ## Notes - Lookup cost stays flat: the old code already read pivot key bytes from mmap; the offset path adds only a 2-byte length read on the same cache line, and the offsets array is more cache-friendly. `bs`/`Get` benchmarks: 0 allocs, timings unchanged. - Structured to be range-friendly for a future PrefixIndex (#20180) rebase: buckets can hold index ranges into `nodeOfft` with derived `di`. Result: Bloatnet: `1.18G -> 0.028G` --------- Co-authored-by: moskud <sudeepdino008@gmail.com>
Cherry-pick of #21889 to main. - The 3.4.4 release-notes block is inserted between the in-development 3.5.0 section and the released 3.4.3 section (main already carries the 3.4.3 date, so the change is purely additive). - The 3.5.0 "Full Changelog" range now bases on `v3.4.4` instead of `v3.4.3`, since 3.4.4 is the release immediately preceding 3.5.0.
## What `checkErrListEnd` (used by the EIP-7928 Block Access List decoder and block-body decoding) detected end-of-list with `errors.Is(err, rlp.EOL)`. A nested BAL decoder returns a *wrapped* `EOL` on malformed input — e.g. an account list with no Address (`AccountChanges.DecodeRLP` → `"read Address: %w"` wrapping `rlp.EOL`). `errors.Is` matched the wrapped EOL and treated it as a clean end-of-list, so the **production** decoder `DecodeBlockAccessListBytes` **silently truncated** a malformed BAL to empty instead of erroring: `0xc1c0` (a list with one empty account) decoded to an empty BAL with no error on `main`. Fix: match the bare sentinel (`err == rlp.EOL`) so a wrapped EOL propagates as a real error. ## Severity (corrected from the original description) This is a **real correctness fix, not no-op hardening** — thanks @yperbasis for catching this. `DecodeBlockAccessListBytes` is the production decoder, called from `NewPayload` (`engine_server.go:374`), where the header commitment is `crypto.HashData` over the **raw** BAL bytes (`:388`) — so the decoder is the only gate. Once Glamsterdam activates, silently truncating malformed input would be an accept/reject divergence vs a strict client. **No mainnet impact today** (BALs are pre-mainnet, Glamsterdam devnets only). Same spirit as #21818 ("reject malformed RLP instead of dropping elements"). The rlp reflection slice decoder already used exact `== EOL` and is unchanged; block-body callers return a bare EOL at genuine end-of-list, so the change is scoped to the only vulnerable site. ## Test `TestBlockAccessListRejectsAddresslessAccount` now goes through `DecodeBlockAccessListBytes` (the production path) so it actually exercises `checkErrListEnd` — verified red→green (FAIL on `main` without the fix, PASS with it). Full `execution/types` suite green; `make lint` clean. Co-authored-by: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com>
…d build semaphore (#21526) ## Problem - block retirement holds snapshotBuild semaphore (`snBuildAllowed`, default size 1) across both collation and merge. - this semaphore is also shared by state aggregator. - when a large block merge runs (100k blocks), it blocks state collation, causing steps_in_db to accumulate (specially during catchup phase). - depends on #21545 Observed on a minimal node: an **8.2 GB / ~19-minute** `025100→025200` transactions merge held the semaphore the whole time, starving state collation — `stepsInDB` climbed to **3.82** (chaindata bloats while collation waits). ## Change - Release the semaphore after the collate phase and run the merge in its **own goroutine, off the semaphore** — mirroring how the aggregator runs `MergeLoop`. - The fast dump stays serialized against state-snapshot building (preserving the I/O-throttle intent); the slow merge no longer starves state collation. ## Effect With the same 8.2 GB block-tx merge in flight, state collation now proceeds concurrently — `stepsInDB` stays **< 2** (was 3.82). The CLI `retire` path calls `MergeBlocks` explicitly so its behavior is unchanged. ## Tests - `TestBlockMergeRunsWithoutSemaphore` — merge completes while the semaphore is fully held (regression-guards re-acquisition). - `TestRetireBlocksInBackgroundReleasesSemaphore` — background retire releases the semaphore, no leak. Draft — full `make lint` + integration verification pending. --------- Co-authored-by: Sudeep Kumar <sudeep.kumar@erigon.tech>
## Summary - Fix data race between `GetHead` (read) and `onTickPerSlot` (write) on `ForkChoiceStore.headHash`/`headSlot` - The fast-path cache hit in `GetHead` was reading struct fields **after** releasing `RLock`, racing with `onTickPerSlot` clearing `headHash` under the write lock - Copy `headHash` and `headSlot` into locals while `RLock` is still held, return the locals after unlock Fixes #21936 ## Test plan - [x] `go test -race ./cl/phase1/forkchoice/...` — pass - [x] `go build -race ./cl/...` — pass - [x] `make lint` — 0 issues
…21981) Fixes a storage-state corruption left behind by `DomainRoTx.unwind` when an unwound range crosses a domain-step boundary. Found via the StateChurn unwind/reorg integration tests being added in #21973 (part of #21860). ## Root cause When a key is modified at **several domain steps inside the unwound range**, the merged diffset carries one entry per step. `unwind` wrote a restore `Put` for **every** step's diff to the same `unwindStep`. In the **DupSort** values table those become *separate* dup entries under the key — e.g. `^step+""` and `^step+\x01` — and `getLatestFromDb` returns the **smallest** dup, which is often an empty tombstone from a *higher* step rather than the value as of the unwind target. Only the **lowest** in-range step's value is `value@txNumUnwindTo`; the higher steps' values are intermediate states *inside* the range. The fix restores once, on the last (lowest-step) diff per key (diffs are sorted by key then descending step). The `LargeValues` path was already correct — MDBX `Put` overwrites at the same key, so last-wins already yields the lowest step — and is left untouched. ## Why it was hidden At the production step size a normal unwind (≤ `MaxReorgDepth` blocks) stays within a single step, so each key has at most one in-range diff and the bug never triggers. It surfaces when the unwound range **crosses a step boundary**: - small step sizes (as the regression test forces continuously), or - a reorg landing just past a freshly-filed step. Symptom: after such an unwind the committed state is internally inconsistent (a later read returns a stale/empty value for a key that was modified across the boundary). This matches the unwind/reorg-regression history behind #21860. ## The fix ```go // ...only the lowest step's value is the value at txNumUnwindTo. Restore once, // on the last (lowest-step) diff — else the DupSort table keeps several dups at // unwindStep and getLatestFromDb returns the smallest. lastForKey := i+1 == len(domainDiffs) || domainDiffs[i+1].Key[:len(domainDiffs[i+1].Key)-8] != keyStr[:len(keyStr)-8] if value != nil && lastForKey { valsCursor.Put(fullKey, append(unwindStepBytes, value...)) } ``` ## Regression test `TestDomain_MultiStepUnwindMatchesGroundTruth` (deterministic, ~0.4s): mirrors StateChurn at the domain level (a dense sum key + sparse ring keys, values in {0,1,2} with 0 = delete), files+prunes early steps, unwinds a multi-step range above the file boundary, and asserts every key equals the tracked ground truth and that the ring values still sum to the sum key. **Red before the fix, green after.** ## Validation - Regression test: red → green. - Existing `db/state` domain/aggregator/unwind/collate/prune suite: pass, no regression. - Full `make lint`: clean.
## Problem
`BlockAssembler` builds the block access list (BAL) by accumulating each
transaction's versioned IO. Done with the general pairwise
`VersionedIO.Merge`, every transaction allocates a fresh `VersionedIO`
and copies the **entire** accumulator, so accumulating a block is
**O(n²)** in time and allocations. For value-transfer-heavy blocks
(cheap txs, many per block) this dominates block-build time.
## Approach
Fold each transaction's recorded reads, writes and accesses **directly
into the accumulator at its tx index**, via
`IntraBlockState.MergeTxIOInto`:
- No intermediate per-tx `VersionedIO` is materialized — the assembler
no longer builds a throwaway one per transaction.
- Each fold touches only that tx's slot (O(1) amortized), so building a
block's BAL is **O(total entries)** rather than O(n²).
- Folds **merge** into the slot rather than overwrite it, so system-call
phases that share a block-level index accumulate correctly.
- The three per-tx slices (`inputs`/`outputs`/`accessed`) grow in
lockstep to a common length, so the accumulator stays rectangular
regardless of fold order.
- The assembler's `recordTxIO`/`clearTxIO` helpers drop their
now-redundant `*VersionedIO` parameter and gate on `ba.HasBAL()`
directly.
## Impact
Building a block full of ether transfers on a ~2 TB mainnet-shadow
("bloatnet") state:
| txs/block | before | after |
|-----------|--------|-------|
| 4000 | ~6.9 s | ~0.8 s |
| 8000 | ~28 s | ~1.0 s |
Build time goes from O(n²) to ~linear; the per-transaction accumulator
copy and the throwaway per-tx `VersionedIO` allocation are both gone.
The `newPayload` (import/validation) path computes its BAL separately
and is unaffected.
## Correctness
- `TestVersionedIO_mergeTxEquivalentToMerge` checks the in-place fold
against repeated `Merge` (kept as an independent oracle) both by
whole-BAL hash and channel by channel — reads, writes and accesses
compared at every index, including the begin-system tx at index -1 and
two txs at the same index — plus that the per-tx slices stay equal
length. The per-channel checks are needed because a non-system access
(and a balance read) contribute no BAL field, so an
overwrite-instead-of-merge bug would otherwise still hash-match.
- `execution/state`, `execution/exec`, `engineapi` (BAL / builder /
payload), `execution/stagedsync` BAL, and `execution/vm/runtime` tests
pass; `make lint` clean.
- The BAL embedded in built blocks is byte-for-byte what the prior
`Merge`-based accumulation produced, and `newPayload` recomputes the BAL
independently as a cross-check.
## Problem `codeBitmap` (JUMPDEST analysis) scans bytecode one byte at a time. Only PUSH opcodes contribute data bits, so runs of non-PUSH bytes have nothing to mark — yet they're still walked byte-by-byte. This is worst for the EIP-2780 `test_ether_transfers_onchain_receivers` **`diff_to_unique_code_jumpdest_contract`** case: each receiver is a unique 24 KiB contract that is almost entirely JUMPDEST padding, and (being unique code) the per-codehash analysis cache can't help, so every transfer rescans 24 KiB. ## Change Detect whether an 8-byte word contains a PUSH opcode with a **SWAR** (SIMD-within-a-register) test — `(b & 0xe0) == 0x60` for every byte via the classic has-zero-byte trick — and skip whole PUSH-free words. A word containing a PUSH falls back to the canonical byte loop, advanced at least to the next 8-byte boundary so the peek is amortised over ≥8 bytes and **PUSH-dense code is not penalised**. This is the portable-Go analogue of Nethermind's SIMD jumpdest scan. Erigon's *data*-bitmap representation makes a PUSH-free word a pure skip (nothing to write), so the fast path is just `pc += 8`. ## Benchmarks (`execution/vm`) | Case | before | after | |---|---|---| | 24 KiB all-JUMPDEST (unique-code receiver) | ~5.9 µs | **~2.5 µs (2.3×)** | | no-PUSH 1.2 MB | ~290 µs | **~125 µs (2.3×)** | | real Solidity contract (PUSH-dense) | ~306 ns | ~298 ns (neutral) | ## Correctness New `TestCodeBitmapSWAREquivalence` fuzzes the result against the byte-at-a-time reference across jumpdest-heavy, push-dense and uniform-random code (20k cases) plus boundary edge cases (lone / trailing PUSH spanning word boundaries), asserting byte-identical bitvecs. Existing `TestJumpDestAnalysis` and the full `execution/vm` suite pass; `make lint` clean. ## Scope This speeds up the analysis itself; on the end-to-end EIP-2780 import it's a small CPU fraction of an I/O-bound (commitment) workload, so it won't move the headline MGas/s much on its own — it's a free, zero-regression win that's most visible on JUMPDEST-heavy / low-PUSH code. Opened as draft for review.
## Problem The **Kurtosis GLOAS Tests** jobs (`gloas_gloas-caplin-mixed_test`, `gloas_gloas-three-cl-mixed_test`) flake / time out. The enclave runs `ethpandaops/assertoor:master`, which moved onto the `glamsterdam-devnet-6` branch (EIP-8282, 2026-06-18) and now expects a **5-list** `ExecutionRequests` (`+ builder_deposits`, `+ builder_exits`). The clients pinned here are devnet-5 and still emit the **3-list** layout, so assertoor can no longer decode their gloas blocks: - SSZ (lighthouse-/prysm-mirrored erigon blocks): `Message.Body.ParentExecutionRequests: unexpected end of SSZ: not enough data for fixed fields (have 12, needed 20)` — 3 offsets present, 5 expected. - JSON (caplin): `builder_deposits: missing`. Only pre-gloas (epoch-0 / Fulu) proposals decode, so `block-proposal-check` hangs whenever a client pair doesn't draw an epoch-0 proposer slot, and the job hits the action timeout. On `main` the single caplin pair is most exposed (lighthouse/prysm pairs sometimes still decode), so it fails less often than `release/3.5` but the skew is the same. ## Fix Pin the kurtosis assertoor image to `master-2231b3e` (2026-06-11) — the last pre-EIP-8282 `master` build, which is gloas-aware but still 3-list, matching the devnet-5 clients. No released tag works: `v0.1.2` predates assertoor's gloas decoding (added 2026-05-19), and assertoor publishes no `glamsterdam-devnet-5` image. Mirrors #22009 (the `release/3.5` stopgap). ## Follow-up Stopgap only. The durable fix is implementing EIP-8282 in erigon and moving the clients to devnet-6, tracked in #22008 — at which point this pin reverts to `:master`.
## Problem The `parallel starting` log line prints a garbage `limit`: ``` [6/8 Execution] parallel starting from=0 to=21715999 limit=18446744073709551615 ... ``` `18446744073709551615` is `math.MaxUint64`: the log computed `limit` as `startBlockNum+blockLimit-1`, which underflows when `blockLimit == 0` (the "no per-cycle limit" case — e.g. `integration stage_exec` from block 0, where `LoopBlockLimit` is 0). ## Fix Log the effective last block of the cycle: - `maxBlockNum` when there's no per-cycle limit (`blockLimit == 0`), - otherwise `min(startBlockNum+blockLimit-1, maxBlockNum)`. This mirrors how the serial path already computes `toBlockNum` (`exec3_serial.go`). Log-only change — execution behavior is unaffected. Now logs: ``` [6/8 Execution] parallel starting from=0 to=21715999 limit=21715999 ... ```
…21920) ## Problem `Peer.handle` runs in the per-peer read loop for **every inbound subprotocol message**. With metrics enabled it did, per message: ```go m := fmt.Sprintf("%s_%s_%d_%#02x", ingressMeterName, proto.Name, proto.Version, msg.Code-proto.offset) metrics.GetOrCreateGauge(m).SetUint32(msg.meterSize) metrics.GetOrCreateGauge(m + "_packets").Set(1) ``` That allocated, per message: the `Sprintf` string, the `+ "_packets"` string, two `&gauge{}` wrappers from `GetOrCreateGauge`, and the variadic arg boxing — and each `GetOrCreateGauge` also took a mutex + map lookup. The gauge identity only depends on `(proto.Name, proto.Version, relativeCode)`, all stable for the lifetime of a `protoRW`. ## Change Cache the gauges per `protoRW`, indexed by the protocol-relative message code. The first message for a code creates and caches the gauges (preserving the original lazy registration — no zero-valued metrics for codes that never arrive); subsequent messages just index the slice and call `Set`. Behavior is identical: same gauge names, same values. Safe without locking because `handle` only runs in the single per-peer read-loop goroutine and each peer owns its own `protoRW` instances (confirmed under `-race`). ## Numbers Benchmarked on the actual code path (`benchmem`, Apple M4 Max): | | allocs/op | bytes/op | ns/op | |---|---|---|---| | Before | 5 | 128 B | ~152 ns | | After (cache warm) | 0 | 0 B | ~3.3 ns | **5 allocations → 0 per inbound message**, ~46× faster per call. ## Tests - `TestProtoRWMeterIngress` — verifies the byte/packet gauges still receive the correct values. - `TestProtoRWMeterIngressNoAllocs` — asserts `0 allocs/op` after warmup (regression guard).
…Witness (#22000) `debug_executionWitness` drops the 20-byte preimage of an accessed account that exists in the parent state but is emptied and EIP-161 state-cleared in-block. `collectAccessedState` gates `keys[]` on `accountExists()` (post-state), so a deleted-in-block account is skipped — yet its leaf is still in the parent-state witness trie. A verifier treating `keys[]` as the closed accessed set then can't route to it. Fix: gate on pre- **or** post-state existence (`existedPreBlock`). Never-existed and created-then-deleted accounts stay excluded; slot preimages were never gated. Repro: mainnet 25350549, `0x16fd7629978addaf41c426601176c37977a0faa7` (0.36 ETH → 0, nonce 0, no code → EIP-161 cleared). | | keys | addr in keys | state | codes | |---|------|------|------|------| | before | 1516 | no | 8700 | 302 | | after | 1517 | yes | 8700 | 302 | One preimage added, witness-trie nodes unchanged. reth `stateless` returns VALID before and after — it routes via the present leaf, so this is a `keys[]`-completeness bug, not re-exec/root. Test: `TestCollectAccessedState_KeysIncludeDeletedPreExisting`. Closes #21979.
…atches (#22002) ## Motivation `seg reset` removed a `.torrent` whose infohash didn't match the preverified set (a locally-built file whose bytes differ from the published copy) but **kept the data file it described** — leaving an unverified local build on disk with no torrent, for the downloader to reconcile later. That delete-and-re-fetch handoff is what surfaces as the recurring `[agg] gap in visible files` warning after a reset (see #21876). The relevant `decideRemove` path already had an acknowledged `// TODO: missing or incorrect torrent delete data file?`. ## Change | before | after | |---|---| | incorrect torrent → remove torrent, **keep** data file | incorrect torrent → remove torrent **and** the data file it vouched for | - When reset removes an in-preverified torrent (incorrect/corrupt infohash), it now also removes the corresponding data file, so the downloader re-fetches the canonical copy deterministically instead of racing on stale content. - A data file is walked before its sibling `.torrent` (`os.ReadDir` sorts; `x.ef` < `x.ef.torrent`), so the retraction is order-deterministic. - Test helper `makeEntries` now writes file contents, so a torrent fixture with a controllable infohash can exercise the mismatch path. ## Test `TestIncorrectTorrentRemovesDataFile` builds a torrent with a mismatched infohash and asserts both the torrent and its data file are removed. Red before the change (data file survived), green after. ## Scope note This fixes reset's internal consistency — it no longer retains a file whose hash it just determined is wrong. It does not change the inherent transient warning while a missing file is being (re)downloaded; it makes the re-download deterministic and avoids leaving known-stale data when the downloader is disabled.
…out (#21999) ## What `FuzzLongestMatch`'s brute-force validation oracle was `O(len(data) × numKeys × keyLen)`. Since `data` grows up to ~8× `len(test)` (each test chunk appends a key plus its reverse), the coverage-guided fuzzer could drive the oracle past the 60s OSS-Fuzz timeout. Fixes OSS-Fuzz issue 527099028 (`erigon:fuzz_patricia_longest_match: Timeout`). ## Root cause The timeout is in the **fuzz harness**, not production code. Timing a 320KB-data × 4000-key input: | Stage | Time | |---|---| | `MatchFinder3.FindLongestMatches` (prod) | ~23 ms | | `ACMatcher.FindLongestMatches` (prod) | ~15 ms | | **brute-force oracle (test)** | **10.5 s** | The production matchers are bounded by trie depth (max key length), so they stay linear even on degenerate all-zeros / prefix-nested input. Only the test oracle was quadratic. ## Fix Replace the inner per-key scan with an independent byte-trie walk — `O(len(data) × maxKeyLen)`, identical greedy longest-match semantics. It's a separate implementation from the AC/MF3 code under test, so it remains a valid oracle. ## Verification - Element-by-element identical output to the old oracle (verified on a 100k-match input). - ~175× faster on that input: 10.5s → 60ms. - Seed corpus passes; a 40s `-fuzz` run did 2.4M execs with no crashes/timeouts and still gained coverage. - `make lint` clean. Test-only change, so no TDD cycle applies (per CLAUDE.md: this is a fuzz-harness performance fix, not a behavior change).
## Motivation Domain purification — the `compact_domains` (alias `purify_domains`) integration command — rewrites domain `.kv` files with repeated keys dropped. A key live at step X may then exist only in an earlier file, so a file ending at step X no longer holds the state present at step X. That broken invariant breaks tooling that works off the latest on-disk state: - **commitment rebuild** - **`seg rm-state --latest`** (and working off the resulting state) ## Change Removes the command and everything exclusive to it: - `compactDomains` cobra command + its flags (`--out`, `--replace-in-datadir`, `--build-idx`, `--min-skip-ratio[-l0]`, `--from`, `--to`) - helpers `makeCompactableIndexDB`, `makeCompactDomains` - the `RELEASE_INSTRUCTIONS.md` step that ran it `read_domains` / `requestDomains` in the same file are untouched. The `db/integrity` comments about purification stay — already-published files remain purified, so that handling is still needed. Net: -409 lines. `make lint` clean; `cmd/integration` builds + vets.
Since #21625, the compressor's cover phase uses only the Aho-Corasick matcher. The old suffix-array `PatriciaTree` / `MatchFinder1/2/3` path has no remaining callers — it's dead code (the sole repo-wide importer, `db/seg/parallel_compress.go`, uses AC exclusively). ## Change - delete `patricia_tree.go`, `patricia_flat.go`, and `patricia_flat_test.go` - relocate the `Match` / `Matches` types (the only part AC still needs) into `aho_corasick.go` - trim `patricia_fuzz_test.go` to the AC + brute-force-oracle path; drop `FuzzPatricia` (it fuzzed the removed `node`) Net −1069 LOC. `db/seg` and `db/seg/patricia` build and tests pass. ## Closes #21626 The prefix-loss bug (`Insert` drops an existing key when a proper prefix is inserted later) lived in the now-removed `PatriciaTree.Insert`. The AC matcher is unaffected — it's validated against a brute-force oracle in `FuzzLongestMatch`, which this PR keeps.
Reduces gossip subscription log noise at startup. - Per-topic `[GossipManager] Subscribed to topic` is demoted from INFO to DEBUG — it previously emitted one INFO line per topic (hundreds, counting attestation/sync-committee/data-column subnets). - `registerGossipService` now returns `subscribed`/`expired` counts instead of logging per service, and `RegisterGossipServices` aggregates them into a single `INFO [GossipManager] Registered services subscribed=A expired=B` line. `expired` counts subnet-fanned topics (attestation, sync committee, data-column sidecar) that default to a past expiry and are subscribed later by other modules; `subscribed` counts topics subscribed immediately.
Brings in the streaming/parallel deep-storage-fold correctness fix #21945 (and its feature line #21709, #21941) plus the rest of bal-devnet-7. Conflict resolutions: - db/state/commitment_convert{.go,_blackbox_test.go}: took bal-devnet-7 (#21933, merged form) over warmup's pre-merge draft. - db/seg/decompress.go: took bal-devnet-7 comment (same change #21927). - execution/stagedsync/rawdbreset/reset_stages.go: combined warmup's out-of-tx ClearTables with bal-devnet-7's branchCache invalidation. - execution/stagedsync/stage_execute.go: kept warmup's PruneExecutionStage (haveMore signature, required by callers); bal-devnet-7's #20860 prune-timeout budget-sharing not carried into this function. - cmd/integration/commands/stages.go: took bal-devnet-7's stageExec (drops removed --no-commit flag), adapted its PruneExecutionStage calls to the haveMore signature.
sudeepdino008
requested review from
AskAlexSharov,
anacrolix,
awskii,
bloxster,
domiwei,
lupin012,
lystopad,
mh0lt,
mriccobene,
taratorio and
yperbasis
as code owners
July 1, 2026 06:48
AskAlexSharov
approved these changes
Jul 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refreshes
bal-devnet-7_warmupontobal-devnet-7, pulling in the parallel deep-storage-fold trie-root fix #21945 (and its feature line #21709, #21941).sstore_bloatedMGas/ssstore_bloated(F) — new slotssstore_bloated(T) — existing slotsNotes
Rendered as a merge, so review the conflict resolutions rather than the upstream commits:
commitment_convert.go/_blackbox_test.go: took bal-devnet-7's merged form ([3.6] cmd:erigon commitment convert#21933) over the pre-merge draft.db/seg/decompress.go: comment-only, took bal-devnet-7 (db/seg: drop redundant posTable.ptrs pointer array #21927).rawdbreset/reset_stages.go: combined out-of-txClearTableswith bal-devnet-7's branchCache invalidation.stage_execute.go: kept warmup'sPruneExecutionStage(haveMoresignature, required by callers). bal-devnet-7's execution: share prune timeout budget #20860 prune-timeout budget-sharing is not carried into this function.cmd/integration/commands/stages.go: took bal-devnet-7'sstageExec(drops the removed--no-commitflag), adapted its prune calls to thehaveMoresignature.