In Cairo 0.x, developers would write Starknet contracts in Cairo, compile them to CASM, and deploy the compilation output directly on Starknet. Users could then interact with Starknet contracts by calling smart contract functions, signing a transaction, and sending it to the sequencer. The sequencer would run the transaction to get the user’s transaction fee, the prover (SHARP) would generate the proof for the batch including this transaction, and the sequencer would charge a fee for including the transaction in a block.
- Only valid statements can be proven in Cairo, so failed transactions cannot get proven.
- Transaction execution may fail, resulting in the transaction not being included in a block. In this case, the sequencer does free work. Since failed transactions don’t have valid proofs, they can’t be included, and there is no way to enforce fee transfer for the sequencer.
- The sequencer can be subjected to DDoS attacks with invalid transactions, causing them to work for nothing and not collect any fee for running these transactions.
- It is impossible to distinguish between censorship (when a sequencer purposefully decides not to include certain transactions) and invalid transactions since both types of transactions will not be included in blocks.
The Starknet network needs to achieve two goals: completeness and soundness. Completeness ensures that transaction execution can always be proven, even when it is expected to fail. Soundness ensures that valid transactions are not rejected, preventing censorship.
Sierra (Safe Intermediate Representation) is an intermediate layer between the high-level language Cairo and compilation targets such as Cairo Assembly (CASM).Sierra is the bridge between our past and the future. Sierra is a correct-by-construction intermediate representation of Cairo code that doesn’t contain any failing semantics. This ensures that no Sierra code can ever fail, and it compiles later down to a safe subset of CASM. Instead of deploying CASM code to Starknet, developers will compile their Cairo 1 code to Sierra and deploy Sierra programs to Starknet. On a declare-transaction, the sequencers will be responsible for compiling the Sierra code to CASM, ensuring that no failing code can be deployed on Starknet.
Sierra is correct-by-construction, letting the sequencer charge a fee for all transactions.
you can generate readable Sierra output for your contracts by using the make sierra command in the Minimal Cairo 1.0 Template. This effectively runs cairo-compile . -r on your code. While Sierra is reported as stabilized, the present examples are accurate as of March 2023.
A basic example of Sierra code is a function that does nothing:
// Equivalent to fn do_nothing() -> () {return (); }
fn do_nothing(){}
The Sierra output is organized into 4 separate sections always presented in the same order.
- type declarations.
- Declarations of built-in library functions.
- The sequence of statements
- The declared Cairo functions.
// 1. Type declarations
type Unit =Struct<ut@Tuple>;
// 2. Library function declarations
libfunc struct_construct<Unit> = struct_construct<Unit>;
libfunc store_temp<Unit> = store_temp<Unit>;
// 3. Statements
struct_construct<Unit>() -> ([0]);
store_temp<Unit>([0]) -> ([1]);
// 4. user-defined functions
sierra_experiments::sierra::do_nothing@0() ->(Unit);
A couple of observations:
The Unit type () is a special case of an empty struct and is used as a default return type for procedures (functions without a declared return type). New temporary variables are created and indexed using square brackets ( [0] and [1] ) . Statements have the following form () -> (); , i.e., we don't see the more traditional [0] = struct_construct(); Code blocks are separate from Cairo function declarations. A function is tied to a specific block of code by starting at a dedicated statement index location (note the do_nothing@0 which indicates that the function begins at the first statement).
Sierra output can be used to understand how built-in types are used in compilation. To study how control flow is represented, we can use a recursive function to compute the factorial.
The best Solidity developers can program in Yul (an intermediate language used in Solidity code compilation) and possess a thorough understanding of EVM. This knowledge not only enables them to identify security vulnerabilities but also enables them to optimize their code for efficiency.
By studying Sierra code, we can gain a deeper understanding of the underlying type system, identify security risks and enhance efficiency, such as reducing storage requirements or execution steps in functions with high recursion. Smart contract developers and auditors in Cairo must not hesitate to delve into Sierra to comprehend how their contracts operate. Although there is much more going on behind the scenes, Sierra offers an ideal balance between readability and insights.