Skip to main content

The Leo Programming Model

This section assumes that you have knowledge of records and their use in the Aleo Protocol.

Leo Record Runtime#

Each Leo .leo file is compiled into a program. Each program lives in a record. Each record lives in a transaction. An Aleo transaction spends two old records: old_record_0, old_record_1 and creates two new records: new_record_0, new_record_1.

Registers#

A register stores intermediate record state during runtime. During runtime, we load an initial input state into a record and expect and output state after the record is run.

  • Input state is stored in the input register.
  • Output state is stored in the output register.
input_register -> record -> output_register

Leo executes each record in order:

  1. state_0 -> old_record_0 -> state_1
  2. state_1 -> old_record_1 -> state_2
  3. state_2 -> new_record_0 -> state_3
  4. state_3 -> new_record_1 -> state_4

To ensure the accuracy of input and output register state, a hash of each is stored in the local data commitment for each record.

Committing to Register Data.#

Register values are hashed and included in the local data commitment. The Leo runtime calculates the record commitment as well as the local data commitment to ensure that all record data is included in the local data root.

.in and .out files#

Input Registers#

Input register information is passed to Leo as program input inside the .in file indicated by the [registers] section.

project.in
[main]
data: [u8; 32] = [0; 32];
[registers]
token_id: [u8; 32] = [0; 32];
value_balance: u64 = 0;

Accessing Input Registers#

Input register values can be accessed by passing the registers section into the main function of a Leo file and accessing each variable via dot . syntax.

function main(data: [u8; 32], registers) {
let new_balance = registers.value_balance + 5;
let is_valid = registers.token_id == data;
}

Output Registers#

Output register information is stored inside the .out file indicated by the [registers] section.

project.out
[registers]
token_id: [u8; 32] = [0; 32];
value_balance: u64 = 0;

Writing to Output Registers#

The return function of main will automatically write to the output registers in .out.

Reading from Output Registers#

Intermediate runtime state will automatically be passed from one record's output register to the next record's input register.

info

To see how to load register files into tests, checkout Writing Tests.

State#

Leo files can access record and leaf state passed into the state file. For example, it could be necessary for Leo programs to access the owner, value, or other private fields within a record. This context is included in the state .state file.

.state file#

State information generated by the current Leo runtime is placed in the .state file.

project.state
[[public]]
[state]
leaf_index: u32 = 0;
root: [u8; 32] = [0; 32];
[[private]]
[record]
serial_number: [u8; 64] = [0; 64];
commitment: [u8; 32] = [0; 32];
owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9;
is_dummy: bool = false;
value: u64 = 0;
payload: [u8; 32] = [0; 32];
birth_program_id: [u8; 48] = [0; 48];
death_program_id: [u8; 48] = [0; 48];
serial_number_nonce: [u8; 32] = [0; 32];
commitment_randomness: [u8; 32] = [0; 32];
[state_leaf]
path: [u8; 128] = [0; 128];
memo: [u8; 32] = [0; 32];
network_id: u8 = 0;
leaf_randomness: [u8; 32] = [0; 32];

Public and Private Sections#

A double bracket [[public]] or [[private]] section specifies whether sections below define public or private variables. Developers cannot define public variables outside of the state leaf_index and root.

Public State Variables#

The [state] section defines the local data root and the current record's index (0 - 3) within the commitment (4 records in a transaction currently). The state section must be defined below the public [[public]] section.

Record Variables#

The [record] section defines record information. All record variables are private so the record section must be defined below the private [[private]] section.

Private State Leaf Variables#

The [state_leaf] section defines state leaf transition information that is encoded in a transaction. The state leaf section must be defined below the private [[private]] section.

info

To see how to load state files into tests, checkout Writing Tests

Where Register and State Files are Stored#

The Leo CLI creates an inputs/ and an outputs/ folder to store program input and output information from the compiler. These folders also provide access to register, record, and leaf state information. We already introduced the program inputs .in file located in the inputs/ folder. When each Leo file in a transaction is run, .out files as well as a .state file are created as follows:

project/
├── Leo.toml
├── inputs/
│ ├── project.in
│ └── project.state
├── outputs/
│ └── project.out
└── src/
└── main.leo

Accessing State File Variables#

State register values can be accessed by passing the state, record, and state_leaf sections into the main function of a Leo file and accessing each variable via dot . syntax.

function main() {
let index = input.state.index;
let balance_is_zero = input.record.value_balance == 0u64;
let id_is_one = input.state_leaf.network_id == 1u8;
}