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(docs): Document slow update tree #3416

Merged
merged 28 commits into from Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f366378
slow update tree explanation
catmcgee Nov 24, 2023
412b298
sidebar
catmcgee Nov 24, 2023
b7f91fb
how-to without include_code
catmcgee Nov 24, 2023
a477e0a
delete file
catmcgee Nov 24, 2023
777dc54
sidebar
catmcgee Nov 24, 2023
e1fef5a
docs build errors
catmcgee Nov 25, 2023
6dec84f
include_code
catmcgee Nov 26, 2023
05f4049
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 26, 2023
fd14bf2
fix typo
catmcgee Nov 26, 2023
43d687c
fix docs build errors
catmcgee Nov 26, 2023
cc5be40
Merge branch 'master' into docs-slow-updates-tree
critesjosh Nov 27, 2023
f9d37e3
Apply suggestions from code review
catmcgee Nov 28, 2023
7b22f94
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 28, 2023
7e2560f
address changes, added reference
catmcgee Nov 28, 2023
5c8a915
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 28, 2023
1db9550
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 28, 2023
84d7488
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 28, 2023
46cbad0
more information on each component, restructured, diagram
catmcgee Nov 29, 2023
4a66e8c
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 29, 2023
9f96bb2
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 29, 2023
d509627
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 29, 2023
08d0030
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 30, 2023
e6a95f5
historic -> historical
catmcgee Nov 30, 2023
33a0a8a
Merge branch 'master' into docs-slow-updates-tree
catmcgee Nov 30, 2023
d3c98c1
comments & grammar
catmcgee Dec 1, 2023
2f3e733
broken link
catmcgee Dec 1, 2023
78cd724
merge conflicts
catmcgee Dec 1, 2023
21b814d
Merge branch 'master' into docs-slow-updates-tree
catmcgee Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/docs/about_aztec/roadmap/engineering_roadmap.md
Expand Up @@ -119,7 +119,9 @@ CI takes up a significant amount of time. It gets its own section here, so we re

## Slow Updates tree?

We _need_ a way to read mutable public data from a private function.
We _need_ a way to read mutable public data from a private function.

Note: we just published the [Slow Updates Tree](../../concepts/foundation/communication/public_private_calls/slow_updates_tree.md).

## Contract classes and instances?

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/concepts/foundation/accounts/keys.md
Expand Up @@ -28,7 +28,7 @@ Similar to using a private note, but using an immutable private note removes the

### Using the slow updates tree

A compromise between the two solutions above is to use the slow updates tree. This would not generate additional nullifiers and commitments for each transaction while allowing the user to rotate their key. However, this causes every transaction to now have a time-to-live determined by the frequency of the slow updates tree.
A compromise between the two solutions above is to use the [slow updates tree](../communication/public_private_calls/slow_updates_tree.md). This would not generate additional nullifiers and commitments for each transaction while allowing the user to rotate their key. However, this causes every transaction to now have a time-to-live determined by the frequency of the slow updates tree.

### Reusing the privacy master key

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/concepts/foundation/accounts/main.md
Expand Up @@ -127,7 +127,7 @@ These two patterns combined allow an account contract to answer whether an actio

Aztec requires users to define [encryption and nullifying keys](./keys.md) that are needed for receiving and spending private notes. Unlike transaction signing, encryption and nullifying is enshrined at the protocol. This means that there is a single scheme used for encryption and nullifying. These keys are derived from a master public key. This master public key, in turn, is used when deterministically deriving the account's address.

A side effect of committing to a master public key as part of the address is that _this key cannot be rotated_. While an account contract implementation could include methods for rotating the signing key, this is unfortunately not possible for encryption and nullifying keys (note that rotating nullifying keys also creates other challenges such as preventing double spends). We are exploring usage of the slow updates tree to enable rotating these keys.
A side effect of committing to a master public key as part of the address is that _this key cannot be rotated_. While an account contract implementation could include methods for rotating the signing key, this is unfortunately not possible for encryption and nullifying keys (note that rotating nullifying keys also creates other challenges such as preventing double spends). We are exploring usage of the [slow updates tree](../communication/public_private_calls/slow_updates_tree.md) to enable rotating these keys.

NOTE: While we entertained the idea of abstracting note encryption, where account contracts would define an `encrypt` method that would use a user-defined scheme, there are two main reasons we decided against this. First is that this entailed that, in order to receive funds, a user had to first deploy their account contract, which is a major UX issue. Second, users could define malicious `encrypt` methods that failed in certain circumstances, breaking application flows that required them to receive a private note. While this issue already exists in Ethereum when transferring ETH (see the [king of the hill](https://coinsbench.com/27-king-ethernaut-da5021cd4aa6)), its impact is made worse in Aztec since any execution failure in a private function makes the entire transaction unprovable (ie it is not possible to catch errors in calls to other private functions), and furthermore because encryption is required for any private state (not just for transferring ETH). Nevertheless, both of these problems are solvable. Initialization can be worked around by embedding a commitment to the bytecode in the address and removing the need for actually deploying contracts before interacting with them, and the king of the hill issue can be mitigated by introducing a full private VM that allows catching reverts. As such, we may be able to abstract encryption in the future as well.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/concepts/foundation/communication/main.md
Expand Up @@ -4,6 +4,6 @@ title: Contract Communication

This section will walk over communication types that behaves differently than normal function calls from.

Namely, if functions are in different domains, private vs. public, their execution behaves a little differently to what you might expect! See [Private <--> Public execution](./public_private_calls.md).
Namely, if functions are in different domains, private vs. public, their execution behaves a little differently to what you might expect! See [Private <--> Public execution](./public_private_calls/main.md).

Likewise, executing a function on a different domain than its origin needs a bit extra thought. See [L1 <--> L2 communication](./cross_chain_calls.md).
Expand Up @@ -4,7 +4,7 @@ title: Private <--> Public execution

import Image from "@theme/IdealImage";

import Disclaimer from "../../../misc/common/\_disclaimer.mdx";
import Disclaimer from "../../../../misc/common/\_disclaimer.mdx";
catmcgee marked this conversation as resolved.
Show resolved Hide resolved

<Disclaimer/>

Expand Down Expand Up @@ -105,3 +105,5 @@ function onlyFresh(pub uint256 blockNumber) public {
:::info
This is not a perfect solution, as any functions using access control might end up doing a lot of public calls it could put a significant burden on sequencers and greatly increase the cost of the transaction for the user. We are investigating ways to improve.
:::

Using a dual-tree structure with a pending and a current tree, it is possible to update public data from a private function. The update is fulfilled when the pending tree becomes the current after the end of a specified epoch. It is also possible to read historical public data directly from a private function. This works perfectly for public data that is not updated often, such as a blacklist. This structure is called a slow updates tree, and you can read about how it works [in the next section](./slow_updates_tree.md).
@@ -0,0 +1,73 @@
---
title: Privately access Historical Public Data
---

In Aztec, private and public execution environments are completely separate and operate with distinct state management. It is not possible for private functions to reliably access the most recent public data public state - only sequencers can do that. You'll want to [read the previous section](./main.md) to understand this before reading this page.

But, what about historical public data (or public data that changes infrequently)? Through a **slow updates tree**, private functions can access historical public state. Please note that we are still experimenting with this feature.

On this page you will learn:

1. Why a slow updates tree exists & use cases
2. How it works
3. How it can be used to access historical public data
4. Limitations

## The need for a slow updates tree
catmcgee marked this conversation as resolved.
Show resolved Hide resolved

This structure was created specifically to privately & publicly access historical public data. It should be used to store public data that doesn't change often.

- Access historical public data from a private function
- Access historical public data from a public function
- Update public data (that does not need updated often) from public and private functions

This data structure is ideal for these use cases:

- Address Registry: Enabling contracts to interact with other contracts more easily requires address storage accessible in both public and private executions. This can be particularly helpful in things such as proxy contracts.
- Access Control: Managing privileges in contracts, such as a token contract owner’s ability to mint new tokens, is streamlined when control information is shared between public and private executions. This might include things like blacklists and whitelists.

## How it works

We developed the Slow Updates Tree to help balance public and private execution in a blockchain context. Earlier systems typically used either fully public or entirely private state trees.

The Slow Updates Tree is a dual-tree structure - a current tree and a pending tree. Any updates are added to the pending tree, which then becomes the current tree at the end of an epoch. The pending tree is replicated from the current tree, and the cycle begins again.

```mermaid
graph TD;
Change{Epoch Over} -->|True| Current{Current}
catmcgee marked this conversation as resolved.
Show resolved Hide resolved
Change -->|False| Pending{Pending}
Current --> Current1[Current Commitment 1]
Current --> CurrentM[Current Commitment 2]
CurrentM --> Value1[Current Value 1]
CurrentM --> Value2[Current Value 2]
CurrentM --> ValueN[Current Value n]
Pending --> PendingM[Pending Commitment 1]
PendingM --> PValue1[Pending Value 1]
PendingM --> PValue2[Pending Value 2]
PendingM --> PValueN[Pending Value n]
```

This way, we can ensure that the values are stable throughout the epoch, and that the membership proofs are not invalidated by changes in other contracts more than once every epoch.

## Reads and Writes

### Accessing Data

*From public state:* Accessed directly from the state
*From private state:* Performs a membership proof for the values in the tree, ensuring that they are part of the commitment.
catmcgee marked this conversation as resolved.
Show resolved Hide resolved

catmcgee marked this conversation as resolved.
Show resolved Hide resolved
### Updating Data

Updates are made to the pending tree. Then at the end of each epoch, the updates in the pending tree are committed and it becomes the current tree.
catmcgee marked this conversation as resolved.
Show resolved Hide resolved

## Limitations

### Delayed State Finality

Updates in the Slow Updates Tree are only finalized at the end of an epoch.

Developers are used to instant state updates, so the Slow Updates Tree might take some getting used to. But we believe this won't take long!

## Dive into the code

For a code walkthrough of how a token blacklist contract can use a slow updates tree, read [this](../../../../dev_docs/contracts/syntax/slow_updates_tree.md).
2 changes: 1 addition & 1 deletion docs/docs/concepts/foundation/main.md
Expand Up @@ -24,7 +24,7 @@ A user of the Aztec network will interact with the network through Aztec.js. Azt

### Private Execution Environment

The PXE provides a secure environment for the execution of sensitive operations, ensuring private information and decrypted data are not accessible to unauthorized applications. It hides the details of the [state model](./state_model/main.md) from end users, but the state model is important for Aztec developers to understand as it has implications for [private/public execution](./communication/public_private_calls.md) and [L1/L2 communication](./communication/cross_chain_calls.md). The PXE also includes the [ACIR Simulator](../advanced/acir_simulator.md) for private executions and the KeyStore for secure key management.
The PXE provides a secure environment for the execution of sensitive operations, ensuring private information and decrypted data are not accessible to unauthorized applications. It hides the details of the [state model](./state_model/main.md) from end users, but the state model is important for Aztec developers to understand as it has implications for [private/public execution](./communication/public_private_calls/main.md) and [L1/L2 communication](./communication/cross_chain_calls.md). The PXE also includes the [ACIR Simulator](../advanced/acir_simulator.md) for private executions and the KeyStore for secure key management.

Procedurally, the PXE sends results of private function execution and requests for public function executions to the [sequencer](./nodes_clients/sequencer.md), which will update the state of the rollup.

Expand Down
Expand Up @@ -41,7 +41,7 @@ Note - you could also create a note and send it to the user. The problem is ther
### Reading public storage in private
You can't read public storage in private domain. But nevertheless reading public storage is desirable. There are two ways:

1. For public storage that changes infrequently, use the slow updates tree! More details TBD
1. For public storage that changes infrequently, use the slow updates tree! Learn more about it [here](../../../../concepts/foundation/communication/public_private_calls/slow_updates_tree.md).

2. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.:
```rust
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/dev_docs/contracts/syntax/functions.md
Expand Up @@ -20,7 +20,7 @@ In Aztec there are multiple different types of visibility that can be applied to

### Data Visibility

Data visibility is used to describe whether the data (or state) used in a function is generally accessible (public) or on a need to know basis (private). Functions with public data visibility are executed by the sequencer, and functions with private data visibility are executed by the user. For more information on why this is the case, see [communication](../../../concepts/foundation/communication/public_private_calls.md).
Data visibility is used to describe whether the data (or state) used in a function is generally accessible (public) or on a need to know basis (private). Functions with public data visibility are executed by the sequencer, and functions with private data visibility are executed by the user. For more information on why this is the case, see [communication](../../../concepts/foundation/communication/public_private_calls/main.md).

In the following sections, we are going to see how these two "types" co-exists and interact.

Expand Down Expand Up @@ -213,7 +213,7 @@ Calling a public function from another public function is quite similar to what

### Private -> Public

As discussed above, private function execution and calls take place on the user's device, while public function execution and calls take place on a sequencer, in two different places at two different times, it is natural to question how we can achieve composability between the two. The solution is asynchronicity. Further reading can be found in the foundational concepts [here](../../../concepts/foundation/communication/public_private_calls.md).
As discussed above, private function execution and calls take place on the user's device, while public function execution and calls take place on a sequencer, in two different places at two different times, it is natural to question how we can achieve composability between the two. The solution is asynchronicity. Further reading can be found in the foundational concepts [here](../../../concepts/foundation/communication/public_private_calls/main.md).

Private function execution takes place on the users device, where it keeps track of any public function calls that have been made. Whenever private execution completes, and a kernel proof is produced, the transaction sent to the network will include all of the public calls that were dispatched.
When the sequencer receives the messages, it will take over and execute the public parts of the transaction.
Expand Down