Skip to content

Commit

Permalink
docs: misc docs changes (#2416)
Browse files Browse the repository at this point in the history
Addresses miscellaneous issues in the documentation. Building on top of
#2408.
  • Loading branch information
LHerskind authored Sep 20, 2023
1 parent 6a75fd0 commit 0e789c7
Show file tree
Hide file tree
Showing 15 changed files with 263 additions and 214 deletions.
28 changes: 26 additions & 2 deletions docs/docs/dev_docs/contracts/layout.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
# Layout
---
title: Structure
---

A contract is a collection of persistent [state variables](./syntax/state_variables.md), and [functions](./syntax/functions) which may manipulate these variables. Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called.

# Contract

A contract may be declared and given a name using the `contract` keyword (see snippet below). By convention, contracts are named in `PascalCase`.

```rust title="contract keyword"
// highlight-next-line
contract MyContract {

// Imports

// Storage

// Functions
}
```
:::info A note for vanilla Noir devs
There is no [`main()`](https://noir-lang.org/getting_started/breakdown/#mainnr) function within a Noir `contract` scope. More than one function can be an entrypoint.
:::

## Directory structure

Expand All @@ -11,4 +34,5 @@ Here's a common layout for a basic Aztec.nr Contract project:
└── Nargo.toml <-- package and dependency management
```

> See the vanilla Noir docs for [more info on packages](https://noir-lang.org/modules_packages_crates/crates_and_packages).
- See the vanilla Noir docs for [more info on packages](https://noir-lang.org/modules_packages_crates/crates_and_packages).
- You can review the structure of a complete contract in the token contract tutorial [here](../getting_started/token_contract_tutorial.md).
2 changes: 1 addition & 1 deletion docs/docs/dev_docs/contracts/syntax/context.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Aztec.nr Context
title: Function Context
description: Documentation of Aztec's Private and Public execution contexts
hide_table_of_contents: false
---
Expand Down
31 changes: 0 additions & 31 deletions docs/docs/dev_docs/contracts/syntax/contract.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ title: Events
Events in Aztec work similarly to Ethereum events in the sense that they are a way for contracts to communicate with the outside world.
They are emitted by contracts and stored inside each instance of an AztecNode.

> Aztec events are currently represented as raw data and are not ABI encoded.
> ABI encoded events are a feature that will be added in the future.
:::info
Aztec events are currently represented as raw data and are not ABI encoded.
ABI encoded events are a feature that will be added in the future.
:::

Unlike on Ethereum, there are 2 types of events supported by Aztec: encrypted and unencrypted.

### Encrypted Events
## Encrypted Events

Encrypted events can only be emitted by private functions and are encrypted using a public key of a recipient.
For this reason it is necessary to register a recipient in the Aztec RPC Server before encrypting the events for them.
Expand Down Expand Up @@ -51,29 +53,49 @@ await aztecRpc.registerRecipient(completeAddress);
</TabItem>
</Tabs>

> **NOTE**: If a note recipient is one of the accounts inside the Aztec RPC Server, we don't need to register it as a recipient because we already have the public key available.
:::info
If a note recipient is one of the accounts inside the Aztec RPC Server, we don't need to register it as a recipient because we already have the public key available. You can register a recipient as shown [here](../deploying#deploying-private-token-contract)

> At this point the Sandbox only enables the emitting of encrypted note preimages through encrypted events.
> In the future we will allow emitting arbitrary information.
> (If you currently emit arbitrary information, Aztec RPC Server will fail to decrypt, process and store this data, so it will not be queryable).
At this point the Sandbox only enables the emitting of encrypted note preimages through encrypted events.
In the future we will allow emitting arbitrary information.
(If you currently emit arbitrary information, Aztec RPC Server will fail to decrypt, process and store this data, so it will not be queryable).
:::

To emit encrypted logs first import the `emit_encrypted_log` utility function inside your contract:
To emit encrypted logs first import the `emit_encrypted_log` utility function which wraps an [oracle](./functions.md#oracle-functions):

#include_code encrypted_import /yarn-project/aztec-nr/value-note/src/utils.nr rust

Then you can call the function:

#include_code encrypted /yarn-project/aztec-nr/value-note/src/utils.nr rust

### Unencrypted Events
### Processing Encrypted Events

Unencrypted events are events which can be read by anyone.
They can be emitted by both public and private functions.
One of the functions of the Aztec RPC Server is constantly loading encrypted logs from the `AztecNode` and decrypting them.
When new encrypted logs are obtained, the Aztec RPC Server will try to decrypt them using the private encryption key of all the accounts registered inside Aztec RPC Server.
If the decryption is successful, the Aztec RPC Server will store the decrypted note inside a database.
If the decryption fails, the specific log will be discarded.

For the Aztec RPC Server to successfully process the decrypted note we need to compute the note's 'note hash' and 'nullifier'.
Aztec.nr enables smart contract developers to design custom notes, meaning developers can also customize how a note's note hash and nullifier should be computed. Because of this customizability, and because there will be a potentially-unlimited number of smart contracts deployed to Aztec, an Aztec RPC Server needs to be 'taught' how to compute the custom note hashes and nullifiers for a particular contract. Therefore, developers will need to implement a `compute_note_hash_and_nullifier` function inside their contracts.

:::danger
If your function has private state variables, you **MUST** include a `compute_note_hash_and_nullifier` function to allow the RPC to process encrypted events.
:::

Every time a new note is successfully decrypted, the Aztec RPC Server will expect the existence of a `compute_note_hash_and_nullifier` function, which must teach it how to correctly process the new note.

#include_code compute_note_hash_and_nullifier /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust


## Unencrypted Events

Emitting unencrypted events from private function is a significant privacy leak and it should be considered by the developer whether it is acceptable.
Unencrypted events are events which can be read by anyone.
They can be emitted by both public and private functions.

:::danger
- Emitting unencrypted events from private function is a significant privacy leak and it should be considered by the developer whether it is acceptable.
- Unencrypted events are currently **NOT** linked to the contract emitting them, so it is practically a [`debug_log`](./functions.md#a-few-useful-inbuilt-oracles).
:::

To emit unencrypted logs first import the `emit_unencrypted_log` utility function inside your contract:
Expand Down Expand Up @@ -104,31 +126,11 @@ aztec-cli get-logs --from 5 --limit 1

All event data is pushed to Ethereum as calldata by the sequencer and for this reason the cost of emitting an event is non-trivial.

> Note: the cost of submitting calldata to Ethereum is currently 4 gas per byte. Currently, in the Sandbox, an encypted note has a fixed overhead of 4 field elements (to broadcast an ephemeral public key, a contract address, and a storage slot); plus a variable number of field elements depending on the type of note being emitted.
> A `ValueNote`, for example, currently uses 3 fields elements (plus the fixed overhead of 4). That's roughly `7 * 32 = 224` bytes of information, costing roughly 896 gas.
> There are plans to compress encrypted note data further.
> There are plans to adopt EIP-4844 blobs to reduce the cost of data submission further.
## Processing events

Both the encrypted and unencrypted events are stored in AztecNode.
Unencrypted logs can be queried by anyone as we described above in the [Unencrypted Events](#unencrypted-events) section.

Encrypted logs need to first be decrypted:

### Decrypting
In the Sandbox, an encrypted note has a fixed overhead of 4 field elements (to broadcast an ephemeral public key, a contract address, and a storage slot); plus a variable number of field elements depending on the type of note being emitted.

One function of Aztec RPC Server is constantly loading encrypted logs from AztecNode and trying to decrypt them.
When new encrypted logs are obtained, the Aztec RPC Server will try to decrypt them using the private encryption key of all the accounts registered inside Aztec RPC Server.
If the decryption is successful, the Aztec RPC Server will store the decrypted note inside a database.
If the decryption fails, the specific log will be discarded.

For the Aztec RPC Server to successfully process the decrypted note we need to compute the note's 'note hash' and 'nullifier'.
Aztec.nr enables smart contract developers to design custom notes, meaning developers can also customise how a note's note hash and nullifier should be computed. Because of this customisability, and because there will be a potentially-unlimited number of smart contracts deployed to Aztec, an Aztec RPC Server needs to be 'taught' how to compute the custom note hashes and nullifiers for a particular contract. Therefore, developers will need to implement a `compute_note_hash_and_nullifier` function inside their contracts.

Every time a new note is successfully decrypted, the Aztec RPC Server will expect the existence of a `compute_note_hash_and_nullifier` function, which must teach it how to correctly process the new note.
A `ValueNote`, for example, currently uses 3 fields elements (plus the fixed overhead of 4). That's roughly `7 * 32 = 224` bytes of information.

This is an example implementation inside the `PrivateTokenContract`:
#include_code value-note-def /yarn-project/aztec-nr/value-note/src/value_note.nr

#include_code compute_note_hash_and_nullifier /yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr rust
- There are plans to compress encrypted note data further.
- There are plans to adopt EIP-4844 blobs to reduce the cost of data submission further.
11 changes: 11 additions & 0 deletions docs/docs/dev_docs/contracts/syntax/functions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
title: Functions
description: This page covers functions, private and public functions composability, as well as their differences.
---


Expand All @@ -23,6 +24,15 @@ A good place to use `internal` is when you want a private function to be able to
Note that non-internal functions could be used directly as an entry-point, which currently means that the `msg_sender` would be `0`, so for now, using address `0` as a burn address is not recommended.
:::

## Mutability
Currently, any function is "mutable" in the sense that it might alter state. In the future, we will support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). This is useful for when you want to call a function in a separate contract, but ensure that it cannot alter state, or call other functions that might alter state (such as re-entering).

Similarly, a special case of a mutating call is the `delegatecall` where the function executed might not be in the same contract as the state being altered. It is at this moment, not certain if `delegatecall`s should become a fully fledged feature.

:::danger No `staticcall` or `delegatecall` support
While `staticcall` and `delegatecall` both have flags in the call context, they are currently not supported and will not behave as one would expect if usage is attempted.
:::

## `constructor`

- A special `constructor` function MUST be declared within a contract's scope.
Expand Down Expand Up @@ -92,6 +102,7 @@ Oracles introduce **non-determinism** into a circuit, and thus are `unconstraine
- [`auth_witness`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/oracle/auth_witness.nr) - Provides a way to fetch the authentication witness for a given address. This is useful when building account contracts to support approve-like functionality.
- [`get_l1_to_l2_message`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr) - Useful for application that receive messages from L1 to be consumed on L2, such as token bridges or other cross-chain applications.
- [`notes`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/oracle/notes.nr) - Provides a lot of functions related to notes, such as fetches notes from storage etc, used behind the scenes for value notes and other pre-build note implementations.
- [`logs`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/oracle/logs.nr) - Provides the to log encrypted and unencrypted data.


---
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/dev_docs/contracts/syntax/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ context.block_number();
```

:::info *Why do the available global variables differ per execution environment?*
> The global variables are constrained by the proving environment. In the case of public functions, they are executed on a sequencer that will know the timestamp and number of the next block ( as they are the block producer ).
> In the case of private functions, we cannot be sure which block our transaction will be included in, hence we can not guarantee values for the timestamp or block number.
The global variables are constrained by the proving environment. In the case of public functions, they are executed on a sequencer that will know the timestamp and number of the next block ( as they are the block producer ).
In the case of private functions, we cannot be sure which block our transaction will be included in, hence we can not guarantee values for the timestamp or block number.
:::
6 changes: 3 additions & 3 deletions docs/docs/dev_docs/contracts/syntax/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ Aztec.nr contains abstractions which remove the need to understand the low-level

- Public and private [state variable types](./state_variables.md)
- Some pre-designed notes
- Functions for [emitting](../events.md) encrypted and unencrypted logs
- [Oracle functions](./functions.md#oracle-calls) for accessing:
- Functions for [emitting](./events.md) encrypted and unencrypted logs
- [Oracle functions](./functions.md#oracle-functions) for accessing:
- private state
- secrets
- Functions for communicating with Ethereum L1
- Functions for communicating with [Ethereum L1](./messaging.md)

To import Aztec.nr into your Aztec contract project, simply include it as a dependency. For example:

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/dev_docs/contracts/syntax/state_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ For example, the following function calls the account contract before it updates

In contrast to public state, private state is persistent state that is _not_ visible to the whole world. Depending on the logic of the smart contract, a _private_ state variable's current value will only be known to one entity, or a closed group of entities.

The value of a private state variable can either be shared via [events](../events), or offchain via web2, or completely offline: it's up to the app developer.
The value of a private state variable can either be shared via [events](./events.md), or offchain via web2, or completely offline: it's up to the app developer.

Aztec private state follows a utxo-based model. That is, a private state's current value is represented as one or many [notes](#notes). Each note is stored as an individual leaf in a utxo-based merkle tree: the [private state tree](/concepts/advanced/data_structures/trees#private-state-tree).

Expand Down
Loading

0 comments on commit 0e789c7

Please sign in to comment.