Skip to content

feat(kona): execute NUT bundles at Karst fork activation#20157

Draft
maurelian wants to merge 9 commits intodevelopfrom
feat-kona-nut-execution
Draft

feat(kona): execute NUT bundles at Karst fork activation#20157
maurelian wants to merge 9 commits intodevelopfrom
feat-kona-nut-execution

Conversation

@maurelian
Copy link
Copy Markdown
Contributor

@maurelian maurelian commented Apr 18, 2026

Summary

Wires Karst NUT bundle execution into kona-node's payload derivation, matching op-node's behavior.

  • kona-hardforks gets a build.rs that reads op-core/nuts/bundles/karst_nut_bundle.json at compile time and emits Rust code constructing the NutBundle — keeps the crate no_std and serde-free at runtime.
  • The Hardfork trait grows upgrade_gas(); the stateful attributes builder adds that gas to the block gas limit when Karst activates, so upgrade transactions have headroom.
  • Test in forks.rs updated from len() == 0 to len() == 32 to reflect the populated bundle.
  • TestActivationBlockNUTBundle in op-e2e/actions/proofs/ verifies activation block contents generically: discovery runs through forks.All + derive.UpgradeTransactions, so any future fork that ships a NUT bundle is covered without test changes.

Test plan

  • cargo nextest run in rust/kona — 119 passed
  • test_karst_upgrade_txs asserts 32 transactions
  • test_karst_upgrade_gas asserts 51_600_000 gas
  • TestActivationBlockNUTBundle/karst compiles + vets clean locally (full run needs forge artifacts — CI)

@maurelian maurelian requested a review from a team as a code owner April 18, 2026 14:59
@wiz-0f98cca50a
Copy link
Copy Markdown

wiz-0f98cca50a Bot commented Apr 18, 2026

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities 3 High 1 Medium 4 Low
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings -
Software Management Finding Software Management Findings -
Total 3 High 1 Medium 4 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 18, 2026

Codecov Report

❌ Patch coverage is 0% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.5%. Comparing base (befabab) to head (0e3aad4).
⚠️ Report is 17 commits behind head on develop.

Files with missing lines Patch % Lines
rust/kona/crates/protocol/hardforks/src/karst.rs 0.0% 16 Missing ⚠️
...t/kona/crates/protocol/hardforks/src/nut_bundle.rs 0.0% 13 Missing ⚠️
rust/kona/crates/protocol/hardforks/src/traits.rs 0.0% 3 Missing ⚠️
rust/kona/crates/protocol/hardforks/src/forks.rs 0.0% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (befabab) and HEAD (0e3aad4). Click for more details.

HEAD has 14 uploads less than BASE
Flag BASE (befabab) HEAD (0e3aad4)
cannon-go-tests-64 1 0
contracts-bedrock-tests 12 0
unit 2 1
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #20157      +/-   ##
===========================================
- Coverage     76.6%     0.5%   -76.2%     
===========================================
  Files          691      488     -203     
  Lines        76081    61762   -14319     
===========================================
- Hits         58298      320   -57978     
- Misses       17639    61442   +43803     
+ Partials       144        0     -144     
Flag Coverage Δ
cannon-go-tests-64 ?
contracts-bedrock-tests ?
unit 0.5% <0.0%> (-76.3%) ⬇️

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

Files with missing lines Coverage Δ
.../crates/protocol/derive/src/attributes/stateful.rs 0.0% <ø> (-98.7%) ⬇️
rust/kona/crates/protocol/hardforks/src/forks.rs 0.0% <0.0%> (-100.0%) ⬇️
rust/kona/crates/protocol/hardforks/src/traits.rs 0.0% <0.0%> (ø)
...t/kona/crates/protocol/hardforks/src/nut_bundle.rs 0.0% <0.0%> (ø)
rust/kona/crates/protocol/hardforks/src/karst.rs 0.0% <0.0%> (-100.0%) ⬇️

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

@maurelian maurelian force-pushed the feat-kona-nut-execution branch from c38d430 to 0a41e7d Compare April 20, 2026 14:14
@maurelian maurelian marked this pull request as draft April 20, 2026 14:25
maurelian added 2 commits April 20, 2026 17:01
Add build.rs that reads karst_nut_bundle.json at compile time and
generates Rust code to construct the NutBundle. The derive pipeline
now adds upgrade gas to the block gas limit at fork activation,
matching op-node's gas accounting behavior.
Verifies that every fork with an embedded NUT bundle produces an
activation block containing exactly the bundle's deposit transactions.
Discovery uses forks.All + derive.UpgradeTransactions, so future forks
with NUT bundles are covered automatically without test changes.
@maurelian maurelian force-pushed the feat-kona-nut-execution branch from 0a41e7d to df9aabf Compare April 20, 2026 21:06
// the copy is byte-identical to op-core/nuts/bundles/<fork>_nut_bundle.json.
let manifest_dir =
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
let karst_bundle = manifest_dir.join("bundles/karst_nut_bundle.json");
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We had discussed whether it would be possible to reach out to the file in op-core, or else just use a symlink to it, but that did not work with the kona build, as the docker context would need to be expanded to include the monorepo root.

If we're ok with that, then it might be better to go that way.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see... wondering if we could add a dir shared/nuts to the repo root and then only add shared/ to the docker context (in addition to rust/) and also reach out to this dir from Go for embedding the bundle JSONs?

Copy link
Copy Markdown
Contributor Author

@maurelian maurelian Apr 21, 2026

Choose a reason for hiding this comment

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

go:embed doesn't allow reaching out to relative paths like that.

So what I ended up doing is just caf98bb, which expands the context to include op-core/nuts/bundles.

It may be a bit weird to have rust reach into a go package, but it is better than the duplication, and it allowed me to remove (e3dc8f0) a lot of the code that was required to copy the bundle into the crate dir.

Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go Outdated
Comment thread rust/kona/crates/protocol/hardforks/build.rs Outdated
Comment thread rust/kona/crates/protocol/hardforks/build.rs Outdated
Comment thread rust/kona/crates/protocol/hardforks/build.rs
// the copy is byte-identical to op-core/nuts/bundles/<fork>_nut_bundle.json.
let manifest_dir =
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
let karst_bundle = manifest_dir.join("bundles/karst_nut_bundle.json");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see... wondering if we could add a dir shared/nuts to the repo root and then only add shared/ to the docker context (in addition to rust/) and also reach out to this dir from Go for embedding the bundle JSONs?

Comment thread rust/kona/crates/protocol/hardforks/src/karst.rs Outdated
Comment thread ops/scripts/check-nut-locks/main.go Outdated
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go
Comment thread op-e2e/actions/proofs/nut_bundle_activation_test.go
@maurelian maurelian force-pushed the feat-kona-nut-execution branch from 941e15a to caf98bb Compare April 21, 2026 18:32
Comment thread rust/kona/docker/apps/kona_app_generic.dockerfile
maurelian added 3 commits April 21, 2026 14:41
The Docker build context for kona images is scoped to rust/, so build.rs
cannot reach op-core/nuts/bundles/ via ancestor walk and the kona-client/
host/node images fail to build. Keep a byte-identical copy inside the
crate, written and verified automatically by the existing snapshot/lock
tooling so the two sources cannot silently drift.
The kona-hardforks build.rs walks ancestors of CARGO_MANIFEST_DIR to find
op-core/nuts/bundles/ during compilation. The kona-{client,host,node}
images scope their Docker context to rust/, so the ancestor walk can't
reach op-core/ and the images fail to build.

Pass op-core/nuts/bundles as an additional named BuildKit context
(nuts-bundles) and copy it into /workspace/op-core/nuts/bundles so the
ancestor walk succeeds. Keeps the primary rust/ context small and avoids
mirroring the bundle JSON into the crate tree.
@maurelian maurelian force-pushed the feat-kona-nut-execution branch from caf98bb to 815bf97 Compare April 21, 2026 18:41
maurelian added 4 commits April 21, 2026 14:45
Iterate forks.From(forks.Karst) with a NoError assertion on
derive.UpgradeTransactions rather than silently skipping forks whose
bundle fails to load, so a broken bundle surfaces as a test failure.

Also assert every tx in the activation block has a successful receipt
so a reverted upgrade tx can't hide behind the byte-equality check.
The Hardfork impl for each NUT-bundle-backed fork is identical boilerplate
(decode, EIP-2718 encode, sum gas). Move that pattern into a single
internal macro so adding future forks is a one-liner next to the
build-script-generated constructor.
Split parsing + codegen into build_helpers.rs, included via #[path] from
both the build script and a new integration test. Use anyhow to carry
error context up to a single panic in main. The integration test runs
the generator on a fixture JSON and asserts the exact Rust source output,
so codegen changes surface as a test failure rather than a downstream
compile error.
Follows the per-fork test convention from ecotone/fjord/isthmus/holocene.
Asserts the EIP-1967 implementation slot of representative predeploy
proxies (L1Block, GasPriceOracle) changes across Karst activation — a
Karst-specific smoke test that the bundle's proxy upgrades took effect.

Not generalized into the NUT bundle activation test because it does not
hold for future forks that may not upgrade proxies.
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