Skip to content

feat: Tsuki hardfork — migrate to DogeOS reth/revm forks - #5

Merged
dghelm merged 42 commits into
mainfrom
feat/tsuki-hardfork-2
Aug 28, 2026
Merged

feat: Tsuki hardfork — migrate to DogeOS reth/revm forks#5
dghelm merged 42 commits into
mainfrom
feat/tsuki-hardfork-2

Conversation

@dghelm

@dghelm dghelm commented Jul 3, 2026

Copy link
Copy Markdown

Summary

Moves the rollup node onto the final DogeOS Tsuki/Reth 2 execution stack and completes the source, API, migration, persistence, test, and container changes required to run it safely.

The final provider family is immutable:

This PR does not consume DogeOS Reth PR #15.

Dependency topology

  • All DogeOS protocol-component crates resolve from the single dogeos-reth revision 8f0b98b0.
  • All direct clean-Reth crates resolve from the single DogeOS69/reth revision 972366a0.
  • Base REVM resolves to crates.io revm 36.0.0.
  • Scroll-specific execution behavior is supplied by revm-scroll from the immutable DogeOS revision dcf08768; that crate depends on mainline REVM.
  • There is no active scroll-tech/revm, op-revm, or scroll-reth dependency.
  • Alloy is aligned with the Reth 2 family, and the workspace/Docker toolchain is Rust 1.93 with resolver 3.

The source-verification guard checks the complete guarded package family and rejects stale revisions, mutable branch sources, retired forks, alternate URL spellings, and null/path substitutions. Its negative fixtures cover the immediately retired dogeos-reth@81c8b33e source and the retired branch-form DogeOS REVM source independently.

Main changes

  • Integrate the DogeOS Reth 2 component crates and migrate the rollup node, engine, sequencer, networking, RPC, primitives, and test fixtures to their APIs.
  • Retain DogeOS protocol behavior outside the clean Reth fork, including Tsuki execution hooks, payload construction, hardfork rules, and RPC/types.
  • Replace retired reth-scroll test and runtime surfaces with the DogeOS component APIs and fixture-owned handles.
  • Bound the eth-wire block ingress bridge and preserve peer attribution and signed-header handling without an unbounded remote-memory path.
  • Implement the supported one-way l2geth-to-Reth crossover using the inbound downloaded-header transform; reverse migration and the obsolete image workflow/scripts are removed.
  • Scope legacy-geth-header-transform to the heterogeneous Docker crossover test via LEGACY_GETH_HEADER_TRANSFORM=true on its sequencer and follower only. Normal and remote-source launch paths retain the baseline behavior.
  • Expose persistence tuning, consume the reviewed RocksDB durability backport, harden build/image metadata, and use a pinned external Anvil test binary.
  • Strengthen deterministic unit, integration, eth-wire, migration, signer-rotation, derivation, and Docker Compose coverage.

Validation

All checks are green for exact head bb895a8b:

Immutable image evidence

  • Source commit: bb895a8b8f47ed03f444491bb58d99bb6d5fb9eb
  • Image: dogeos69/rollup-node:pr5-bb895a8b
  • Digest: sha256:97452629af675b514a31d3462e23b9d1f80831d724d0f166520862f4badc3e2f
  • Build and provenance run

Consumers should use the digest, not the mutable tag, when immutable deployment identity is required.

Historical context

The PR began as a port of scroll-tech/rollup-node#500, but its final dependency graph no longer uses the old scroll-tech/revm feat/v103 branch or the abandoned scroll-reth repository. The provider pins and validation above describe the final head.

Update the workspace dependencies to build against the Tsuki hardfork
toolchain:

- Point all reth-*, reth-scroll-*, and scroll-alloy-* crates at
  DogeOS69/dogeos-reth rev 65bae46 (reth 1.11.1 base, Tsuki hardfork).
- Patch revm/op-revm to scroll-tech/revm branch feat/v103 to match the
  revm version used by dogeos-reth; revm-scroll resolves to
  DogeOS69/dogeos-revm tag tsuki-v0.4 transitively. This stays a branch
  ref (not a pinned rev) so it unifies with dogeos-reth's own internal
  revm reference; Cargo.lock still pins the exact commit.
- Pin the anvil (scroll-tech/foundry) and solar patches to full-length
  revs for supply-chain hygiene.
- Bump alloy to 1.6.3 / alloy-primitives 1.5.6 to match reth 1.11.1.
- Switch anvil test dep to scroll-tech/foundry feat/bump-dependencies
  and add the solar crates.io patches it requires.
- Bump rust-version and Docker images to 1.91; adopt resolver 3 so
  dependency selection stays MSRV-aware and avoids crates that require
  newer toolchains than the 1.91 build target.
- Add reth-tasks/test-utils to node, chain-orchestrator and watcher
  test-utils features.
- Exclude Cargo.toml from dprint formatting.

Cargo.lock alloy versions are pinned to the set that dogeos-reth 1.11.1
and the foundry/tempo/solar test dependencies compile against
(big-alloy 1.7.3, alloy-primitives/sol 1.5.7, alloy-chains 0.2.30).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dghelm
dghelm force-pushed the feat/tsuki-hardfork-2 branch from 9d2c4b9 to 65825bb Compare July 3, 2026 21:56
Port the source and test-utils changes required by the reth 1.11.1 /
Tsuki upgrade (mirrors scroll-tech/rollup-node scroll-tech#500):

- Migrate off the removed spawn / spawn_critical task helpers. pprof
  stays critical via spawn_critical_task; db_maintenance and
  scroll_network_manager use spawn_task to preserve their original
  non-critical behavior (a plain rename to spawn_critical_task would
  silently tear down the node if the network manager returns).
- Implement RpcHandleProvider::rpc_handle_mut on ScrollAddOnsHandle.
- Replace TaskManager with TaskExecutor in the node test harness, and
  build it with TaskExecutor::test() (lightweight 2-thread pools) rather
  than ::default(), which would allocate full CPU-sized pools per node
  and blow up thread counts on high-core CI under --all-features. Move
  the graceful-shutdown closure accordingly.
- Rename TransactionTestContext::transfer_tx_nonce_bytes to
  transfer_tx_bytes_with_nonce.
- Update the sequencer setup() call sites to the new 2-tuple return.
- Regenerate anvil_state.json for the newer anvil serialization
  (adds gas_refund_counter).
- Test stabilizers: bump txpool max_account_slots (with rationale),
  tolerate already-known transactions, wait on block_sequenced instead
  of a fixed sleep, raise integration timeouts to 120s, and run nextest
  with --test-threads 4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dghelm
dghelm force-pushed the feat/tsuki-hardfork-2 branch from 65825bb to fea90ef Compare July 3, 2026 23:24
dghelm and others added 24 commits July 10, 2026 19:12
Replace the two remaining inner.add_ons_handle.rollup_manager_handle
reads in the node e2e tests with the fixture-owned handle, import
DogeosChainSpecParser from this crate instead of the removed
reth-scroll-cli, and migrate the first two sequencer e2e tests from
reth_scroll_node::test_utils::setup to the setup_engine fixture used by
the rest of the file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Commit 98984de dropped the tokio_unstable rustflags while keeping the
ENABLE_CONSOLE_SUBSCRIBER runtime option, so a normally built binary
panicked at startup whenever the option was enabled. Restore the build
cfg so console_subscriber::init() works again.

The clean DogeOS Reth line (ae16009) compiles a tokio task-dump debug
endpoint whenever tokio_unstable is set, and tokio only provides
Handle::dump with its taskdump feature; enable it workspace-wide so the
graph builds. This activates tokio's optional, already-locked backtrace
dependency, adding one dependency edge to Cargo.lock. No package
revisions change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous guard exact-checked three anchor packages, dropped
null/path sources before inspecting DogeOS packages, matched retired
forks case-sensitively with fixed .git spellings, and accepted every
official-Reth revision. Rewrite it around a factored jq predicate that
validates every dogeos-*, reth-*, and revm-scroll package, pins each
guarded repository to its exact reviewed source, rejects null/path
sources for guarded families, and normalizes URL spelling before
matching retired forks.

The entry point still runs cargo metadata --locked --offline by
default but now accepts a metadata file, letting
verify_reth_sources_test.sh prove the negative cases (null/path
components, duplicate stale sources, alternate retired-fork spellings,
wrong REVM and official-Reth revisions) without touching Cargo.lock.
The fixture run is wired into the lint workflow next to the positive
check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per review, globally enabling tokio_unstable plus the taskdump feature
turned Reth's unauthenticated /debug/tokio/dump metrics route into a
live, expensive endpoint reachable in the repository's documented
deployment shape, and constrained compilation to Linux aarch64/x86.
Revert the build cfg, the taskdump feature, and its lockfile edge, and
remove the ENABLE_CONSOLE_SUBSCRIBER option together with the
console-subscriber dependency surface. Console support can return once
DogeOS Reth independently gates the task-dump route.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrite can_gossip_over_eth_wire through the fixture and orchestrator
event surface: with scroll-wire disabled, deterministically build a
block and assert the follower receives it over eth-wire, extends its
chain, and imports the identical block. The removed
EthWireProvider/eth_wire_block_listener() APIs do not exist at clean
Reth ae16009.

Replace the five removed BlockDataHint::none() calls in the derivation
pipeline tests with BlockDataHint::default(), the pinned type's empty
representation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The workspace requires Rust 1.93 but the integration-test image still
built with 1.91. Bump the builder image, pin cargo-chef to 0.1.71 as in
the main Dockerfile, and fetch git dependencies with the CLI for parity
with the main build. Token plumbing is intentionally not carried over:
the pinned dependency repositories are public.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reth's block-import callback cloned every remote block announcement
into an unbounded queue ahead of the serial rollup consumer, giving a
connected peer an avoidable remote memory-exhaustion path. Replace the
bridge with a bounded channel of 1000 announcements, matching the bound
the retired listener API enforced. Because BlockImport::on_new_block is
synchronous, the bridge now uses try_send: announcements that meet a
full queue are dropped with a rate-limited warning (at most one per
five seconds, with a dropped-count), and a closed queue drops silently
at trace level. Peer attribution and the signed-header transforms are
unchanged. Unit tests cover normal delivery, full-queue drops with drop
accounting, and a dropped receiver.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address two non-blocking review notes on the bounded bridge. Use
Sender::try_reserve to acquire a slot before cloning the announced
block, so a full queue no longer pays for a clone it would immediately
drop. Clarify in the drop warning that the dropped count aggregates
announcements across all peers and the logged peer id is only the most
recent sender (now `latest_peer`), not the sole source.

No behavioral change to delivery, drop, or closed-queue handling; the
existing bridge unit tests still pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move both coordinated provider families atomically to the reviewed
inbound/downloaded-header-only stack:

- 36 DogeOS69/reth entries: ae160090 -> f851224e (Reth PR #1 cleaned to a
  downloaded-header hook plus the approved RocksDB durability layer;
  drops PR #3's composite RPC handle layer);
- 11 DogeOS69/dogeos-reth component entries: c5198f7 -> 18adb117 (the
  provider repin that itself pins f851224e).

Cargo.lock regenerated through Cargo: 102 clean-Reth packages repin to
f851224e and 13 component packages to 18adb117, with no package,
version, or dependency-edge churn. revm-scroll (dcf0876), the official
paradigmxyz/reth dev pin (b25f32a), and all registry crates are
unchanged.

Point the source guard at the two new canonical sources and convert two
negative fixtures to inject the exact retired ae160090 and c5198f7
sources, proving the guard rejects both beside the good graph.

The networking API adaptation to the two-argument start_network and the
optional downloaded-header hook follows in a separate commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reth f851224e scopes the network header transform to downloaded headers
and restores the two-argument start_network. Adapt the rollup network
builder accordingly:

- set NetworkConfig.header_transform to the new Option hook and call the
  two-argument ctx.start_network(network, pool);
- remove the outbound ScrollRequestHeaderTransform (served-response
  transform) and its now-dead signature-serving path;
- since the inbound transform's insert_signatures persistence fed only
  that removed served path, drop the persistence, the network builder's
  Database field/constructor argument, and the now-unused DB imports
  (the block-signature schema/migration is left intact).

Gate the inbound transform behind an explicit temporary control:

- add --network.legacy-geth-header-transform (default false), threaded
  through RollupNodeNetworkArgs and ScrollNetworkBuilder;
- resolve_header_transform installs the hook only when enabled and
  rejects startup on DogeOS Mainnet (NamedChain::Scroll); the decision is
  gated on chain identity, not the signer, since Mainnet and Chikyu both
  configure one. With the flag off the hook is None (baseline path).

The inbound transform still canonicalizes downloaded legacy headers by
stripping the extra_data signature and still verifies the signer, now
explicitly documented as observability-only: it never drops or rejects a
header, exactly as before (the prior signer check only gated the removed
persistence). Live signed NewBlock gossip in the network manager and the
standard RpcHandle add-ons model are unchanged.

Focused adapter tests cover canonicalization with order/cardinality
preservation, the invalid/unauthorized-signature (header-retained)
result, and the enabled-Testnet / rejected-Mainnet / disabled hook
resolution. Their execution shares the known Tempo/Alloy E0119
dev-dependency blocker (anvil -> foundry-primitives -> tempo-alloy).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dghelm and others added 3 commits August 12, 2026 12:33
Under the approved Tsuki Testnet contract the geth-to-Reth transition is
one-directional: geth is retired after the cutover with no rollback or
recovery path. Retire the bidirectional migration artifacts accordingly.

Tests:
- rewrite docker_test_migrate_sequencer from a geth<->Reth alternation
  loop to a single one-way handoff: geth sequences, is frozen at its
  final head, all nodes are proven to reach that frozen head, then Reth
  sequences for the remainder;
- rewrite docker_test_heterogeneous_client_sync_and_sequencer_handoff to
  drop the network-partition step that made geth catch up from Reth and
  the step that returned production to geth, keeping the geth->Reth
  cross-client sync, the one-way handoff, and the Reth follower restart
  recovery.

Scripts/docs:
- remove switch-to-l2geth.sh and revert-l2geth-to-block.sh (geth
  rollback paths) and migrate-sequencer.sh (bidirectional driver);
- rewrite sequencer-migration/README.md to the one-way runbook and point
  the migration Dockerfile at the remaining forward scripts.

These docker tests are gated behind Docker and share the known
Tempo/Alloy E0119 dev-dependency blocker, so they are not executed here;
rustfmt validates their syntax.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace "unparseable" (flagged by codespell as a misspelling of
"unparsable") with a length-based description in the inbound-transform
adapter test; no behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Reth 2 component migration left two feature propagations un-updated,
which zepter flags (the target base's zepter check is green):

- rollup-node-primitives `arbitrary` -> `dogeos-reth-primitives/arbitrary`
  (Cargo.lock gains the required `arbitrary` edge under
  `dogeos-reth-primitives`);
- scroll-network `serde` -> `dogeos-protocol-types/serde`.

`zepter run check` now passes. No default-feature behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dghelm added 7 commits August 12, 2026 16:28
feat: consolidate Tsuki migration onto inbound-only clean Reth (f851224e + component 18adb117)
* fix(tests): launch pinned external Anvil

* ci(tests): install checksum-pinned Anvil

* fix(ci): print absolute Anvil path
chore(deps): pin canonical txpool recovery providers
…#33)

* feat(node): exit on authorized signer rotation

* fix(node): bound signer rotation polls

* fix(node): harden signer rotation safeguards

* fix(docker): use supported DogeOS chain aliases
* fix(orchestrator): hold derived batches while engine syncs

* fix(orchestrator): harden held-batch recovery

* refactor(orchestrator): simplify held-batch handling

* fix(orchestrator): bound held L1 notifications

* test(orchestrator): cover in-flight FIFO overflow

* fix(orchestrator): address syncing-hold review findings

* fix(orchestrator): defer L1 intake during derivation

* test(orchestrator): stabilize deferred L1 regressions
@dghelm
dghelm marked this pull request as ready for review August 16, 2026 19:06
dghelm and others added 2 commits August 16, 2026 14:33
Sync the Tsuki hardfork line with main's Blacksmith CI migration and Docker
build optimizations (cargo-chef cache reuse, single rollup-node binary,
Dockerfile.test consolidation).

Conflict resolutions:
- Dockerfile: keep the github_token secret mounts required to fetch the
  private dogeos-reth dependency, and adopt main's CARGO_TARGET_DIR env +
  cargo-chef artifact-reuse comment.
- release.yml: retain the private-dep secret alongside main's registry
  cache-from in the PR build step.
- Dockerfile.test: accept main's deletion (no remaining references).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reset the DogeOS rollup-node line to a 0.x devnet series and set the
workspace version so image tags and OCI labels agree for the
v0.3.0-beta.0 devnet build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codspeed-hq

codspeed-hq Bot commented Aug 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing feat/tsuki-hardfork-2 (bb895a8) with main (9cbdc6f)

Open in CodSpeed

dghelm and others added 3 commits August 16, 2026 15:35
This workflow is an upstream-Scroll leftover: it fired on every tag and
pushed to the scrolltech/sequencer-migration namespace using our Docker
Hub credentials. The DogeOS fork builds its image via release.yml
(dogeos69/rollup-node), so this only produced failing or misdirected
runs. Remove it so DogeOS release tags build a single, correct image.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Repin workspace DogeOS Reth components to 8f0b98b056111e8f497a4c6dd78ef1f776b626a5, regenerate Cargo.lock, and update source-guard fixtures. Scope legacy geth header transform to the docker-compose test lane, and align sequencer/node e2e with DogeOS_DEV (Tsuki Never for the signed Galileo fixture; empty in-family batch calldata; DEFAULT_BASE_FEE_OVERHEAD).
Restore default nextest concurrency on the Blacksmith 2 vCPU
integration job so four Anvil/Reth clusters cannot starve the
runner agent. Keep the same tests, skip list, runner, and timeout.
@dghelm
dghelm merged commit bebc1ae into main Aug 28, 2026
18 checks passed
@dghelm
dghelm deleted the feat/tsuki-hardfork-2 branch August 28, 2026 13:49
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.

2 participants