Skip to content

fix(kona): load DependencySet from embedded registry, oracle as fallback#20377

Merged
ajsutton merged 11 commits intodevelopfrom
aj/fix/kona-depset-embedded
Apr 29, 2026
Merged

fix(kona): load DependencySet from embedded registry, oracle as fallback#20377
ajsutton merged 11 commits intodevelopfrom
aj/fix/kona-depset-embedded

Conversation

@ajsutton
Copy link
Copy Markdown
Contributor

@ajsutton ajsutton commented Apr 28, 2026

BootInfo::load (kona-proof-interop) loaded the dependency set only from the preimage oracle, which the real on-chain PreimageOracle cannot supply (local(8)), so a fault-proof program couldn't complete once interop is active. This adds the embedded-first / oracle-fallback pattern already used for rollup_configs and l1_config: kona_registry::DEPENDENCY_SETS is now a HashMap<u64, DependencySet> keyed by L2 chain id and populated at compile time from etc/depsets.json. The build script aggregates one DependencySet per cluster from the superchain-registry's [interop.dependencies] blocks (validating cluster consistency and rejecting dangling members) and merges any custom depsets from KONA_CUSTOM_CONFIGS_DIR/depsets.json with cross-cluster collision detection. BootInfo::load does a single embedded lookup against the proof's first chain id and falls back to the oracle when the binary has no embedded depset for that chain. Cross-cluster and partial-coverage proofs aren't checked at boot — they fail downstream when interop message validation rejects messages whose source chain isn't in the chosen depset's dependencies map.

To break the kona-interop ↔ kona-registry dependency cycle, DependencySet/ChainDependency/MESSAGE_EXPIRY_WINDOW move to kona-genesis (re-exported by kona-interop for API compatibility). ChainConfig gains an optional [interop] field with serde(skip_serializing_if = "Option::is_none") so existing JSON round-trips are unchanged. Wire compatibility with op-supervisor's StaticConfigDependencySet is locked in by a fixture round-trip test.

@ajsutton ajsutton marked this pull request as ready for review April 28, 2026 04:05
@ajsutton ajsutton requested a review from a team as a code owner April 28, 2026 04:05
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 1.84697% with 372 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.5%. Comparing base (307ff9b) to head (768aed5).
⚠️ Report is 10 commits behind head on develop.

Files with missing lines Patch % Lines
rust/kona/crates/protocol/interop/src/graph.rs 0.0% 208 Missing ⚠️
...st/kona/crates/protocol/genesis/src/interop/mod.rs 0.0% 80 Missing ⚠️
rust/kona/crates/proof/proof-interop/src/boot.rs 0.0% 58 Missing ⚠️
...t/kona/crates/protocol/genesis/src/chain/config.rs 0.0% 12 Missing ⚠️
...kona/crates/protocol/genesis/src/interop/depset.rs 0.0% 7 Missing ⚠️
rust/kona/crates/protocol/registry/src/lib.rs 58.3% 5 Missing ⚠️
...na/crates/proof/proof-interop/src/consolidation.rs 0.0% 1 Missing ⚠️
...st/kona/crates/protocol/registry/src/superchain.rs 0.0% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (307ff9b) and HEAD (768aed5). Click for more details.

HEAD has 25 uploads less than BASE
Flag BASE (307ff9b) HEAD (768aed5)
contracts-bedrock-tests 24 0
cannon-go-tests-64 1 0
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #20377      +/-   ##
===========================================
- Coverage     76.3%     0.5%   -75.9%     
===========================================
  Files          186      486     +300     
  Lines        10694    62756   +52062     
===========================================
- Hits          8170      323    -7847     
- Misses        2380    62433   +60053     
+ Partials       144        0     -144     
Flag Coverage Δ
cannon-go-tests-64 ?
contracts-bedrock-tests ?
unit 0.5% <1.8%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...na/crates/proof/proof-interop/src/consolidation.rs 0.0% <0.0%> (ø)
...st/kona/crates/protocol/registry/src/superchain.rs 26.0% <0.0%> (ø)
rust/kona/crates/protocol/registry/src/lib.rs 36.9% <58.3%> (ø)
...kona/crates/protocol/genesis/src/interop/depset.rs 0.0% <0.0%> (ø)
...t/kona/crates/protocol/genesis/src/chain/config.rs 14.1% <0.0%> (ø)
rust/kona/crates/proof/proof-interop/src/boot.rs 0.0% <0.0%> (ø)
...st/kona/crates/protocol/genesis/src/interop/mod.rs 0.0% <0.0%> (ø)
rust/kona/crates/protocol/interop/src/graph.rs 0.0% <0.0%> (ø)

... and 664 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.

Comment thread rust/kona/crates/protocol/interop/src/depset.rs Outdated
Comment thread rust/kona/crates/proof/proof-interop/src/boot.rs
Comment thread rust/kona/crates/protocol/genesis/src/interop/depset.rs Outdated
Comment thread rust/kona/crates/protocol/registry/src/lib.rs Outdated
Comment thread rust/kona/crates/protocol/genesis/src/interop/mod.rs
ajsutton and others added 11 commits April 29, 2026 08:56
Move DependencySet, ChainDependency, MESSAGE_EXPIRY_WINDOW from kona-interop into
kona-genesis to break the circular dep that would block kona-registry from
embedding interop dependency sets. kona-interop re-exports the types so its
public API is unchanged.

Add a typed [interop] field to ChainConfig (Option<InteropConfig>, with
serde(skip_serializing_if = "Option::is_none") so existing JSON round-trips do
not gain "interop": null lines) and an aggregate_clusters helper that the
registry build script will use to derive per-cluster depsets from the
superchain-registry TOMLs. Also add an Arbitrary derive on the moved types so
ChainConfig's existing Arbitrary derive keeps compiling once the field lands.

Wire-format compatibility against op-supervisor's StaticConfigDependencySet is
locked in by a fixture round-trip test and the rehearsal-0-bn-0.toml fixture
exercises the [interop.dependencies] block end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nterop blocks

Introduce kona_registry::DEPENDENCY_SETS, a HashMap<u64, DependencySet> keyed by
L2 chain id, populated at compile time from etc/depsets.json. The build script
resets the file to [] on every build, derives per-cluster DependencySets from
each chain TOML's [interop.dependencies] block under KONA_BIND, and merges any
KONA_CUSTOM_CONFIGS_DIR/depsets.json on top with cross-cluster collision
detection. validate_depsets catches dangling chain id references at build
time. Disjoint clusters (e.g. mainnet, sepolia, rehearsal-0-bn) stay disjoint:
each cluster's chains map to that cluster's DependencySet, never a union.

Also adds embedded_depsets_empty_by_default and extends
custom_chain_is_loaded_when_enabled to assert cluster identity for the test
fixture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…le fallback

BootInfo::load now consults kona_registry::DEPENDENCY_SETS before the preimage
oracle, matching the existing embedded-first pattern for rollup_configs and
l1_config. The on-chain PreimageOracle cannot supply DEPENDENCY_SET_KEY data,
so the previous oracle-only path could not complete a real fault proof once
interop is active.

The lookup is extracted into load_dependency_set so it is unit-testable.
When the proof's chain ids span two embedded clusters, the helper returns
BootstrapError::CrossDependencySetProof rather than silently unioning them
(which would let cross-cluster messages validate). Partial coverage and empty
embedded maps fall back to the oracle, preserving existing host/test flows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tightens load_dependency_set: if any chain id in the proof has an
embedded DependencySet, all chain ids must have one. Previously,
partial coverage fell back to the oracle for the missing chains,
which would let an attacker insert non-cluster chains via oracle
data while we trusted the rest from the embedded registry.

Adds BootstrapError::PartialDependencySetCoverage and replaces the
old fallback path with a hard error. Oracle fallback now only
applies when no chain id is in any embedded depset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Trust the build pipeline (aggregate_clusters / superchain-registry /
custom-config validation) for embedded depset consistency. The boot
helper now does a single HashMap lookup against chain_ids[0]; if the
first chain id is in any embedded cluster, the build script's
lazy_static loop guarantees we get the correct cluster. If not, fall
back to the preimage oracle for dev/test flows.

Drops the cross-cluster and partial-coverage checks (and their
BootstrapError variants and tests). Cross-cluster and partial proofs
still fail downstream when interop message validation rejects messages
whose source chain isn't in the chosen depset's dependencies — same
outcome, later detection, far cheaper inside cannon (no Vec
allocations, single hashmap lookup, ~25 lines vs ~120).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The kona-interop depset.rs module became a single-line `pub use` of
kona-genesis types after the type-cycle break. Inline the re-export
into lib.rs and remove the file — there's no local definition to
anchor a separate module the way SUPER_ROOT_VERSION anchors
constants.rs.

Public API (`kona_interop::DependencySet`, `kona_interop::ChainDependency`)
is unchanged; only the internal `kona_interop::depset::*` submodule path
goes away, and no in-tree consumer used that path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an explicit HasChain-equivalent check to check_single_dependency
on both ends of every cross-chain edge, mirroring op-supervisor's
LinkChecker.CanExecute semantics. The pre-existing comment claiming
this was "enforced implicitly by the graph constructor and the
provider" was aspirational — nothing in the resolve path consulted
the dependency set for membership, so a proof spanning chains from
two disjoint embedded clusters would silently validate cross-cluster
messages.

MessageGraph now carries `&'a DependencySet` and surfaces a new
MessageGraphError::ChainNotInDependencySet variant when either end
of an edge is missing. proof-interop's consolidation driver passes
the boot-info depset through. Test module gains a OnceLock-backed
default_dep_set() helper so existing assertions are unchanged, plus
two dedicated tests covering the executing-chain and initiating-chain
rejection paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The fixture and test were framed as a cross-language wire-format check
against op-supervisor. That framing isn't right: kona's depset format is
its own, and op-supervisor (and op-supernode) may diverge. Rename the
fixture and test to reflect what's actually being tested — that a
DependencySet can be JSON round-tripped through kona's serde derives.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
debug_assert_eq! was silent in release builds, so a bug in
aggregate_clusters or merge_custom_depsets that produced overlapping
clusters with differing contents would have been masked in production
binaries — last-insert-wins, no panic. Tighten to assert_eq! since the
check runs once at lazy_static init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
aggregate_clusters always emits None for override_message_expiry_window
because no chain TOML field is read for it. Document this and the
schema-extension contract.

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

The graph test module builds DependencySets directly via BTreeMap, which
trips clippy::zero_sized_map_values since ChainDependency is empty. Match
the allow already on DependencySet itself, and apply rustfmt.
@ajsutton ajsutton requested a review from digorithm April 28, 2026 22:56
Copy link
Copy Markdown
Contributor

@digorithm digorithm left a comment

Choose a reason for hiding this comment

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

LGTM, great stuff!

@ajsutton ajsutton force-pushed the aj/fix/kona-depset-embedded branch from 768aed5 to 08dd2b2 Compare April 28, 2026 23:28
@ajsutton ajsutton enabled auto-merge April 28, 2026 23:28
@ajsutton ajsutton added this pull request to the merge queue Apr 28, 2026
Merged via the queue into develop with commit 67a48c9 Apr 29, 2026
116 of 120 checks passed
@ajsutton ajsutton deleted the aj/fix/kona-depset-embedded branch April 29, 2026 00:29
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