Skip to content

Commit

Permalink
Merge pull request #372 from AleoHQ/update/futures-technical-docs
Browse files Browse the repository at this point in the history
[Update] Remove finalize.
  • Loading branch information
d0cd authored May 21, 2024
2 parents 10ffb8f + 5eb9abe commit 9b596f3
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 89 deletions.
108 changes: 38 additions & 70 deletions documentation/leo/03_language.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,8 @@ program test.aleo {
## Layout of a Leo Program

A Leo program contains declarations of a [Program Scope](#program-scope), [Constants](#constant), [Imports](#import)
, [Transition Functions](#transition-function), [Helper Functions](#helper-function), [Structs](#struct)
, [Records](#record),
[Mappings](#mapping), and [Finalize Functions](#finalize-function).
, [Transition Functions](#transition-function), [Async Functions](#async-function), [Helper Functions](#helper-function), [Structs](#struct)
, [Records](#record), and [Mappings](#mapping).
Declarations are locally accessible within a program file.
If you need a declaration from another Leo file, you must import it.

Expand All @@ -154,7 +153,7 @@ A program scope in the sense of Leo is a collection of code (its functions) and
[program ID](#program-id) on the Aleo blockchain.

```leo
import foo.leo;
import foo.aleo;
program hello.aleo {
mapping balances: address => u64;
Expand All @@ -169,17 +168,17 @@ program hello.aleo {
object: u64,
}
transition mint_public(
async transition mint_public(
public receiver: address,
public amount: u64,
) -> token {
return token {
) -> (token, Future) {
return (token {
owner: receiver,
amount,
} then finalize(receiver, amount);
}, update_state(receiver, amount));
}
finalize mint_public(
async function update_state(
public receiver: address,
public amount: u64,
) {
Expand All @@ -201,7 +200,7 @@ The following must be declared inside the program scope in a Leo file:
- struct types
- transition functions
- helper functions
- finalize functions
- async functions

The following must be declared outside the program scope in a Leo file:

Expand Down Expand Up @@ -244,18 +243,11 @@ program foo.aleo {
### Import

You can import dependencies that are downloaded to the `imports` directory.
An import is declared as `import {filename}.leo;`
This will look for `imports/{filename}.leo` and bring all declarations into the current file scope.
If there are duplicate names for declarations, Leo will fail to compile.
Ordering is enforced for imports, which must be at the top of file.

:::caution
Leo imports are unstable and currently only provide minimal functionality.
Their syntax is expected to change.
:::
An import is declared as `import {filename}.aleo;`
The dependency resolver will pull the imported program from the network or the local filesystem.

```leo showLineNumbers
import foo.leo; // Import all `foo.leo` declarations into the `hello.aleo` program.
import foo.aleo; // Import all `foo.aleo` declarations into the `hello.aleo` program.
program hello.aleo { }
```
Expand Down Expand Up @@ -452,18 +444,16 @@ The rules for functions (in the traditional sense) are as follows:
- inlines can only call inlines.
- Direct/indirect recursive calls are not allowed

### Finalize Function
### Async Function

A finalize function is declared as `finalize {name}:` and is used to run computations on chain. One of its primary purposes is to initiate or change public on chain state within mappings. A finalize function must immediately follow a [transition function](#transition-function), and must have the same name;
it is associated with the transition function and is executed on chain,
after the zero-knowledge proof of the execution of the associated transition is verified;
a finalize function _finalizes_ a transition function on chain.
Upon success of the finalize function, the program logic is executed.
Upon failure of the finalize function, the program logic is reverted.
An async function is declared as `async function` and is used to define computation run on-chain.
It is asynchronous because the code gets executed at a later point in time.
One of its primary uses is to initiate or change public on chain state within mappings.
An async function can only be called by an async [transition function](#transition-function) and is executed on chain, after the zero-knowledge proof of the execution of the associated transition is verified.
Async functions are atomic; they either succeed or fail, and the state is reverted if they fail.

Consequently, nodes on the Aleo network execute the code of the finalize function. Only code within finalize blocks, run by nodes on the Aleo Network, updates program mappings. Only a program can write into its own mapping, but all nodes on the Aleo network can read the public state.

An example of on-chain state mutation is the transfer_public_to_private transition in the finalize example, which updates the public account mapping (and thus a user's balance) when called.
An example of using an async function to perform on-chain state mutation is in the `transfer_public_to_private` transition below, which updates the public account mapping (and thus a user's balance) when called.

```leo showLineNumbers
program transfer.aleo {
Expand All @@ -472,21 +462,21 @@ program transfer.aleo {
//
// This function preserves privacy for the receiver's record, however
// it publicly reveals the caller and the specified token amount.
transition transfer_public_to_private(
async transition transfer_public_to_private(
public receiver: address,
public amount: u64
) -> token {
) -> (token, Future) {
// Produce a token record for the token receiver.
let new: token = token {
owner: receiver,
amount,
};
// Return the receiver's record, then decrement the token amount of the caller publicly.
return new then finalize(self.caller, amount);
return (new, update_public_state(self.caller, amount));
}
finalize transfer_public_to_private(
async function update_public_state(
public sender: address,
public amount: u64
) {
Expand All @@ -499,7 +489,7 @@ program transfer.aleo {
}
```

If there is no need to create or alter the public on-chain state, finalize functions are not required.
If there is no need to create or alter the public on-chain state, async functions are not required.

### Mapping

Expand All @@ -520,18 +510,18 @@ The mapping struct allows the programmer to apply updates to a program mapping d
following functions.

:::info
Mapping operations are only allowed in a [finalize function](#finalize-function).
Mapping operations are only allowed in an [async function](#async-function).
:::

```leo showLineNumbers
program test.aleo {
mapping counter: address => u64;
transition dubble() {
return then finalize(self.caller);
async transition dubble() -> Future {
return update_mappings(self.caller);
}
finalize dubble(addr: address) {
async function update_mappings(addr: address) {
let current_value: u64 = Mapping::get_or_use(counter, addr, 0u64);
Mapping::set(counter, addr, current_value + 1u64);
current_value = Mapping::get(counter, addr);
Expand Down Expand Up @@ -718,14 +708,16 @@ program test.aleo {
Returns the height of the current block.

:::info
`block.height` is only allowed in a [finalize function](#finalize-function).
`block.height` is only allowed in an [async function](#async-function).
:::

```leo showLineNumbers
program test.aleo {
transition matches(height: u32) {
return then finalize(height);
} finalize matches(height: u32) {
async transition matches(height: u32) -> Future {
return check_block_height(height);
}
async function check_block_height(height: u32) {
assert_eq(height, block.height);
}
}
Expand Down Expand Up @@ -783,7 +775,7 @@ Leo supports the `ChaCha` random number generation algorithm.
The output type of a random function is specified in the function name. e.g. `rand_group` will return a `group` type.

:::info
Random functions are only allowed in a [finalize function](#finalize-function).
Random functions are only allowed in an [async function](#async-function).
:::

```leo showLineNumbers
Expand All @@ -800,31 +792,7 @@ let b: u32 = ChaCha::rand_u32();
`increment()` and `decrement()` functions are deprecated as of Leo v1.7.0.
Please use the [`Mapping::set()`](#set) function instead.

```leo showLineNumbers
program transfer.aleo {
// On-chain storage of an `account` map,
// with `address` as the key,
// and `u64` as the value.
mapping account: address => u64;
#### Finalize

transition transfer_public(...) {...}
finalize transfer_public(
public sender: address,
public receiver: address,
public amount: u64
) {
// Decrements `account[sender]` by `amount`.
// If `account[sender]` does not exist, it will be created.
// If `account[sender] - amount` underflows, `transfer_public` is reverted.
let sender_amount: u64 = Mapping::get_or_use(account, sender, 0u64);
Mapping::set(account, sender, sender_amount - amount);
// Increments `account[receiver]` by `amount`.
// If `account[receiver]` does not exist, it will be created.
// If `account[receiver] + amount` overflows, `transfer_public` is reverted.
let receiver_amount: u64 = Mapping::get_or_use(account, receiver, 0u64);
Mapping::set(account, receiver, receiver_amount + amount);
}
}
```
`finalize` and the associated programming model is deprecated as of Leo v2.0.0.
Please use an [`async function`](#async-function) instead.
13 changes: 7 additions & 6 deletions documentation/leo/04_operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,22 +335,23 @@ Checks whether `first` and `second` are not equal, halting if they are equal.
### `block.height`

```leo
transition matches(height: u32) {
return then finalize(height);
async transition matches(height: u32) -> Future {
return check_block_height(height);
}
finalize matches(height: u32) {
async function check_block_height(height: u32) {
assert_eq(height, block.height);
}
```

#### Description

The `block.height` operator is used to fetch the latest block height in a Leo program. It represents the number of
blocks in the chain. In the above example, `block.height` is used in a `finalize` context to fetch the latest block
blocks in the chain. In the above example, `block.height` is used in an async function to fetch the latest block
height in a program.

#### Note:
* The `block.height` operator can only be used in a `finalize` context. Using it outside a `finalize` context will result in a compilation error.
* The `block.height` operator can only be used in an async function. Using it outside an async function will result in a compilation error.
* The `block.height` operator doesn't take any parameters.

[Back to Top](#table-of-standard-operators)
Expand Down Expand Up @@ -1359,7 +1360,7 @@ let result: scalar = ChaCha::rand_scalar();
#### Description

Returns a random value with the destination type.
**Must be used in a finalize context**
**This operation can only be used in an async function.**

#### Supported Types

Expand Down
8 changes: 4 additions & 4 deletions documentation/leo/09_cheatsheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: Leo Syntax Cheatsheet

## 1. File Import
```leo
import foo.leo;
import foo.aleo;
```

## 2. Programs
Expand Down Expand Up @@ -111,10 +111,10 @@ let remove_bal: () = Mapping::remove(balances, receiver);

## 12. Commands
```leo
transition matches(height: u32) {
return then finalize(height);
transition matches(height: u32) -> Future {
return check_height_matches(height);
}
finalize matches(height: u32) {
async function check_height_matches(height: u32) {
assert_eq(height, block.height); // block.height returns latest block height
}
Expand Down
8 changes: 5 additions & 3 deletions documentation/leo/11_basic_bank.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Can you find any others?
- record ownership
- loops and bounded iteration
- mappings
- finalize
- async/await

## How to Run

Expand Down Expand Up @@ -95,7 +95,7 @@ leo run deposit "{
}" 50u64
```

You'll see that the output contains a new private record belonging to the user with 50 credits, and a finalize `deposit` function taking the arguments (bank address, amount) that will update a public mapping with 50 credits. This information is queryable on-chain.
You'll see that the output contains a new private record belonging to the user with 50 credits, and a `Future` indicating code to be run on-chain and its associated inputs.

## <a id="wait"></a> Wait

Expand All @@ -116,4 +116,6 @@ PRIVATE_KEY=APrivateKey1zkpHtqVWT6fSHgUMNxsuVf7eaR6id2cj7TieKY1Z8CP5rCD
leo run withdraw aleo1zeklp6dd8e764spe74xez6f8w27dlua3w7hl4z2uln03re52egpsv46ngg 50u64 1234u64 15u64
```

You'll see here the withdrawal function creates a new private record for the user containing all 266 withdrawn tokens, and then calls the finalize `withdraw` function with arguments (address, amount), which will update the public balance of the bank back to 0. The public mapping will be queryable on-chain.
You'll see here the withdrawal function creates a new private record for the user containing all 266 withdrawn tokens, and then outputs a `Future` which will be run on-chain.

```
6 changes: 3 additions & 3 deletions documentation/leo/13_token.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ PRIVATE_KEY=APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR
leo run mint_public aleo13ssze66adjjkt795z9u5wpq8h6kn0y2657726h4h3e3wfnez4vqsm3008q 100u64
```

You can see the output of the finalize function of `mint_public`, which takes the arguments Alice's address and the amount of tokens to mint publicly. This information is shown on-chain and can be queried on a network.
You can see the output of `mint_public`, which takes the arguments Alice's address and the amount of tokens to mint publicly. This information is shown on-chain and can be queried on a network.

## <a id="step1"></a> Private Mint

Expand Down Expand Up @@ -119,7 +119,7 @@ PRIVATE_KEY=APrivateKey1zkp1w8PTxrRgGfAtfKUSq43iQyVbdQHfhGbiNPEg2LVSEXR
leo run transfer_public_to_private aleo17vy26rpdhqx4598y5gp7nvaa9rk7tnvl6ufhvvf4calsrrqdaqyshdsf5z 30u64
```

When calling `transfer_public_to_private`, we see the finalize function with the arguments to modify Alice's public token mapping (address, amount), and a private record created that's owned by Bob and contains 110 tokens.
Calling `transfer_public_to_private`, outputs a `Future`, which indicates code to be run on-chain, along with its associated inputs.

## <a id="step5"></a> Private to Public Transfer

Expand All @@ -138,4 +138,4 @@ leo run transfer_private_to_public "{
}" aleo13ssze66adjjkt795z9u5wpq8h6kn0y2657726h4h3e3wfnez4vqsm3008q 40u64
```

When we call `transfer_private_to_public`, we take Bob's private record that contains 110 tokens, and outputs a record owned by Bob with 70 tokens, and calls the finalize function under `transfer_private_to_public` with Alice's address and 40 tokens as arguments. This changes the public mapping under Alice's address to contain 100 public tokens. Again, public mappings are queryable on-chain.
When we call `transfer_private_to_public`, we take Bob's private record that contains 110 tokens, and outputs a record owned by Bob with 70 tokens, and then outputs a `Future` which will be run on-chain.
7 changes: 4 additions & 3 deletions documentation/leo/17_testnet_beta.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ program bar.aleo {
...
let (c, f): (foo.aleo/credit, Future) = foo.aleo/bar(...);
...
return c then finalize(f, ...);
return (c, finalize_bar(f, ...));
}
finalize bar(f: Future, ...) {
async function finalize_bar(f: Future, ...) {
f.await();
...
}
Expand Down Expand Up @@ -179,7 +180,7 @@ If you haven't updated Leo in a while, you're probably used to using `.leo` in y


**The updated rules are:**
- all programs must end with a `.leo` file extension.
- all files containing Leo programs must end with a `.leo` file extension.
- all imports must be defined with the `.aleo` prefix.
- all program scopes must be declared with the `.aleo` prefix.
- all external calls must be made with the `.aleo` prefix.
Expand Down

0 comments on commit 9b596f3

Please sign in to comment.