Repository navigation
v2.10.3 candidate - #2492
v2.10.3 candidate#2492
Conversation
…er-tx code hashes
…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)
…ing tests manually (cherry picked from commit 083d153)
…eters (cherry picked from commit 956538d)
…city (cherry picked from commit 460eca8)
…not hash (cherry picked from commit 97c6d86)
…-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
build: bump Go toolchain to 1.26.8
core/state, eth/tracers: count logs without copying them when tracing
…s-517-518' into marcello33/cp-bor-2464
) * 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
params: bump version to v2.10.3
…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.
…s-517-518' into HEAD
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
…es-517-518 v2.10.3-private candidate
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
🔵 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 Report❌ Patch coverage is Additional details and impacted files@@ 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
... and 19 files with indirect coverage changes
🚀 New features to boost your workflow:
|
Summary
Publishes
v2.10.3: security and stability fixes on top ofv2.10.2. Code is identical tov2.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:
txpool.strandedlifetime, default3h), filtered addresses applied to SetCode authorities, pool signer no longer swapped whenallow-unprotected-txsis set (core/txpool: stop swapping the pool signer when allow-unprotected-txs is set #2464).[cache] addresscachepersist, defaultfalse).30s).Executed tests
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.v2.10.2, p50 import time unchanged.v2.10.3-privsince 2026-10-08, stranded-tx eviction reducing sentry pending pools as expected.Rollout notes
[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 old5stemplate default) will start using it. Remove the value or set it to30sunless you need something else.txpool.strandedlifetime(on by default,3h;0disables) and[cache] addresscachepersist(off by default; needs disk space for the snapshot, ~9 GB on mainnet with the default cache sizes).v2.10.3(latest), then backportmaster→develop.