Skip to content

v2.10.3 candidate - #2492

Merged
marcello33 merged 62 commits into
masterfrom
v2.10.3-candidate
Oct 15, 2026
Merged

marcello33 merged 62 commits into
masterfrom
v2.10.3-candidate

Conversation

@marcello33

@marcello33 marcello33 commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Publishes v2.10.3: security and stability fixes on top of v2.10.2. Code is identical to v2.10.3-priv (Amoy: v2.10.3-beta-priv), already running on internal Amoy and mainnet nodes and on most external validators and major RPC providers. Only the private-release CI/installer files were left out, plus the version meta (2.10.3, no -private).

Main changes:

Executed tests

  • Amoy soak since 2026-10-05 on all internal nodes (v2.10.3-beta-priv): chain/execution/parallel/error +0 on every host, pipelined-import fallback / root mismatch +0 over ~72k blocks per pipelined sentry, no bad blocks or reorgs against a serial reference node.
  • core/state, core/blockstm: resolve parallel balance reads across self-destruct boundary #2403 scenario on a Kurtosis devnet (create → self-destruct → late funding → CREATE2 redeploy in one block): V2-only and serial importers agree on block hash, state root and receipts root across all scenario blocks. The same scenario fails on an unfixed build.
  • Memory, keccak/ecrecover-heavy load on devnet: importer live-heap peak 124 MiB vs 528 MiB on v2.10.2, p50 import time unchanged.
  • SetCode filtering: verified on Amoy.
  • Address-cache persistence on a mainnet sentry: storage trie preload went from ~1h25m (cold) to ~4s on restart, imports caught up within seconds. A missing cache falls back to the normal preload.
  • Mainnet: internal fleet on v2.10.3-priv since 2026-10-08, stranded-tx eviction reducing sentry pending pools as expected.

Rollout notes

  • Not consensus-affecting. No hardfork. Nodes can be upgraded one at a time, in any order.
  • Operator check, [heimdall] timeout: previously ignored (a hardcoded value was used). It's now honored, so a node with a low value set explicitly (e.g. the old 5s template default) will start using it. Remove the value or set it to 30s unless you need something else.
  • New optional config: txpool.strandedlifetime (on by default, 3h; 0 disables) and [cache] addresscachepersist (off by default; needs disk space for the snapshot, ~9 GB on mainnet with the default cache sizes).
  • After merge: tag v2.10.3 (latest), then backport master → develop.

marcello33 and others added 30 commits September 30, 2026 13:47
…able head

Pending transactions never expire: Lifetime only applies to the queue. When
an account's lowest-nonce pending tx can no longer be mined (fee cap below
the base fee, or effective tip below the minimum tip producers enforce), the
whole gapless chain behind it stays in the pool indefinitely.

This happened on mainnet: during the 2026-09-19 base fee collapse an account
signed txs with a 40 gwei fee cap; its last tx was mined at block 94098309
(base fee 15 gwei) and the base fee passed 40 gwei at 94098398. Four days
later its 56,856 txs were still pending, 97% of the pool, and producers'
Pending() copied all of them on every block build.

The evict ticker now drops the whole pending list of an account whose head
has been unminable for longer than Lifetime, in one pass. Evicted unminable
txs are remembered for Lifetime and re-adds are refused as underpriced while
they are still unminable, so peers can't push them straight back and the tx
fetcher marks them underpriced too.

(cherry picked from commit d3db897)
…-destruct boundary (#2403)

BlockSTM V2 resolved account balance reads as base + cumulative deltas
without consulting the SuicidePath tombstone that GetNonce, GetCode and
GetState already honour. A prior-tx SELFDESTRUCT deletes the account at
that tx's finalisation, so a later tx must observe a zero balance until a
subsequent tx re-funds the address. Without this, a same-tx create +
SELFDESTRUCT that receives value after the opcode left a stale balance
delta visible to later transactions, diverging from serial execution and
the resulting state root.

Make GetBalance tombstone-aware: when a prior tx destroyed the account,
drop the base balance and every delta at or before the destroying tx,
counting only deltas after it. MVBalanceStore gains ReadDeltaAfter for
the bounded read; BalReadDesc records the boundary so read validation
resolves it the same way, and the SuicidePath dependency recorded by
priorDestructedAt re-executes the reader if the destruction changes.

Add a serial/V2 parity regression test for the create/destruct/late-fund
+ CREATE2 sequence across worker counts 1, 2 and 8. Verified against the
241-block mainnet witness corpus (241/241 consistent).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit af1941e)
…2x refusal

- A head is stranded only when its fee cap is below the base fee. The
  pool does not know the tip producers apply (miner.gasprice), so a low
  effective tip no longer counts.
- New flag txpool.strandedlifetime (default 3h, 0 disables), separate
  from txpool.lifetime.
- Evicted txs are refused for 2x the stranded lifetime, and the evicted
  memory holds 2x the pool capacity to match.

(cherry picked from commit 5af4254)
core/state, core/blockstm: resolve parallel balance reads across self-destruct boundary
core/txpool/legacypool: expire pending txs that producers will not include
core/state, eth/tracers: count logs without copying them when tracing
)

* p2p: keep static peers dialed across jails and full dynamic slots

Two cases left static nodes disconnected indefinitely even when they were
also configured as trusted:

- A static peer jailed while connected was dropped from staticPool on
  disconnect (checkDial returned errJailed), and nothing re-added it when the
  jail expired. It was only redialed after a restart or admin_addPeer. The
  dialer now parks jailed static nodes in the dial history until their unban
  time, so expireHistory moves them back into the pool.

- Static dials were taken from freeDialSlots(), which counts dynamic peers.
  Once discovery filled MaxPeers/DialRatio outbound slots, a static node that
  dropped was not redialed until a dynamic peer left. Static dials now use
  their own budget where only connected static peers count, so dynamic peers
  cannot starve them while the static set is still bounded.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* p2p: retry static pool immediately when a jail expires mid-check

If the jail expired between checkDial and the unban time lookup, the static
node was neither pooled nor parked in the dial history and would be lost
again. Re-run updateStaticPool in that case, and cover it with a
deterministic test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* p2p: count only static dials in flight against the static budget

Dynamic dials in flight no longer defer static dials when the dial queue
is full. Addresses review feedback on #2438.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
preloadAddressAsync kept its BFS frontier in a single slice
(append + queue[1:]). For large contracts the frontier reaches hundreds
of millions of items, so every growth step is a multi-GB pointerful
allocation and copy. These steps cannot be preempted, and when a GC
stop-the-world lands during one the whole process freezes for seconds.
Consumed items also stay reachable until the next growth.

Replace it with preloadQueue, a FIFO of fixed 4096-item (128 KiB)
segments. The queue never allocates more than one segment at a time,
popped slots are cleared, and a segment is released as soon as it is
fully consumed. BFS order and the preload result are unchanged.

In a 20M-push BFS benchmark the largest single allocation drops from
652.5 MiB to 0.125 MiB, the slowest push from 67-183 ms to under 0.25 ms,
and peak heap from ~1.3-1.6 GiB to ~0.6 GiB.

(cherry picked from commit b647296)
…s fast

TestPreloadQueue_LargeN pushed 5M items. With a mutant that allocates a new
segment on every push, that is ~640 GB and the CI runner was killed.
Use 200k items and a boundedPusher helper that fails as soon as the queue
holds more segments than its item count needs.

(cherry picked from commit ab09588)
core/txpool: stop swapping the pool signer when allow-unprotected-txs is set
consensus/bor/heimdall: honor the configured request timeout
p2p: keep static peers dialed across jails and full dynamic slots
eth: keep configured static peers out of the dropper
lucca30 and others added 18 commits October 14, 2026 15:06
…ededBuffer

After h.stop()/h.resume() the publisher's read client can still hold the
transport the outage killed. The build-start read then fails at once,
the state becomes buildUnknown, and that blind path keeps the buffer, so
the test failed about 3% of runs (unacked=2 rebased=false).

Wait until the raw read client gets an answer from the store before the
adoption step. The raw client is used so failed tries do not count
against the read breaker. 0 failures in 500 runs, 0 in 100 with -race.
Root bypasses directory permissions, so the chmod 0o500 trick does not
make the save or remove fail and the log assertion would fail.
A batch item can hand its slot back (e.g. while waiting on a receipt) and fail to take it again. Wait for a slot before running the next item, giving up on the same terms as SubmitWithSlot, and answer the remaining calls with a timeout error if the request context is done.
The txpool address filter only checked the transaction sender. A SetCode
authorization can be carried by any sender, so a filtered account could
attach code to itself through an unfiltered sender's transaction and then
act through that code.

Reject a transaction if any recoverable authorization signer is filtered,
including revocations and tuples that would be skipped at execution for a
wrong chain ID or nonce, since validity at admission is not validity at
execution. Authority recovery is skipped when the filter list is empty.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
triedb/pathdb: persist address-biased preload cache across restarts
http.ep-requesttimeout and ws.ep-requesttimeout were parsed into the node config but never passed to the RPC servers, which were always created with a 0 timeout. Pass them through so a saturated pool lets a waiting request run unbounded after the configured timeout, as documented.
…-authorities

core/txpool: apply filtered addresses to SetCode authorities
@marcello33
marcello33 marked this pull request as ready for review October 14, 2026 13:50
Copilot AI balanced review requested due to automatic review settings October 14, 2026 13:50

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The release combines execution-state correctness, txpool policy, persistence, concurrency, and networking changes requiring final human validation.

0 open findings

What changed in this PR

Publishes Bor v2.10.3 with execution correctness, memory, txpool, trie-cache, networking, RPC, and Heimdall reliability fixes.

Changes:

  • Fixes BlockSTM self-destruct balance parity and bounds shared execution caches.
  • Adds stranded-transaction eviction and persistent address-cache support.
  • Improves static-peer redialing, RPC slot handling, timeouts, tooling, and release metadata.
File Description
triedb/​pathdb/​journal.go Avoids cache persistence during journaling.
triedb/​pathdb/​disklayer.go Adds controlled cache persistence lifecycle.
triedb/​pathdb/​disklayer_terminate_test.go Tests shutdown and persistence behavior.
triedb/​pathdb/​database.go Persists caches safely on final close.
triedb/​pathdb/​config.go Adds address-cache persistence configuration.
triedb/​pathdb/​config_test.go Tests persistence log fields.
triedb/​pathdb/​biased_fastcache.go Reloads snapshots and segments preload queues.
triedb/​pathdb/​biased_fastcache_queue.go Implements segmented BFS queue.
triedb/​pathdb/​biased_fastcache_queue_test.go Tests queue correctness and memory bounds.
triedb/​pathdb/​biased_fastcache_persist.go Implements snapshot persistence utilities.
rpc/​handler.go Reacquires execution slots between batch calls.
rpc/​execution_slot.go Adds blocking slot reacquisition.
rpc/​execution_slot_test.go Tests batch slot and timeout behavior.
rpc/​execution_pool.go Extracts reusable bounded acquisition logic.
params/​version.go Bumps Bor to v2.10.3.
p2p/​server.go Exposes peer jail expiry times.
p2p/​peer_jail_test.go Updates jail lookup coverage.
p2p/​dial.go Prevents static-peer dial starvation.
p2p/​dial_test.go Tests static redial and jail expiry.
node/​rpcstack.go Applies RPC pool request timeouts.
node/​rpcstack_test.go Verifies RPC pool configuration wiring.
node/​node.go Passes configured RPC timeouts.
internal/​ethapi/​api.go Removes ineffective chain-ID exceptions.
internal/​cli/​server/​flags.go Adds cache and stranded-lifetime flags.
internal/​cli/​server/​config.go Wires new settings and timeout defaults.
internal/​cli/​server/​config_test.go Verifies Heimdall timeout default.
internal/​cli/​server/​command_test.go Tests persistence CLI flag.
internal/​cli/​dumpconfig.go Dumps stranded-lifetime configuration.
go.mod Updates the Go toolchain version.
eth/​tracers/​parity.go Uses allocation-free log counting.
eth/​tracers/​parity_replay_tx.go Uses allocation-free log counting.
eth/​tracers/​api.go Uses allocation-free log counting.
eth/​sequencer/​adoption_test.go Stabilizes store-read readiness testing.
eth/​ethconfig/​gen_config.go Serializes address-cache persistence.
eth/​ethconfig/​config.go Exposes persistence in ETH configuration.
eth/​dropper.go Excludes all configured static peers.
eth/​dropper_test.go Tests peer drop eligibility.
eth/​backend.go Wires persistence and removes signer mutation.
docs/​cli/​server.md Documents new defaults and options.
docs/​cli/​example_config.toml Adds stranded-lifetime example.
docs/​cli/​default_config.toml Updates generated defaults.
Dockerfile.alltools Updates the Go builder image.
Dockerfile Updates the Go builder image.
core/​vm/​keccak_cache.go Adds bounded Keccak memoization.
core/​vm/​keccak_cache_test.go Tests Keccak cache bounds.
core/​vm/​interpreter.go Uses typed bounded shared caches.
core/​vm/​instructions.go Uses typed Keccak cache reads.
core/​vm/​instructions_test.go Updates Keccak cache coverage.
core/​vm/​evm.go Uses bounded ECRECOVER caching.
core/​vm/​evm_precompile_cache_test.go Updates ECRECOVER cache tests.
core/​vm/​ecrecover_cache.go Adds bounded ECRECOVER cache.
core/​vm/​bounded_cache.go Implements generic bounded memoization.
core/​types/​transaction_signing.go Removes unsafe fake signer.
core/​txpool/​validation.go Always validates transaction senders.
core/​txpool/​legacypool/​list.go Adds constant-time first transaction lookup.
core/​txpool/​legacypool/​list_test.go Tests first-element lookup.
core/​txpool/​legacypool/​legacypool.go Adds filtering and stranded eviction wiring.
core/​txpool/​legacypool/​legacypool_test.go Tests signer and authority filtering fixes.
core/​txpool/​legacypool/​legacypool_stranded.go Implements stranded-chain eviction.
core/​txpool/​legacypool/​legacypool_stranded_test.go Tests stranded-chain lifecycle.
core/​state/​v2_method_parity_test.go Accounts for the new log-count API.
core/​state/​statedb.go Exposes constant-time log count.
core/​state/​statedb_test.go Tests log-count consistency.
core/​state/​parallel_statedb.go Fixes balance boundaries and memoizes code hashes.
core/​state/​parallel_statedb_validate.go Validates bounded balance reads.
core/​state/​parallel_statedb_journal.go Invalidates reverted code-hash entries.
core/​state/​parallel_codehash_cache_test.go Tests code-hash cache invalidation.
core/​parallel_selfdestruct_balance_test.go Tests serial/V2 self-destruct parity.
core/​parallel_keccak_cache_bound_test.go Tests speculative cache memory bounds.
core/​parallel_extcodehash_hashcost_test.go Tests repeated code-hash performance.
core/​blockstm/​mvbalance_store.go Adds destruction-bounded delta reads.
core/​blockchain.go Creates bounded shared block caches.
consensus/​bor/​heimdall/​client.go Honors configured Heimdall timeouts.
consensus/​bor/​heimdall/​client_test.go Tests configured and fallback timeouts.
cmd/​keeper/​go.sum Updates keeper dependency checksums.
cmd/​keeper/​go.mod Updates keeper Go and indirect dependencies.
.golangci.yml Aligns linting with Go 1.26.8.
.github/​workflows/​kurtosis-stateless-e2e.yml Updates kurtosis-pos.
.github/​workflows/​kurtosis-sequencer-e2e.yml Updates kurtosis-pos.
.github/​workflows/​kurtosis-pipeline-e2e.yml Updates kurtosis-pos.
.github/​workflows/​kurtosis-e2e.yml Updates kurtosis-pos.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Oct 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.20253% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.73%. Comparing base (9c445ef) to head (33a9d96).

Files with missing lines Patch % Lines
core/txpool/legacypool/legacypool.go 80.00% 5 Missing and 2 partials ⚠️
eth/ethconfig/gen_config.go 0.00% 6 Missing ⚠️
eth/dropper.go 62.50% 3 Missing ⚠️
core/blockstm/mvbalance_store.go 60.00% 1 Missing and 1 partial ⚠️
core/txpool/validation.go 0.00% 0 Missing and 1 partial ⚠️
internal/cli/dumpconfig.go 0.00% 1 Missing ⚠️
internal/ethapi/api.go 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2492      +/-   ##
==========================================
+ Coverage   57.58%   57.73%   +0.15%     
==========================================
  Files         959      965       +6     
  Lines      176072   176419     +347     
==========================================
+ Hits       101390   101861     +471     
+ Misses      69006    68900     -106     
+ Partials     5676     5658      -18     
Files with missing lines Coverage Δ
consensus/bor/heimdall/client.go 51.11% <100.00%> (+2.22%) ⬆️
core/blockchain.go 72.75% <100.00%> (+0.28%) ⬆️
core/state/parallel_statedb.go 95.86% <100.00%> (+0.10%) ⬆️
core/state/parallel_statedb_journal.go 92.50% <100.00%> (+0.39%) ⬆️
core/state/parallel_statedb_validate.go 90.51% <100.00%> (ø)
core/state/statedb.go 78.73% <100.00%> (+0.02%) ⬆️
core/txpool/legacypool/legacypool_stranded.go 100.00% <100.00%> (ø)
core/txpool/legacypool/list.go 91.90% <100.00%> (+0.69%) ⬆️
core/types/transaction_signing.go 56.89% <ø> (+2.35%) ⬆️
core/vm/bounded_cache.go 100.00% <100.00%> (ø)
... and 34 more

... and 19 files with indirect coverage changes

Files with missing lines Coverage Δ
consensus/bor/heimdall/client.go 51.11% <100.00%> (+2.22%) ⬆️
core/blockchain.go 72.75% <100.00%> (+0.28%) ⬆️
core/state/parallel_statedb.go 95.86% <100.00%> (+0.10%) ⬆️
core/state/parallel_statedb_journal.go 92.50% <100.00%> (+0.39%) ⬆️
core/state/parallel_statedb_validate.go 90.51% <100.00%> (ø)
core/state/statedb.go 78.73% <100.00%> (+0.02%) ⬆️
core/txpool/legacypool/legacypool_stranded.go 100.00% <100.00%> (ø)
core/txpool/legacypool/list.go 91.90% <100.00%> (+0.69%) ⬆️
core/types/transaction_signing.go 56.89% <ø> (+2.35%) ⬆️
core/vm/bounded_cache.go 100.00% <100.00%> (ø)
... and 34 more

... and 19 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@marcello33
marcello33 merged commit a16f123 into master Oct 15, 2026
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants