Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: sierra explanation #264

Merged
merged 14 commits into from
Feb 17, 2025
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@ target/*
src/**/*.md

node_modules

4 changes: 4 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ name = "pragma_lib"
version = "1.0.0"
source = "git+https://github.com/astraly-labs/pragma-lib?tag=2.9.1#ee1f3f7e9276cf64e19e267832de380d84c04d28"

[[package]]
name = "sierra_ir"
version = "0.1.0"

[[package]]
name = "simple_account"
version = "0.1.0"
Expand Down
1 change: 1 addition & 0 deletions listings/advanced-concepts/sierra_ir/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
16 changes: 16 additions & 0 deletions listings/advanced-concepts/sierra_ir/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "sierra_ir"
version.workspace = true
edition.workspace = true

[lib]
sierra-text = true

[dependencies]
starknet.workspace = true

[dev-dependencies]
cairo_test.workspace = true

[scripts]
test.workspace = true
10 changes: 10 additions & 0 deletions listings/advanced-concepts/sierra_ir/simple_program.sierra
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type felt252 = felt252 [storable: true, drop: true, dup: true, zero_sized: false];

libfunc felt252_add = felt252_add;
libfunc store_temp<felt252> = store_temp<felt252>;

felt252_add([0], [1]) -> ([2]); // 0
store_temp<felt252>([2]) -> ([2]); // 1
return([2]); // 2

sierra_ir::add_numbers@0([0]: felt252, [1]: felt252) -> (felt252);
1 change: 1 addition & 0 deletions listings/advanced-concepts/sierra_ir/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod simple_program;
3 changes: 3 additions & 0 deletions listings/advanced-concepts/sierra_ir/src/simple_program.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn add_numbers(a: felt252, b: felt252) -> felt252 {
a + b
}
323 changes: 323 additions & 0 deletions listings/getting-started/variables/storage_variables.sierra

Large diffs are not rendered by default.

169 changes: 169 additions & 0 deletions pages/advanced-concepts/sierra_ir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Understanding Sierra: From High-Level Cairo to Safe CASM

Sierra (**S**afe **I**nt**er**mediate **R**epresent**a**tion) is a linear intermediate representation of Cairo instructions, designed to bridge the gap between high-level Cairo 1 and low-level Cairo Assembly (CASM).

Check warning on line 3 in pages/advanced-concepts/sierra_ir.md

View workflow job for this annotation

GitHub Actions / typos

"afe" should be "safe".
Sierra can be compiled to a subset of CASM, known as `Safe CASM{:md}`.

Sierra ensures that programs are always **provable** by preventing the compilation of programs with infinite loops or invalid constraints.

### From Cairo 1 to Sierra

Before Starknet Alpha v0.11.0, developers wrote contracts in Cairo 0, which compiled directly to Cairo Assembly (CASM), and contract classes were submitted to the sequencer via `DECLARE` transactions.
This approach had risks, as the sequencer could not determine whether a given transaction would fail without executing it, and therefore could not charge fees for failed transactions.

Cairo 1 introduced contract class compilation to this new Sierra intermediate representation instead of directly compiling to CASM. The Sierra code is then submitted to the sequencer, compiled down to CASM, and finally executed by the Starknet OS.
Using Sierra ensures that all transactions (including failed ones) are provable, and allows sequencers to charge fees for all submitted transactions, making DoS attacks significantly more expensive.

### Compilation Pipeline

```
Cairo 1.0 Source (High-level)
|
| with Cairo-to-Sierra Compiler
V
Sierra IR (Safe, Provable Code)
|
| with Sierra-to-CASM Compiler (Run by Sequencer)
V
CASM (Cairo Assembly)
|
| with CairoVM Execution
V
STARK Proofs (Proof Generation)
```

At its core, Sierra's compilation process is focused on safety and efficiency.
Cairo 1 uses a linear type system and a non-deterministic, immutable, contiguous memory model, which guarantees that dereferencing never fails.

Sierra transforms loops into recursion and keeps track of gas usage, which prevents infinite loops.

:::note
If you're interested in really understanding how the compilation works under the hood, check out the [cairo-compiler-workshop](https://github.com/software-mansion-labs/cairo-compiler-workshop).
:::

### Anatomy of a Sierra Program

### Type Declarations

Sierra, as a Cairo representation, also uses a **linear type system**, where each value **must be used exactly once**.
During the compilation, a unique identifier is assigned to each type.

When types can safely be used multiple times, they need to be duplicated using the `dup` instruction, which will assign two new identifiers to preserve linearity.

Type declaration is done with the following syntax:

```cairo
type type_id = concrete_type;
```

:::info
In addition, each type has a set of attributes that describe how it can be used:

- storable
- droppable
- duplicatable
- zero_sized

They are added in the type declaration:

```cairo
type type_id = concrete_type [storable: bool, drop: bool, dup: bool, zero_sized: bool]
```

:::

### Library Function Declarations

Sierra comes with a set of built-in functions (`libfuncs`) that represent the call to low-level units of code known to be safe. After type declarations, a Sierra program must define all the libfuncs used in the program along with their expected input types.

Libfunc declaration is done with the following syntax:

```cairo
libfunc libfunc_id = libfunc_name<input_types>;
```

:::note
While this section is generic, Starknet uses an allowed [list](https://github.com/starkware-libs/cairo/tree/main/crates/cairo-lang-starknet-classes/src/allowed_libfuncs_lists) of libfuncs.
:::

### Statements

This section shows the sequence of operations that occur during execution, describing the actual logic of the program. A statement either invokes a libfunc or returns a value.

Statements are declared with the following syntax:

```cairo
libfunc_id<input_types>(input_variables) -> (output_variables);
```

To return a value, we use the `return(variable_id)` statement.

### User Defined Functions Declarations

At the end of a Sierra program, each user-defined function is declared with a unique identifier and the statement index where the function starts. This provides information about the function, such as its signature, while the implementation is defined in the statements section.

An user defined function is declared with the following syntax:

```cairo
function_id@statement_index(parameters: types) -> (return_types);
```

## Simple Sierra Program Breakdown

Let's go through the following Cairo program:

```cairo
// [!include ~/listings/advanced-concepts/sierra_ir/src/simple_program.cairo]
```

It compiles to the following Sierra code:

```cairo
// [!include ~/listings/advanced-concepts/sierra_ir/simple_program.sierra]
```

Type Declarations:

- `felt252`: Represents the field element type

Libfunc Declarations:

- `felt252_add`: Performs addition on field elements
- `store_temp<felt252>`: Temporarily stores the result

Statements Section:

- Statement 0: calls the `felt252_add` libfunc to add the values from memory cells 0 and 1, storing the result in memory cell 2
- Statement 1: calls the `store_temp<felt252>` libfunc to prepare the result for the return statement
- Statement 2: returns the value from memory cell 2

User Defined Functions:

- `add_numbers`: Takes two `felt252` types in memory cells 0 and 1 and returns a `felt252` value by starting at statement 0

:::info
To enable Sierra code generation in a human-readable format, add the `sierra-text` flag to the library target in your `Scarb.toml{:md}` file:

```toml
[lib]
sierra-text = true
```

:::

### Storage Variables Smart Contract Sierra Code

You can find a more complex example of the [compiled Sierra code](/advanced-concepts/sierra_ir_storage_contract) of the [Storage Variables Example](/getting-started/basics/variables#storage-variables).

## Further Reading

- [Under the hood of Cairo 1.0: Exploring Sierra](https://www.nethermind.io/blog/under-the-hood-of-cairo-1-0-exploring-sierra-part-1)

- [Under the hood of Cairo 2.0: Exploring Sierra](https://www.nethermind.io/blog/under-the-hood-of-cairo-1-0-exploring-sierra-part-2)

- [Under the hood of Cairo 1.0: Exploring Sierra](https://www.nethermind.io/blog/under-the-hood-of-cairo-1-0-exploring-sierra-part-3)

- [Cairo and Sierra](https://docs.starknet.io/architecture-and-concepts/smart-contracts/cairo-and-sierra/)

- [Sierra - Deep Dive](https://www.starknet.io/blog/sierra-deep-dive-video/)

- [Cairo and MLIR](https://blog.lambdaclass.com/cairo-and-mlir/)
3 changes: 3 additions & 0 deletions pages/advanced-concepts/sierra_ir_storage_contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```cairo
// [!include ~/listings/getting-started/variables/storage_variables.sierra]
```
Loading
Loading