Skip to content

Bump Base to v1.5.4 - #41

Merged
sduchesneau merged 26 commits into
release/1.xfrom
bump/base-1.5.4
Nov 6, 2026
Merged

sduchesneau merged 26 commits into
release/1.xfrom
bump/base-1.5.4

Conversation

@dfuse-bot

Copy link
Copy Markdown

Merges upstream Base v1.5.4 (with v1.5.2 and v1.5.3) into release/1.x. Tag v1.5.4-fh3.1 once merged.

Upstream recommends this release for synchronization and block propagation at 200 ms block times. It also raises the engine persistence defaults (--engine.persistence-threshold 7 → 70, --engine.memory-block-buffer-target 5 → 70, --engine.persistence-backpressure-threshold 16 → 160); set them explicitly to keep the old values.

Merge and tag streamingfast/reth#89 first. Upstream moves its reth pin from base-v2.5.2.8 to base-v2.5.2.11, so this PR pins streamingfast/reth base-v2.5.2.11-fh3.1, which streamingfast/reth#89 releases. Until that tag exists, this branch does not build. Cargo.lock records that PR's head commit (9f9f5efa1) under the tag; it stays reachable from the tag as long as base#89 is merged with a merge commit. After tagging, cargo update -p reth-firehose moves the lock to the tagged commit (same tree).

firehose-tracer stays on 5.7.0 and the Firehose block model is unchanged, so the tag keeps fh3.1.

Besides the merge:

  • Conflicts: Cargo.toml (reth pins; kept our extra crates and moved every base/reth pin to base-v2.5.2.11 and every streamingfast/reth pin to base-v2.5.2.11-fh3.1), crates/execution/payload/src/builder.rs (kept the Firehose trace of blocks built from payload attributes alone with the new build_payload closure), crates/builder/multiplex/src/service_builder.rs (kept OpFirehoseEvmConfig with upstream's imports), Cargo.lock (upstream's lock plus our Firehose crates; no other version changed).
  • ACTIVATIONS.md: Denim active on Base mainnet, statuses refreshed against v1.5.4.
  • CHANGELOG entry below.

CHANGELOG

## v1.5.4-fh3.1

### Changed

* Rebased on upstream Base `v1.5.4` (with `v1.5.2` and `v1.5.3`), recommended for synchronization
  and block propagation at 200 ms block times. Uses `streamingfast/reth` `base-v2.5.2.11-fh3.1`;
  `firehose-tracer` stays on 5.7.0 and the Firehose block model is unchanged.
* Upstream raises the engine persistence defaults of `base-reth-node` to 70 blocks
  (`--engine.persistence-threshold`, `--engine.memory-block-buffer-target`) and 160 blocks
  (`--engine.persistence-backpressure-threshold`). After an unclean shutdown the node executes
  the blocks it held in memory again and emits their FIRE BLOCK lines again: up to about 14 s of
  chain at 200 ms blocks, instead of about 1 s.

Test Execution Summary

Branch bump/base-1.5.4: release/1.x at v1.5.1-fh3.1 + git merge v1.5.4. Built and tested against streamingfast/reth bump/base-v2.5.2.11 at 9f9f5efa1, served locally as the base-v2.5.2.11-fh3.1 tag through a url.<local mirror>.insteadOf git redirect (CARGO_NET_GIT_FETCH_WITH_CLI=true). The tag does not exist on GitHub yet.

Build Status

  • cargo build --release --package base-reth-node --bin base-reth-node --package base-consensus --bin base-consensus (same command as Dockerfile.sf): PASSED (5 min 18 s)
  • cargo test --no-run -p base-execution-firehose -p base-firehose-tests -p base-firehose-flashblocks -p base-reth-node -p base-execution-chainspec -p base-common-genesis -p base-common-chains -p base-execution-payload-builder -p base-builder-multiplex -p base-reth-cli: PASSED
  • cargo clippy -p base-reth-node -p base-builder-multiplex -p base-execution-payload-builder --tests: PASSED. No warning in a file this merge touches; the warnings left are in crates/firehose-flashblocks/src/processor.rs, crates/execution/firehose and crates/execution/flashblocks/src/traits.rs, which this merge does not change.
  • Smoke run: base-reth-node node --chain base --datadir <empty dir> --disable-discovery for 60 s: PASSED. Prints FIRE INIT 3.1 reth base-1.5.4 and the genesis FIRE BLOCK 0, lists Denim @1793901600; node --help shows --engine.persistence-threshold defaulting to 70.

Unit Tests

Package Status Notes
cargo test -p base-firehose-tests PASSED 14 tests (prestate replay, EIP-8130 tracing)
cargo test -p base-firehose-flashblocks PASSED 44 tests
cargo test -p base-reth-node PASSED 2 tests
cargo test -p base-execution-firehose PASSED no unit tests in the crate
cargo test -p base-execution-chainspec PASSED 49 passed, 1 ignored (upstream)
cargo test -p base-common-genesis PASSED 103 tests
cargo test -p base-common-chains PASSED 52 passed, 1 ignored (upstream)
cargo test -p base-execution-payload-builder PASSED 144 passed, 1 ignored; covers the conflict resolved in builder.rs
cargo test -p base-reth-cli PASSED 16 passed, 1 ignored; covers the new engine defaults
cargo test -p base-builder-multiplex FAILED (not merge-related) 11 passed, 1 failed: in_process_smoke::payload_builder_modes_match_flashblocks_baseline returns Invalid payload attributes (-38003). It fails the same way on pure upstream v1.5.4 and on release/1.x (v1.5.1-fh3.1), so it is not caused by this merge
cargo test -p reth-firehose -p reth-firehose-tests (in streamingfast/reth bump/base-v2.5.2.11) PASSED 35 + 2 tests
cargo test -p reth-engine-tree --test firehose_live_tracing --test firehose_live_tracing_bal (same checkout) PASSED 2 tests
cargo test -p reth-trie --lib node_iter (same checkout) PASSED 2 tests, the iterator changed in base-v2.5.2.11

Integration Tests

  • Status: PASSED
  • RUSTFLAGS="-C debug-assertions=off" RUST_MIN_STACK=33554432 cargo test -p base-system-tests --test firehose_denim --test firehose_b20 --test firehose_cobalt_b20, Docker-backed (after forge soldeer install && forge build in crates/utilities/test-utils/contracts):
Test Status Time
firehose_b20::b20_transfer_is_traced PASSED 139.3 s
firehose_cobalt_b20::cobalt_b20_surfaces_are_traced PASSED 54.4 s
firehose_denim::denim_activation_block_traces_base_time_install PASSED 51.3 s

Battlefield Tests

  • Status: PASSED
  • Pass/Fail: 79 passing, 25 pending, 0 failing
  • streamingfast/battlefield-ethereum at 879ea9a (origin/HEAD), op-reth-devnet suite with this branch's release base-reth-node (1.5.4) as the Firehose node: ./scripts/optimism/run_optimism_devnet.sh (with op-node built from streamingfast/optimism release/op-reth-2.x), then OP_RETH_BINARY=<base>/target/release/base-reth-node RUST_MIN_STACK=33554432 ./scripts/run_firehose_op_reth_devnet.sh, then pnpm test:fh3.0:op-reth-devnet. All snapshots matched; none changed. Header corresponds to RPC and Compare blocks: Firehose blocks match RPC blocks passed. No ERROR or panic in the node log (304 blocks).
  • The 25 pending tests are gated on forks or features this devnet does not have (Amsterdam/BAL, slot number, Transfer logs, blobs, millisecond timestamps, chain-specific assets, Arbitrum and BSC specifics).
  • The devnet script needed two local workarounds that are not in the suite: start builder-playground with --keep and wait for the op-geth container as well as op-node before reading its name (it raced and exited once). Its bproxy container also exited once because op-rbuilder did not resolve yet.
  • The devnet runs the OP Stack forks up to Isthmus from genesis, not Base's own upgrades (Azul, Beryl, Cobalt, Denim, Everest). Denim and Cobalt are covered by the system tests above.

Firehose bug patterns

  1. Serial order: the validity pool, resting predicate carry-over and the resting sweep (which now runs on a task executor worker) evaluate txpool predicates only; they never run the EVM on the traced executor. Sequencer catch-up sizing and gossip queue changes are in consensus. BuiltBlock::trace for blocks built from payload attributes alone is kept after the build_payload signature change. None found.
  2. Emit after accept: no change to crates/execution/consensus or engine validation. The base reth bump changes the trie iterator seek, which runs during state root validation before mark_verified() prints the block. The new persistence defaults (70 / 70 / 160 blocks) only mean that after an unclean shutdown the node executes and prints again up to about 14 s of blocks it held in memory. None found.
  3. Activations: no new BaseUpgrade and no schedule change in crates/common between v1.5.1 and v1.5.4. Denim is now active on Base mainnet (first Denim block 53_556_127 at 1_793_901_601). Everest stays unscheduled: no timestamp in code, and getSchedule() on the configured L1 protocol_versions_address reverts on both L1s. ACTIVATIONS.md refreshed.
  4. Fields: no change to crates/common (consensus types, RPC types) in the range, and no change to the reth mapper. None found.

Open questions

  • in_process_smoke in base-builder-multiplex. payload_builder_modes_match_flashblocks_baseline fails with Invalid payload attributes here, on pure upstream v1.5.4 and on v1.5.1-fh3.1 alike. I left it alone since it is not caused by this merge; someone may want to check whether it also fails in upstream CI.
  • Cargo.lock after tagging. I kept the lock on fix: logging inconsistencies base/base#89's head commit rather than leaving the reth entries stale. If fix: logging inconsistencies base/base#89 is squash- or rebase-merged, run cargo update -p reth-firehose once the tag exists before merging this one.

github-actions Bot and others added 26 commits October 24, 2026 09:46
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* chore(proof): bump SP1 to 6.10.0

Bump host and guest SP1 crates and the cargo-prove Docker tag to v6.10.0, sp1-cluster to v2.9.0, kzg-rs to 0.2.9, and the sp1-patches guest patches to their 6.10.0 tags.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 510820c)

* ci: bump SP1 setup actions to v6.10.0

Update the sp1-version default and SP1UP_REF in the GitHub and Depot setup actions so CI installs cargo-prove v6.10.0, matching etc/just/succinct.just.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit b1272d6)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…oning the submitted batch to v1.5.2 (base#6223)

* fix(txpool): store each validity predicate once by partitioning the submitted batch

Compiled conditions cloned balance, nonce, and storage predicates out of the
submitted batch while keeping the full batch for forwarding, roughly doubling
the heap attributed to validity transactions. Move each predicate into exactly
one partition and re-combine them when forwarding to a builder.

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
(cherry picked from commit cece5ad)

* bench(payload): measure validity condition memory and evaluation with interleaved timing predicates

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
(cherry picked from commit e68ab19)
Co-authored-by: Toshi <toshi-noreply@coinbase.com>

---------

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
…hblocks on follower nodes to v1.5.2 (base#6220)

* fix(txpool): expire validity transactions at received flashblocks on follower nodes

Validity transactions are evicted at their inclusive flashblock deadline as
soon as the builder publishes that flashblock, so an unbumped same-nonce
replacement can be admitted mid-block. That expiry only ran on the builder.
Transaction ingress is mempool-node first, and those nodes only expired on
block commit, so the stale predecessor kept its nonce slot and the
replacement was rejected as underpriced for the rest of the block.

Add `FlashblockExpiry::expire_published` to record a flashblock observed
from the builder's stream under the admission lock, and have the flashblocks
node extension route every received flashblock through the local pool before
the pending-state processor. A node-level regression test submits a validity
transaction through `base_sendRawTransactionValidity`, feeds its deadline
flashblock through the follower, and asserts the unbumped replacement is
admitted via `eth_sendRawTransaction` before the block commits.

Linear: CHAIN-6241
Co-authored-by: Toshi <toshi-noreply@coinbase.com>

* fix(txpool): bound follower-recorded flashblock position to the canonical tip

A follower records the published position from the websocket stream, which
is not authoritative for the pool: a stream for another network, a corrupt
frame, or a misbehaving proxy could record a position far ahead of the chain,
drain every validity transaction behind it, and reject every later deadline
until a reorg. Ignore received flashblocks that are already canonical or more
than `RECEIVED_FLASHBLOCK_MAX_LEAD` blocks ahead of the pool's last seen
block; block commit still expires those deadlines.

Linear: CHAIN-6241
Co-authored-by: Toshi <toshi-noreply@coinbase.com>

* Revert "fix(txpool): bound follower-recorded flashblock position to the canonical tip"

This reverts commit e03d9c7.

* chore(docs): restamp flashblocks-node README in the docs index

The release branch still carries the committed docs index; the README gained
a pool deadline expiry section, so its summary and digest need refreshing.

Co-authored-by: Toshi <toshi-noreply@coinbase.com>

---------

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
…e#6222)

Keep the resting-predicate index between payload jobs so a validity
transaction found unsatisfied in one block is not re-evaluated in the next
until a commit or pre-block write changes the state its predicate reads.
Today the first flashblock of every block re-evaluates every resting
transaction; after Denim every one-shot native block would.

- Move the resting set into base-execution-payload-builder as
  RestingPredicates and RestingPredicateStore, shared by the flashblocks
  and native builders.
- Carry members only when the next block builds on the block this builder
  finished; wake members from pre-block system calls and deposits through
  the block-start TransitionState; always release block-number blockers;
  drop members not yielded for 10-20 blocks.
- Extend the existing --builder.resting-predicates mode instead of adding
  a flag: the flashblocks builder carries the set across flashblocks and
  blocks, and the native builder carries it across blocks from Denim on.
- Move the resting parked and shadow-mismatch counters to the shared
  validity metrics, and add carry-over metrics.

Backport to v1.5.2. The benchmarks from the main change are left out
because their scaffolding is not on this branch, and the validity
evaluation counters keep this branch's string labels.
…base#6239)

* test(consensus): reproduce startup reset cancellation by admin queries

Add an intentionally failing regression test using the real sequencer actor and queued engine client. Hold the startup reset response while servicing read-only admin queries, then assert the response receiver survives and no replacement reset is submitted.

Amp-Thread-ID: https://ampcode.com/threads/T-daeea7bf-86c0-43de-a2d5-3430dbf84abe
Co-authored-by: Julian Meyer <julian.meyer@coinbase.com>

* fix(consensus): retain startup reset across admin queries

Pin each startup reset attempt across the admin-query select loop so read-only queries cannot drop its response receiver and cause replacement resets. Preserve shutdown, takeover, shadow gating, and deferred-reset backoff behavior.

Amp-Thread-ID: https://ampcode.com/threads/T-daeea7bf-86c0-43de-a2d5-3430dbf84abe
Co-authored-by: Julian Meyer <julian.meyer@coinbase.com>

---------

Co-authored-by: Amp <amp@ampcode.com>
(cherry picked from commit dadb34f)

Adapted for releases/v1.5.2: the new test no longer sets `schedule_delay`, which
base#5560 added on main only; this branch has no such field.

Co-authored-by: Julian Meyer <julian.meyer@coinbase.com>
… builder (base#6241)

Backport of base#6184 to releases/v1.5.2. The schedule flag previously reached
only the standalone execution node's native payload builder; base-builder and
base sequencer (the unified binary) built the native payload config from
`ResourceMeteringConfig::default()`, so a mounted schedule had no effect.

`base_builder_cli::Args` now carries `--payload.resource-metering-schedule`
(`PAYLOAD_RESOURCE_METERING_SCHEDULE`), builds `ResourceMeteringConfig`
through `from_parts`, and `MultiplexingServiceBuilder::native_payload_config`
copies the resulting config instead of overriding it with the default.
`--builder.enable-resource-metering` is the single switch for both the
Flashblocks metering store and native schedule evaluation.

Adaptation to releases/v1.5.2: only the import list in
`crates/builder/cli/src/args.rs` conflicted, because the release branch still
carries `ShadowValidityConfig`; both imports are kept. Every other file
applies with byte-identical hunks.

Added `sequencer_schedule_wiring_feeds_the_multiplexed_native_payload_builder`
to cover the unified binary's CLI-to-multiplexer path, which the original PR
only covered up to `BuilderConfig`.

(cherry picked from commit e6f58f8)
…flashblocks block-start path to v1.5.2 (base#6278)

* fix(builder): sweep unseen resting validity transactions off the block-start path

`RestingPredicates::begin_block` walked the whole resting set every
`RESTING_UNSEEN_RETAINED_BLOCKS` blocks to drop members no build had
yielded. The flashblocks builder calls it between the forkchoice update
and `calculate_flashblocks`, so on those blocks the whole flashblock
schedule started late by however long the sweep took. With a large
resting set that is long enough to cost several flashblocks, every tenth
block.

- Move the sweep out of `begin_block`. `RestingPredicateStore::finish`
  runs it when a sweep block finishes, on a named reth task-executor
  worker, so it overlaps the state root and the leeway. `take` waits for
  an unfinished sweep and records the wait.
- Derive the flashblock schedule before carrying the resting set, and
  anchor the flashblock timer to that instant, so block-start work can
  only shorten the first flashblock.
- Add `resting_predicate_begin_block_duration`,
  `resting_predicate_sweep_duration`,
  `resting_predicate_sweep_wait_duration` and
  `flashblocks_schedule_delay`, plus `resting_begin_block` and
  `resting_unseen_sweep` debug spans.
- Add `resting_carry`, `native_resting_sweep` and
  `flashblocks_resting_sweep` benches that carry a large resting set.

* perf(payload): sweep resting validity transactions by generation every block

The unseen sweep walked every member every 10 blocks. Off the flashblocks
block-start path it overlaps the leeway, but the native post-Denim builder
has no leeway: the next build waits for any sweep that outlasts the state
root, and the cost arrives as a spike every 10 blocks.

File each member under the block that rested it and sweep, at the end of
every block, only the generation that is `RESTING_UNSEEN_RETAINED_BLOCKS`
old: members not seen since are dropped and the rest are re-filed under the
block that last saw them. `hold` is unchanged, so the selection loop does
no extra work. A member now leaves the set exactly
`RESTING_UNSEEN_RETAINED_BLOCKS` blocks after it was last seen, instead of
between one and two windows.

ABBA against the previous behaviour, `native_resting_sweep` (100k live
resting transactions, 4.8k churned per block, 4 runs each): with the next
block starting as soon as the last one finishes, the 29-31ms carry on one
block in ten becomes a 3.3-4.5ms sweep wait on every block. With 20ms
between blocks for the state root, carry is under 0.02ms on every block,
against 32-54ms on one block in ten before.

* fix(builder): take only the resting carry out of the first flashblock

Anchoring the flashblock timer to the moment the schedule was derived also
took the fallback build, the payload send and the index-0 publish out of
the first flashblock on every block. When those outlast a short first
offset, the first tick is already in the past and missed ticks fire back
to back, cancelling flashblocks before they build anything.

Start the timer where it started before and shorten only the first tick
by the resting carry, capped at the whole first flashblock so the first
tick is never in the past.

`RestingPredicates::rest` also listed a member in the current generation
again when it rested twice in one block. The sweep skipped the duplicate,
but it cost memory and sweep time per call rather than per member.

* fix(payload): drop stale resting generations when the set empties

`finish` skipped an empty set before the sweep, so generation entries for
members removed by inclusion, wakeups or rescans stayed listed. A builder
whose resting transactions all clear before the block finishes would pile
them up, and the next sweep over a non-empty set would walk the whole
backlog at once. With no members left every entry is stale, so clear them.

* fix(payload): bound the wait for the previous block's resting sweep

`take` runs before the fallback build and before the native selection
loop, so waiting without limit for a slow sweep could delay the payload
itself. Wait at most `RESTING_SWEEP_WAIT_LIMIT` (25ms), then start with an
empty set, which only means re-evaluating every validity transaction as
after a reset. The sweep finishes on its worker and drops the set there.
Count give-ups in `resting_predicate_sweep_wait_timeouts_total`.

Also update the `resting_predicate_begin_block_duration` description,
which still placed the carry before flashblock scheduling.

* fix(builder): wait up to one flashblock interval for the resting sweep

The flashblocks builder gave up on the previous block's sweep after the
same 25ms as the native builder. Its sweep has already overlapped the
state root and the leeway, and starting with an empty set means
evaluating every validity transaction again in the first flashblock, so a
longer wait pays off there. Make the wait limit a `take` argument: the
flashblocks builder waits up to one flashblock interval, so a slow sweep
costs at most about one flashblock, and the native builder keeps 25ms.
…on flow to v1.5.2 (base#6330)

* feat(txpool-tracing): label inclusion metrics by transaction flow

Validity transactions can wait in the pool until their predicates hold, so
mixing them with standard transactions makes the slow-inclusion share and
latency quantiles hard to read. Resolve each transaction's flow from its
validity conditions when it enters the pending or queued pool, and label the
inclusion duration, healthy/slow inclusion and end-to-end inclusion metrics
with `flow` (`standard` or `validity`), matching the builder's flow label.

* docs: refresh txpool-tracing docs index summary
…celled (base#6395)

The flashblocks and native selection loops returned straight out of the
loop when the build was cancelled, skipping every metric recorded after it:
`validity_predicate_eval_duration_per_block`,
`validity_predicate_candidates_evaluated_per_build`,
`validity_candidate_handling_duration`, `predicate_bucket_depth`,
`resting_predicate_parked_total` and the payload builder histograms.

A flashblock whose selection loop runs until the deadline is the build
where validity handling costs the most, so these series went silent
exactly when they mattered. On mainnet on 2026-11-02, every flashblock
build hit the deadline from about 12:15 UTC and the predicate dashboards
dropped to 0 while per-transaction counters kept climbing.

Break out of the loop instead, so the post-loop recording runs for
cancelled builds too. The flashblocks builder still reports the build as
cancelled through `FlashblockDiagnostics::cancelled` and the
`flashblock_selection_total{outcome="cancelled"}` counter, and the native
builder still returns `Some(())` for a cancelled scan.
…se#6398)

Adds a txpool.validity.predicates_per_tx histogram recorded alongside txpool.validity.admitted at every pool admission site, so dashboards can read the average and distribution of predicates per validity transaction.
…se at their target to v1.5.2 (base#6396)

* fix(batcher): flush the compression stream so channels close at their target (base#6393)

* fix(batcher): flush the compression stream so channels close at their target

Brotli holds up to about one window (4 MiB) of input before it emits
anything. CompressionStream never flushed, so output_size(), which drives
the channel soft target, stayed at zero until Brotli emitted about 1.17 MB
at once, and any compressed_size_target below that closed the channel at
about 1.17 MB.

Flush the encoder once 512 KiB of input has been appended since the last
flush. A flush keeps the window, so it only adds a meta-block boundary.
The trigger counts input bytes, not blocks: block sizes vary widely across
chains, and a fixed block count of large blocks can exceed the window.

* fix(batcher): derive the compression flush interval from the size target

With a fixed 512 KiB flush interval, the emitted bytes the target is checked against can trail the real compressed size by up to 512 KiB of input, so a target well below that, such as 150 KB, cannot be honored. Flush every quarter of the target instead, so the lag and the overshoot stay small relative to any target, at a constant few flushes per channel. Channels without a target no longer flush.

(cherry picked from commit e3507dd)

* chore(docs): restamp docs index for batcher READMEs

* fix(batcher): count flush overhead in the compression-size bound

Each flush ends a Brotli meta-block early, which costs one more meta-block
header and up to two bytes of padding, so max_output_size() could undercount
streams with a short flush interval. Charge 6 bytes per possible flush, at most
one per flush interval of input, and cover a one-byte interval in the bound
test.

* fix(batcher): make a zero compression flush interval unrepresentable

CompressionStream::new took the flush interval as Option<usize>, so a
caller passing Some(0) made max_output_size divide by zero. Take
Option<NonZeroUsize> instead, and have Channel::flush_interval return
None for a zero target.

Co-authored-by: Toshi <toshi-noreply@coinbase.com>

---------

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
…er a failed forward to v1.5.2 (base#6402)

* [backport] perf(tx-forwarding): resend validity transactions only after a failed forward to v1.5.2

Backport of base#6401.

* docs: restamp tx-forwarding and transaction-events docs index entries

* perf(tx-forwarding): count resends per fill and record them once

* fix(tx-forwarding): share the already-imported check with the builder and floor the validity hold
…ol iterator to v1.5.2 (base#6403)

* perf(txpool): park resting validity transactions in the pool iterator (base#6256)

Backport of base#6256 to releases/v1.5.2, adapted to the release tree, which
lacks base#6251/base#6252 and already carries the base#6277 resting sweep.

(cherry picked from commit b65abe2)

* fix(txpool): interrupt held resting walks when the build is cancelled

Since base#6256 the pool iterator parks resting validity transactions itself, so
one `next` call can advance past the whole resting set without returning to
the build loop. The build loop used to check cancellation, and the native
builder finalization requests, before each of those members; with 120k
resting members the walk takes about 100ms of a flashblock and could not be
interrupted.

`BestTransactionsHold::is_interrupted` lets a hold end the walk. The parking
iterator checks it every `HOLD_INTERRUPT_INTERVAL` (256) holds and returns
without a source head, and the build loop then observes the same
interruption. The flashblocks builder interrupts on the flashblock's
cancellation token. The native builder interrupts once the job is cancelled
or asked to finalize, observing its `CancelOnDrop` through a weak reference
so the hold never owns a clone whose drop would cancel the job.

Also:
- `native_resting_sweep` installs the hold, as the production builder does.
  It measured the build loop evaluating every resting member instead.
- The native builder records the hold's time as
  `resting_predicate_hold_duration`; it was measured and discarded.

* fix(builder): report interrupted flashblock selection as cancelled

An interrupted resting hold ends the pool iterator with `None`, so the
selection loop exits before its per-candidate cancellation check and the
flashblock was labelled `pool_drained`/`pool_empty`. Re-check the token after
the loop.

Also makes `flashblock_hold` a public, re-exported function, per CLAUDE.md.

---------

Co-authored-by: Haardik H <haardik.haardik@coinbase.com>
…idity pool to v1.5.2 (base#6400)

* feat(txpool): hold validity transactions in a separate validity pool

Backport of base#6253 to releases/v1.5.2, re-implemented on the release's
transaction pool.

Every transaction carrying validity predicates (protocol-nonce and EIP-8130
channel or nonce-free) is admitted to a dedicated, separately bounded
validity pool instead of reth's pending/queued subpools, so validity
transactions that rest on hot state can no longer crowd out standard
transactions, and a standard flood cannot evict validity transactions.

Validity lanes keyed on the protocol nonce follow reth's pending prefix for
the same sender, protocol-nonce slots stay exclusive across stores under the
price bump, and the builder merges the stores by tip without yielding a
nonce before its predecessor.

New flags: --rollup.validity-pool-max-count, --rollup.validity-pool-max-size,
--rollup.validity-pool-max-account-slots.

Release adaptations: the EIP-8130 sidecar keeps this release's uncapped
limits; tip backing, allowlisted payers, best-transaction holds, guard
replacement checks and state-diff nonce advances are main-only and are not
ported. Benchmarks are omitted because the release has no bench harness.

* fix(txpool): drop unused test imports and restamp the txpool docs summary

* fix(txpool): drop block-expiry entries of evicted lane-store transactions

* fix(txpool): reject EIP-7702 delegation on validity transactions

Validity transactions live in their own pool, which does not enforce reth's in-flight limits for delegated accounts and pending authorizations. Rather than share those limits across pools, a transaction with validity predicates is rejected when it is an EIP-7702 transaction or its sender is delegated, and a state diff that changes an account's code drops that account's validity transactions.
…fter Denim to v1.5.2 (base#6422)

* fix(txpool): reject flashblock-index validity predicates after Denim

After Denim the sequencer builds native 200ms blocks without flashblocks,
and the native builder skips every transaction that carries a
flashblock-index predicate. Ingress still admitted them, so submitters got
a transaction hash back for a transaction that could never be included. It
then sat in the validity pool, counting toward the resting set and the pool
cap, until its block expiry.

On Base Sepolia, which has Denim active, a validity transaction with
`flashblock_index >= 1` was accepted through the public endpoint, forwarded
to the sequencer, evaluated as `unsupported` in every block and never
included.

Reject these submissions in `base_sendRawTransactionValidity` with an
invalid-params error once the block being built is a Denim block, using the
same transition check as the expiry window. The mempool nodes run this same
ingress, so the submitter sees the error directly.

* fix(txpool): reject flashblock-index predicates before forwarding

Run the post-Denim flashblock-index rejection before a forwarding node
proxies the request upstream, so the submitter gets the error from the
first node it reaches. A forwarding node that cannot read its head defers
to the upstream node, which runs the same check.
…ow-ups) (base#6416)

* fix(deps): pin reth backport of eth_getLogs blocking-pool fixes for v1.5.2

Co-authored-by: Toshi <toshi-noreply@coinbase.com>

* chore(deps): pin reth to base-v2.5.2.10

---------

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
Co-authored-by: William Law <williamlaw.wtl@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Carries base/reth#39, the trie node iterator seek-boundary fix, on the
releases/v1.5.3 line.

Generated with Claude Code

Co-authored-by: Claude <noreply@anthropic.com>
…ump (base#6444)

The reth pin bump in base#6442 re-resolved several third-party crates to
older versions. Restore them so the lockfile differs from the pre-bump
state only in the base/reth source lines.

Generated with Claude Code

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…v1.5.4 backport) (base#6321)

* [backport] fix(consensus): size sequencer catch-up buffer for fast block times to v1.5.2 (base#6320)

Co-authored-by: Toshi <toshi-noreply@coinbase.com>

* test(consensus): cover regular gossip gap against catch-up window

Co-authored-by: Toshi <toshi-noreply@coinbase.com>

* test(actions): pass catch-up batch limit in shadow sequencer action test

Co-authored-by: Toshi <toshi-noreply@coinbase.com>

---------

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
….5.4) (base#6464)

* fix(reth-cli): scale engine persistence defaults for 200ms blocks

* docs: restamp reth-cli README in docs index

@sduchesneau sduchesneau 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.

LGTM

@sduchesneau
sduchesneau merged commit 14cf389 into release/1.x Nov 6, 2026
2 checks passed
@sduchesneau
sduchesneau deleted the bump/base-1.5.4 branch November 6, 2026 21:13
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.