Skip to content

init rollup: genesis Controller account classes land at non-canonical hashes (Controller auto-deploy fails) — #584 follow-up #586

@kariy

Description

@kariy

Summary

katana init rollup (with --cartridge.controllers) embeds the Cartridge Controller
account classes into the rollup genesis, but they land on-chain at non-canonical
class hashes
. The Controller keychain deploys an account at the canonical class
hash for its version, so the genesis-seeded classes are unusable for auto-deploy —
starknet_getClassHashAt/the deploy fails with "Class with hash 0x… is not declared",
and the account can never deploy on the appchain.

This is a follow-up to #584 ("declare Controller account classes in rollup genesis"):
that PR seeds the classes, but the genesis serialization round-trip changes their
computed class hashes, so the on-chain hashes don't match the canonical artifacts.

Impact

A Cartridge Controller cannot auto-deploy (and therefore cannot sign) on a
katana init rollup appchain out of the box, even with --cartridge.controllers.
Both examples/cross-chain-game and examples/cross-chain-dungeon work around it by
re-declaring the canonical controller artifacts at boot (scripts/declare-controller-class.ts).

Evidence

Appchain genesis (.run/chain-config/genesis.json) declares 10 classes as inline sierra.
Computing each one's class hash (starknet.js computeContractClassHash) yields hashes
that match none of the canonical controller artifacts:

genesis[0] -> 0x335d906ee6dac6d9c3b1733ddd514f494982aa9ec4d180af7e603893da7d9b7
genesis[1] -> 0x3f7111ba26a37797004efe45f9a9dac4e14dd07c5dbe41f9a174d96df29469e
... (8 more, all non-canonical) ...

Canonical hashes (from crates/contracts/contracts/controller/account_sdk/artifacts/classes):

  • controller.latest / controller.v1.0.9 -> 0x743c83c41ce99ad470aa308823f417b2141e02e04571f5c0004e743556e7faf
  • controller.v1.0.8 -> 0x0511dd75da368f5311134dee2356356ac4da1538d2ad18aa66d57c47e3757d59

On the running appchain, starknet_getClass for either canonical hash returns
"Class hash not found" until the artifact is re-declared via a normal declare tx.

Likely root cause

The genesis stores classes as inline sierra; the JSON (de)serialization round-trip
re-encodes the sierra program (felt/number formatting, field ordering), so the class
hash computed at genesis load differs from the hash of the original artifact. #584
declares the round-tripped classes, landing the shifted hashes rather than the
canonical ones the keychain deploys.

Repro

  1. katana init rollup --id <X> ... then run with --cartridge.controllers.
  2. starknet_getClass for 0x743c8… (controller.latest) -> not found.
  3. Connect a Cartridge Controller and send a tx -> account auto-deploy reverts with
    "Class with hash 0x… is not declared".

Workaround (current)

Re-declare the on-disk canonical artifacts at boot. Note a Controller account is pinned
to the class version it was created with (e.g. v1.0.8), and the keychain deploys
it at that version — so all bundled versions must be declared, not just latest:

for (const v of allControllerVersions) {
  await account.declareIfNot({ contract: `${v}.contract_class.json`, casm: `${v}.compiled_contract_class.json` });
}

Suggested fix

Make init rollup preserve canonical class hashes through the genesis round-trip
(declare/seed from the original artifact bytes, or store the class hash explicitly and
verify it round-trips), so genesis-seeded controller classes are queryable at their
canonical hashes and no boot-time re-declare is needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions