feat(katana): declare Controller account classes in rollup genesis#584
Merged
Conversation
…nnet address Rollup mode previously deployed a custom STRK ERC20 via UDC at the derived address 0x2e7…, because UDC-derived addresses can't land at the canonical Starknet mainnet STRK address (0x0471…). This made it impossible for wallets and explorers to treat a rollup like Starknet mainnet/sepolia. The fix mirrors the dev-mode pattern: the STRK fee token is now pre-allocated into genesis state (class declared, contract deployed, ERC20 storage seeded with the master account holding initial supply) at DEFAULT_STRK_FEE_TOKEN_ADDRESS, bypassing UDC entirely. The genesis transactions builder drops the ERC20 declare+deploy txs and points its in-memory fee-token cursor at the canonical address so the existing transfer_balance invokes keep working. A small PreloadedStateProvider overlay lets the executor see the pre-allocated state when processing the genesis block; init_rollup_genesis merges the pre-allocation into the execution output before commit. DEFAULT_APPCHAIN_FEE_TOKEN_ADDRESS is removed in favor of the canonical constant; CLI init and the settlement bootstrap (SNOS / Katana-TEE config hashes) are updated to bind to it. add_fee_token is extracted into a shared chain-spec/fee_token module since dev and rollup now both call it. Out of scope: deployment.rs INITIAL_STATE_ROOT stays at Felt::ZERO. Genesis state is no longer empty before block 0 executes, so SNOS-proven settlement will diverge until the settlement bootstrap publishes the real genesis state root — tracked as a follow-up in the deployment.rs comment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codec benchmark diff vs
|
| Benchmark | Baseline (ns) | Current (ns) | Δ |
|---|---|---|---|
CompiledClass(fixture)/compress |
2686623 | 2398943 | -10.71% |
CompiledClass(fixture)/decompress |
2931175 | 2698628 | -7.93% |
ExecutionCheckpoint/compress |
35 | 28 | -20.00% |
ExecutionCheckpoint/decompress |
25 | 23 | -8.00% |
PruningCheckpoint/compress |
35 | 29 | -17.14% |
PruningCheckpoint/decompress |
25 | 23 | -8.00% |
VersionedHeader/compress |
643 | 652 | +1.40% |
VersionedHeader/decompress |
821 | 725 | -11.69% |
StoredBlockBodyIndices/compress |
76 | 71 | -6.58% |
StoredBlockBodyIndices/decompress |
37 | 36 | -2.70% |
StorageEntry/compress |
146 | 120 | -17.81% |
StorageEntry/decompress |
141 | 119 | -15.60% |
ContractNonceChange/compress |
145 | 118 | -18.62% |
ContractNonceChange/decompress |
234 | 203 | -13.25% |
ContractClassChange/compress |
217 | 167 | -23.04% |
ContractClassChange/decompress |
259 | 219 | -15.44% |
ContractStorageEntry/compress |
160 | 127 | -20.63% |
ContractStorageEntry/decompress |
309 | 279 | -9.71% |
GenericContractInfo/compress |
140 | 122 | -12.86% |
GenericContractInfo/decompress |
102 | 85 | -16.67% |
Felt/compress |
82 | 70 | -14.63% |
Felt/decompress |
59 | 47 | -20.34% |
BlockHash/compress |
82 | 73 | -10.98% |
BlockHash/decompress |
58 | 47 | -18.97% |
TxHash/compress |
82 | 70 | -14.63% |
TxHash/decompress |
59 | 47 | -20.34% |
ClassHash/compress |
82 | 70 | -14.63% |
ClassHash/decompress |
59 | 47 | -20.34% |
CompiledClassHash/compress |
82 | 70 | -14.63% |
CompiledClassHash/decompress |
59 | 47 | -20.34% |
BlockNumber/compress |
47 | 43 | -8.51% |
BlockNumber/decompress |
25 | 23 | -8.00% |
TxNumber/compress |
47 | 43 | -8.51% |
TxNumber/decompress |
25 | 23 | -8.00% |
FinalityStatus/compress |
1 | 0 | -100.00% |
FinalityStatus/decompress |
12 | 10 | -16.67% |
TypedTransactionExecutionInfo/compress |
18091 | 14741 | -18.52% |
TypedTransactionExecutionInfo/decompress |
3635 | 2531 | -30.37% |
VersionedContractClass/compress |
373 | 354 | -5.09% |
VersionedContractClass/decompress |
795 | 647 | -18.62% |
MigratedCompiledClassHash/compress |
146 | 118 | -19.18% |
MigratedCompiledClassHash/decompress |
138 | 119 | -13.77% |
ContractInfoChangeList/compress |
1628 | 1521 | -6.57% |
ContractInfoChangeList/decompress |
2237 | 2131 | -4.74% |
BlockChangeList/compress |
689 | 645 | -6.39% |
BlockChangeList/decompress |
903 | 865 | -4.21% |
ReceiptEnvelope/compress |
30170 | 25712 | -14.78% |
ReceiptEnvelope/decompress |
6131 | 5402 | -11.89% |
TrieDatabaseValue/compress |
165 | 140 | -15.15% |
TrieDatabaseValue/decompress |
219 | 223 | +1.83% |
TrieHistoryEntry/compress |
289 | 268 | -7.27% |
TrieHistoryEntry/decompress |
255 | 197 | -22.75% |
|
`add_fee_token` is a builder-style genesis helper whose 8 args are each a distinct token field; allow the lint locally rather than wrapping them in a struct that just moves the arg list to the callers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`katana init rollup --cartridge-controllers` declares the Cartridge Controller account classes in the generated genesis, so a Controller can deploy and sign on the appchain (not just the settlement chain). In that mode the genesis also seeds 3 dev accounts instead of 1, because the Cartridge paymaster sidecar reserves accounts 0/1/2 (relayer, gas tank, estimate) and would otherwise fail to bootstrap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lockfile catch-up from the `--cartridge-controllers` katana work; regenerated by the build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3376f8f to
83568bf
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/rollup-chain-spec #584 +/- ##
==========================================================
+ Coverage 68.68% 68.70% +0.02%
==========================================================
Files 322 322
Lines 45601 45664 +63
==========================================================
+ Hits 31320 31375 +55
- Misses 14281 14289 +8 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Classes inserted into `genesis.classes` (e.g. the Cartridge Controller account classes added by `katana init rollup --cartridge-controllers`) were never declared on a rollup: the genesis builder only declared the core classes it deploys, so preloaded classes lived in `genesis.classes` but had no declare transaction. On a rollup the genesis is built solely from those transactions, so the classes weren't actually declared, and the genesis.json round-trip shifted their map key — leaving them unusable by their canonical hash (worked around with a runtime declare). Declare any preloaded class through a real genesis declare tx, the same way the core classes are declared. `declare` recomputes the class hash from the artifact (not the map key), so the class lands at its canonical hash even after a genesis.json round-trip. The STRK fee token class is skipped — it's pre-allocated into state at the canonical mainnet address, not declared (enforced by `strk_pre_allocated_at_canonical_address`); the UDC/account classes are already declared, so dedup makes them no-ops and a controllerless rollup's genesis transactions are byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4271395 to
95d8e2c
Compare
Drop the opt-in `--cartridge-controllers` flag on `katana init rollup` and make rollups Cartridge Controller–ready by default: the Controller account classes are always declared in the genesis, and 3 dev accounts are always seeded (the Cartridge paymaster sidecar reserves accounts 0/1/2, so fewer aborts its bootstrap). The classes are declared via a real genesis declare tx, so they're usable by their canonical hash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kariy
added a commit
that referenced
this pull request
Jun 3, 2026
Most blockers are resolved now: the fee-token mismatch (canonical STRK pre-allocated in the rollup genesis) and the stale-fee / false "Simulation Error" review-screen bugs (merged upstream in cartridge-gg/controller#2609). Rework the section into "Resolved" vs "Still open" — the latter being the self-hosted keychain (switch re-point not yet in the deployed x.cartridge.gg, CORS proxy) and the runtime controller-class declare. Note the #584 gap: it declares the round-tripped genesis artifact at a shifted hash, not the canonical 0x743c8 the keychain deploys, so the runtime declare is still required. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kariy
added a commit
that referenced
this pull request
Jun 3, 2026
Expand keychain-fork/README into a working setup: clone controller at the #2609 merge + apply the local patch, generate trusted mkcert certs, install/build-deps/run the keychain on :3010 (with health-check curls), point the demo at it, declare the controller class (the #584 runtime step), and connect. Adds a Gotchas section (trusted cert mandatory, keychain must be up first, Chrome PNA flag, ports, re-declare each ./up.sh). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kariy
added a commit
that referenced
this pull request
Jun 3, 2026
…ler class The production keychain at x.cartridge.gg redeployed from main right after #2609 (confirmed: the deployed bundle carries the use-simulate fix), so it now has both the behavioral fixes and the switchChain rebuild. That lets the demo drive the appchain Controller with the *hosted* keychain directly — no self-hosted keychain, no CORS proxy. The default path needs no app/.env.local. The one remaining gap was the controller class hash: katana #584 declares the round-tripped genesis artifact at a shifted hash, not the canonical 0x743c8 the keychain deploys, so the Controller couldn't auto-deploy on the appchain after boot. Fold a boot-time declare into up.sh (CONTROLLER mode) via a new scripts/declare-controller-class.ts, so `CONTROLLER=1 ./up.sh` is now sufficient. Docs: rewrite client.md "known blockers" (most resolved; the #584 declare is now handled by up.sh), make the README "Using Controller" accurate, and demote the keychain-fork to a documented fallback for unreleased keychain changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
katana init rollupnow declares the Cartridge Controller account classes in the rollup genesis by default (so a Controller can be UDC-deployed on the appchain) and seeds 3 dev accounts (the cartridge paymaster sidecar reserves dev accounts 0/1/2 as relayer/gas-tank/estimate).The classes are declared via a real genesis declare transaction (
GenesisTransactionsBuilder::build_preloaded_classes), so the rollup genesis builder is the single source of the genesis state. The declare hash is recomputed from the class artifact, so the classes are usable by their canonical hash even after thegenesis.jsonround-trip — removing the previous runtime re-declare workaround. A rollup's genesis transactions are otherwise unchanged (the core classes dedup to no-ops; the STRK fee token stays pre-allocated).Stacked on #583 (base:
feat/rollup-chain-spec).🤖 Generated with Claude Code