(bug fix): validate entry-point builtins are in canonical order in class-to-casm - #10213
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
PR SummaryMedium Risk Overview A new public Tests load example contracts via a shared helper and mutate the libfuncs-coverage external entry point to cover accepted canonical order, swapped builtins, and mid-list gas/system. The Starknet plugin documents that order is enforced in Reviewed by Cursor Bugbot for commit c3f5303. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4a5298d. Configure here.
orizi
left a comment
There was a problem hiding this comment.
@orizi made 1 comment.
Reviewable status: 0 of 5 files reviewed, 2 unresolved discussions (waiting on eytan-starkware and TomerStarkware).
crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 111 at r1 (raw file):
(MulModType::ID, "core::circuit::MulMod"), (GasBuiltinType::ID, "core::gas::GasBuiltin"), (SystemType::ID, "System"),
rather have it duplicated - and use this as the source of truth - as this now has information that has nothing to do with sierra.
Code quote:
(RangeCheckType::ID, "core::RangeCheck"),
(BitwiseType::ID, "core::integer::Bitwise"),
(EcOpType::ID, "core::ec::EcOp"),
(PoseidonType::ID, "core::poseidon::Poseidon"),
(SegmentArenaType::ID, "core::SegmentArena"),
(RangeCheck96Type::ID, "core::circuit::RangeCheck96"),
(AddModType::ID, "core::circuit::AddMod"),
(MulModType::ID, "core::circuit::MulMod"),
(GasBuiltinType::ID, "core::gas::GasBuiltin"),
(SystemType::ID, "System"),4a5298d to
013c7ed
Compare
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware made 1 comment.
Reviewable status: 0 of 5 files reviewed, 2 unresolved discussions (waiting on orizi and TomerStarkware).
crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 111 at r1 (raw file):
Previously, orizi wrote…
rather have it duplicated - and use this as the source of truth - as this now has information that has nothing to do with sierra.
Done.
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 2 files, made 2 comments, and resolved 1 discussion.
Reviewable status: 2 of 5 files reviewed, 2 unresolved discussions (waiting on eytan-starkware and TomerStarkware).
crates/cairo-lang-starknet/src/plugin/consts.rs line 68 at r2 (raw file):
/// Starknet OS required implicit precedence. /// Checked in `cairo-lang-starknet-classes` during contract-class-to-CASM compilation (see
Validated
Code quote:
Checkedcrates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 550 at r2 (raw file):
require(builtins.iter().all(|type_id| { canonical.any(|generic_id| generic_id == type_resolver.get_generic_id(type_id)) }))
Suggestion:
let mut order_iter = ENTRY_POINT_BUILTIN_ORDER.iter();
require(builtins.iter().all(|type_id| {
order_iter.any(|generic_id| generic_id == type_resolver.get_generic_id(type_id))
}))013c7ed to
4612711
Compare
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware made 2 comments.
Reviewable status: 2 of 5 files reviewed, 2 unresolved discussions (waiting on orizi and TomerStarkware).
crates/cairo-lang-starknet/src/plugin/consts.rs line 68 at r2 (raw file):
Previously, orizi wrote…
Validated
Done.
crates/cairo-lang-starknet-classes/src/casm_contract_class.rs line 550 at r2 (raw file):
require(builtins.iter().all(|type_id| { canonical.any(|generic_id| generic_id == type_resolver.get_generic_id(type_id)) }))
Done.
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 2 files and all commit messages, made 1 comment, and resolved 2 discussions.
Reviewable status: 4 of 5 files reviewed, 1 unresolved discussion (waiting on eytan-starkware and TomerStarkware).
crates/cairo-lang-starknet-classes/src/casm_contract_class_test.rs line 45 at r3 (raw file):
/// Hand-written Sierra for a contract with a single entry point. `RangeCheck` is fixed as the /// first builtin (it feeds `withdraw_gas`, so the entry-point cost is properly accounted); the
i really hate this test :\ i;m wondering if we should instead just read an existing program and edit it inplace.
4612711 to
524a8cf
Compare
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware made 1 comment.
Reviewable status: 4 of 5 files reviewed, 1 unresolved discussion (waiting on orizi and TomerStarkware).
crates/cairo-lang-starknet-classes/src/casm_contract_class_test.rs line 45 at r3 (raw file):
Previously, orizi wrote…
i really hate this test :\ i;m wondering if we should instead just read an existing program and edit it inplace.
Done.
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 1 file and all commit messages, and made 1 comment.
Reviewable status: 4 of 5 files reviewed, 2 unresolved discussions (waiting on eytan-starkware and TomerStarkware).
a discussion (no related file):
add a pre-PR making signature checks happen before full sierra-to-casm bytecode compilation.
080a411 to
d5c0814
Compare
524a8cf to
36be342
Compare
eytan-starkware
left a comment
There was a problem hiding this comment.
@eytan-starkware made 1 comment.
Reviewable status: 4 of 5 files reviewed, 2 unresolved discussions (waiting on orizi and TomerStarkware).
a discussion (no related file):
Previously, orizi wrote…
add a pre-PR making signature checks happen before full sierra-to-casm bytecode compilation.
Done.
36be342 to
9172dbb
Compare
d5c0814 to
46939ec
Compare
orizi
left a comment
There was a problem hiding this comment.
@orizi reviewed 2 files and all commit messages, made 1 comment, and resolved 1 discussion.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on TomerStarkware).
orizi
left a comment
There was a problem hiding this comment.
@orizi resolved 1 discussion.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on TomerStarkware).
…ass-to-casm A Starknet entry point's builtin order is only *assumed* to be the canonical order the OS expects: it is produced upstream by the `cairo-lang-starknet` plugin (which stamps `#[implicit_precedence(...)]`) plus the lowering-stage sort, and nothing re-checks it when a `ContractClass` is compiled to a `CasmContractClass`. A class whose entry points list builtins out of that order would compile here yet misbehave in the OS. Add `ENTRY_POINT_BUILTIN_ORDER` to `cairo-lang-starknet-classes`: the canonical order excluding the trailing gas/system pair (which is checked separately). `from_contract_class` now validates that each entry point's remaining builtins are a subsequence of it, returning `InvalidEntryPointSignatureWrongBuiltinsOrder` otherwise; gas or system threaded mid-list is rejected as `InvalidBuiltinType` since they are no longer in the valid mid-list set. The plugin's `IMPLICIT_PRECEDENCE` path list stays in the plugin (Cairo type paths don't belong in the sierra/casm layer) with a comment tying it to the check here. Tested by loading the generated libfuncs-coverage example contract (whose entry point lists all builtins) and swapping two builtins' positions in its entry point signature — params, return types, returns and their store_temps, consistently, so the program stays valid; the frontend can never emit such an order. Canonical compiles; a swapped mid-pair is rejected as wrong order; gas or system swapped into the mid-list is rejected as an invalid builtin type.
9172dbb to
c3f5303
Compare
Merge activity
|


Summary
The
IMPLICIT_PRECEDENCEconstant, which defines the canonical order that entry-point builtins must appear in as required by the Starknet OS, previously existed as two separate definitions: a&[&str]slice of Cairo paths incairo-lang-starknet/src/plugin/consts.rs(used by the plugin to stamp#[implicit_precedence(...)]attributes), and an implicit inline set incasm_contract_class.rs(used to validate builtin types during compilation). These two definitions could silently drift out of sync.This PR consolidates them into a single
pub static IMPLICIT_PRECEDENCE: [(GenericTypeId, &str); 11]incasm_contract_class.rs, pairing each SierraGenericTypeIdwith its Cairo path string. The plugin now imports and iterates over this shared constant (extracting the.1path strings), andfrom_contract_classderives itsbuiltin_typesvalidation set from the same source (extracting the.0type IDs).Additionally,
from_contract_classnow enforces that an entry point's builtins are a subsequence ofIMPLICIT_PRECEDENCE— i.e., they appear in the canonical OS-required order — returningInvalidEntryPointSignatureWrongBuiltinsOrderif they do not. Two new tests cover this: one verifying that a canonically-ordered entry point compiles successfully, and one verifying that a hand-written Sierra entry point with swapped builtins is rejected (this case cannot arise from the frontend, which always emits builtins in canonical order).Type of change
Please check one:
Why is this change needed?
The builtin order required by the Starknet OS was encoded in two separate places with different representations. A change to one would not automatically update the other, risking silent divergence between what the plugin emits and what the compiler validates. Additionally, there was no runtime enforcement that entry-point builtins actually appear in the OS-required order during CASM compilation.
What was the behavior or documentation before?
The plugin used a
&[&str]slice of Cairo path strings inconsts.rsto generate#[implicit_precedence(...)]attributes. The compiler used a separately constructedUnorderedHashSetofGenericTypeIds to check that builtins were valid types, but did not verify their ordering.What is the behavior or documentation after?
A single
IMPLICIT_PRECEDENCEstatic incasm_contract_class.rspairs eachGenericTypeIdwith its Cairo path string. Both the plugin (for attribute generation) and the compiler (for type validation and order enforcement) derive their data from this one source. The compiler now also rejects entry points whose builtins are not a subsequence of the canonical order.Related issue or discussion (if any)
N/A
Additional context
The non-canonical builtin order check can only be triggered by hand-crafted Sierra, since the Cairo frontend always emits builtins in canonical order. The new tests construct such Sierra directly using a hand-written
entry_point_sierrahelper and bypass the frontend entirely.