You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Include a high level overview in Foundational Concepts of the
transaction lifecycle.
- formatting the common patterns page
- added a note about a generic error to the Debugging page
ClosesAztecProtocol#3764
# Checklist:
Remove the checklist to signal you've completed it. Enable auto-merge if
the PR is ready to merge.
- [x] If the pull request requires a cryptography review (e.g.
cryptographic algorithm implementations) I have added the 'crypto' tag.
- [ ] I have reviewed my diff in github, line by line and removed
unexpected formatting changes, testing logs, or commented-out code.
- [x] Every change is related to the PR description.
- [ ] I have
[linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
this pull request to relevant issues (if any exist).
Copy file name to clipboardexpand all lines: docs/docs/concepts/foundation/transactions.md
+35-3
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
title: Transactions
3
3
---
4
4
5
-
Transactions on Aztec start with a call from Aztec.js or the Aztec CLI, which creates a request containing transaction details. This request moves to the Private Execution Environment (PXE) which simulates and processes it. Then the PXE interacts with the Aztec Node which uses the sequencer to ensure that all the transaction details are enqueued properly. The sequencer then submits the block to the rollup contract, and the transaction is successfully mined.
5
+
import Image from '@theme/IdealImage';
6
6
7
7
On this page you'll learn:
8
8
@@ -11,13 +11,45 @@ On this page you'll learn:
11
11
- The Aztec Kernel and its two circuits: private and public, and how they execute function calls
12
12
- The call stacks for private & public functions and how they determine a transaction's completion
13
13
14
+
## Simple Example of the (Private) Transaction Lifecycle
15
+
16
+
The transaction lifecycle for an Aztec transaction is fundamentally different from the lifecycle of an Ethereum transaction.
17
+
18
+
The introduction of the Private eXecution Environment (PXE) provides a safe environment for the execution of sensitive operations, ensuring that decrypted data are not accessible to unauthorized applications. However, the PXE exists client-side on user devices, which creates a different model for imagining a transaction lifecycle. The existence of a sequencing network also introduces some key differences between the Aztec transaction model and the transaction model used for other networks.
19
+
20
+
The accompanying diagram illustrates the flow of interactions between a user, their wallet, the PXE, the node operators (sequencers / provers), and the L1 chain.
1.**The user initiates a transaction** – the user decides to privately send 10 DAI to gudcause.eth. After inputting the amount and the receiving address, the user clicks the confirmation button on their wallet.
25
+
26
+
_The transaction has not been broadcasted to the sequencer network yet._
27
+
28
+
2.**The PXE executes transfer locally** – The PXE, running locally on the user's device, executes the transfer method on the DAI token contract on Aztec and computes the state difference based on the user’s intention.
29
+
30
+
_The transaction has still not been broadcasted to the sequencer network yet._
31
+
32
+
3.**The PXE proves correct execution** – the PXE proves correct execution (via zero-knowledge proofs) of the authorization and the private transfer method. Once the proofs have been generated, the PXE sends the proofs and required inputs (inputs are new note commitments, stored in the [note hash tree](../advanced/data_structures/trees.md#note-hash-tree) and nullifiers stored in the [nullifiers tree](../advanced/data_structures/trees.md#nullifier-tree)) to the sequencer. Nullifiers are data that invalidate old commitments, ensuring that commitments can only be used once.
33
+
34
+
The sequencer has received transaction proof and can begin to process the transaction (verify proofs and apply updates to the relevant [data trees](../advanced/data_structures/trees.md)) alongside other public and private transactions.
35
+
36
+
4.**The sequencer has the necessary information to act** – the randomly-selected sequencer (based on the Fernet sequencer selection protocol) validates the transaction proofs along with required inputs (e.g. the note commitments and nullifiers) for this private transfer. The sequencer also executes public functions and requests proofs of public execution from a prover network. The sequencer updates the corresponding data trees and does the same for other private transactions. The sequencer requests proofs from a prover network that will be bundled into a final rollup proof.
37
+
38
+
_The sequencer has passed the transaction information – proofs of correct execution and authorization, or public function execution information – to the prover, who will submit the new state root to Ethereum._
39
+
40
+
5.**The transaction settles to L1** – the verifier contract on Ethereum can now validate the rollup proof and record a new state root. The state root is submitted to the rollup smart contract. Once the state root is verified in an Ethereum transaction, the private transfer has settled and the transaction is considered final.
41
+
42
+
### Going deeper
43
+
44
+
Transactions on Aztec start with a call from Aztec.js or the Aztec CLI, which creates a request containing transaction details. This request moves to the Private Execution Environment (PXE) which simulates and processes it. Then the PXE interacts with the Aztec Node which uses the sequencer to ensure that all the transaction details are enqueued properly. The sequencer then submits the block to the rollup contract, and the transaction is successfully mined.
45
+
14
46
<ahref="https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg"><imgsrc="/img/sandbox_sending_a_tx.svg"alt="Sending a transaction" /></a>
15
47
16
-
See [this diagram](https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg) for an in-depth overview of the transaction execution process. It highlights 3 different types of transaction execution: contract deployments, private transactions and public transactions.
48
+
See [this diagram](https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg) for a more detailed overview of the transaction execution process. It highlights 3 different types of transaction execution: contract deployments, private transactions and public transactions.
17
49
18
50
See the page on [contract communication](./communication/main.md) for more context on transaction execution.
19
51
20
-
## Enabling Transaction Semantics: The Aztec Kernel
52
+
###Enabling Transaction Semantics: The Aztec Kernel
21
53
22
54
There are two kernel circuits in Aztec, the private kernel and the public kernel. Each circuit validates the correct execution of a particular function call.
Copy file name to clipboardexpand all lines: docs/docs/dev_docs/contracts/resources/common_patterns/main.md
+31-12
Original file line number
Diff line number
Diff line change
@@ -9,48 +9,56 @@ This doc aims to summarize some of them!
9
9
Similarly we have discovered some anti-patterns too (like privacy leakage) that we will point out here!
10
10
11
11
## Common Patterns
12
+
12
13
### Safe Math and SafeU120
14
+
13
15
Field operations may overflow/underflow. Hence we have built a SafeMath library that you can use [based on instructions here](../dependencies.md#safe-math)
14
16
15
17
### SafeU120 for comparison operations on Field elements
18
+
16
19
Comparison on Field is also not possible today. For such cases, we recommend using u120, which is wrapped under the SafeU120 class found in the SafeMath library.
17
20
18
21
### Approving another user/contract to execute an action on your behalf
22
+
19
23
We call this the "authentication witness" pattern or authwit for short.
Here you approve someone to transfer funds publicly on your behalf
29
34
30
-
### Prevent the same user flow from happening twice using nullifiers
35
+
### Prevent the same user flow from happening twice using nullifiers
36
+
31
37
E.g. you don't want a user to subscribe once they have subscribed already. Or you don't want them to vote twice once they have done that. How do you prevent this?
32
38
33
-
Emit a nullifier in your function. By adding this nullifier into the tree, you prevent another nullifier from being added again. This is also why in authwit, we emit a nullifier, to prevent someone from reusing their approval.
39
+
Emit a nullifier in your function. By adding this nullifier into the tree, you prevent another nullifier from being added again. This is also why in authwit, we emit a nullifier, to prevent someone from reusing their approval.
Note be careful to ensure that the nullifier is not deterministic and that no one could do a preimage analysis attack. More in [the anti pattern section on deterministic nullifiers](#deterministic-nullifiers)
38
44
39
-
Note - you could also create a note and send it to the user. The problem is there is nothing stopping the user from not presenting this note when they next interact with the function.
45
+
Note - you could also create a note and send it to the user. The problem is there is nothing stopping the user from not presenting this note when they next interact with the function.
40
46
41
47
### Reading public storage in private
48
+
42
49
You can't read public storage in private domain. But nevertheless reading public storage is desirable. There are two ways:
43
50
44
51
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).
45
52
46
53
2. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.:
54
+
47
55
```rust
48
56
structStorage {
49
57
token:PublicState<Field, 1>,
50
58
}
51
59
52
60
contractBridge {
53
-
61
+
54
62
#[aztec(private)]
55
63
fnburn_token_private(
56
64
token:AztecAddress, // pass token here since this is a private method but can't access public storage
@@ -62,8 +70,9 @@ contract Bridge {
62
70
#include_codeassert_token_is_same/yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr raw
63
71
}
64
72
```
73
+
65
74
:::danger
66
-
This leaks information about the private function being called and the data which has been read.
75
+
This leaks information about the private function being called and the data which has been read.
67
76
:::
68
77
69
78
### Writing public storage from private
@@ -72,20 +81,22 @@ When calling a private function, you can update public state by calling a public
72
81
In this situation, try to mark the public function as `internal`. This ensures your flow works as intended and that no one can call the public function without going through the private function first!
73
82
74
83
### Moving public data into the private domain
84
+
75
85
Let's say you have some storage in public and want to move them into the private domain. If you pass your aztec address that should receive the data, then that leaks privacy (as everyone will know who has the private notes). So what do you do?
76
86
77
-
1. You have to create a note in public domain and can't encrypt it, because you can't leak the public key of the receiver.
87
+
1. You have to create a note in public domain and can't encrypt it, because you can't leak the public key of the receiver.
78
88
2. So how do you control who can claim this note? Pass a hash of a secret instead of the address. And then in the private domain, pass the preimage (the secret) to later claim your funds
79
89
80
90
So you have to create a custom note in the public domain that is not encrypted by some owner - we call such notes a "TransparentNote" since it is created in public, anyone can see the amount and the note is not encrypted by some owner.
81
91
82
92
This pattern is discussed in detail in [writing a token contract section in the shield() method](../../../tutorials/writing_token_contract.md#shield) and [redeem_shield() method](../../../tutorials/writing_token_contract.md#redeem_shield).
83
93
84
94
### Discovering my notes
95
+
85
96
When you send someone a note, the note hash gets added to the [note hash tree](../../../../concepts/advanced/data_structures/trees#note-hash-tree). To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes:
86
97
87
98
1. When sending someone a note, use `emit_encrypted_log` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](../../syntax/events.md)
88
-
2.Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`emit_encrypted_log` shouldn't be called in the public domain because everything is public), like in the previous section where we created a TransparentNote in public.
99
+
2. Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`emit_encrypted_log` shouldn't be called in the public domain because everything is public), like in the previous section where we created a TransparentNote in public.
> Alice and Bob agree to a trade, where Alice sends Bob a passcode to collect funds from a web2 app, in exchange of on-chain tokens. Alice should only send Bob the passcode if the trade is successful. But just sending the passcode as an encrypted log doesn't work, since Bob could see the encrypted log from the transaction as soon as Alice broadcasts it, decrypt it to get the passcode, and withdraw his tokens from the trade to make the transaction fail.
103
114
104
115
### Randomness in notes
116
+
105
117
Notes are hashed and stored in the merkle tree. While notes do have a header with a `nonce` field that ensure two exact notes still can be added to the note hash tree (since hashes would be different), preimage analysis can be done to reverse-engineer the contents of the note.
106
118
107
119
Hence, it's necessary to add a "randomness" field to your note to prevent such attacks.
### Working with `compute_note_hash_and_nullifier()`
124
+
112
125
Currently, if you have storage defined, the compiler will error if you don't have a `compute_note_hash_and_nullifier()` defined. Without this, the PXE can't process encrypted events and discover your notes.
113
126
114
127
If your contract doesn't have anything to do with notes (e.g. operates solely in the public domain), you can do the following:
@@ -119,37 +132,43 @@ Otherwise, you need this method to help the PXE with processing your notes. In o
Refer to [Token Portal tutorial on bridging tokens between L1 and L2](../../../tutorials/token_portal/main.md) and/or [Uniswap tutorial that shows how to swap on L1 using funds on L2](../../../tutorials/uniswap/main.md). Both examples show how to:
137
+
123
138
1. L1 -> L2 message flow
124
139
2. L2 -> L1 message flow
125
140
3. Cancelling messages from L1 -> L2.
126
141
4. For both L1->L2 and L2->L1, how to operate in the private and public domain
127
142
128
143
### Sending notes to a contract/Escrowing notes between several parties in a contract
144
+
129
145
To send a note to someone, they need to have a key which we can encrypt the note with. But often contracts may not have a key. And even if they do, how does it make use of it autonomously?
130
146
131
147
There are several patterns here:
148
+
132
149
1. Give the contract a key and share it amongst all participants. This leaks privacy, as anyone can see all the notes in the contract.
133
150
2.`Unshield` funds into the contract - this is used in the [Uniswap tutorial where a user sends private funds into a Uniswap Portal contract which eventually withdraws to L1 to swap on L1 Uniswap](../../../tutorials/uniswap/swap_privately.md). This works like ethereum - to achieve contract composability, you move funds into the public domain. This way the contract doesn't even need keys.
134
151
135
152
There are several other designs we are discussing through [in this discourse post](https://discourse.aztec.network/t/how-to-handle-private-escrows-between-two-parties/2440) but they need some changes in the protocol or in our demo contract. If you are interested in this discussion, please participate in the discourse post!
136
153
137
154
### Share Private Notes
155
+
138
156
If you have private state that needs to be handled by more than a single user (but no more than a handful), you can add the note commitment to the note hash tree, and then encrypt the note once for each of the users that need to see it. And if any of those users should be able to consume the note, you can generate a random nullifier on creation and store it in the encrypted note, instead of relying on the user secret.
139
157
140
158
## Anti Patterns
159
+
141
160
There are mistakes one can make to reduce their privacy set and therefore make it trivial to do analysis and link addresses. Some of them are:
142
161
143
162
### Passing along your address when calling a public function from private
163
+
144
164
If you have a private function which calls a public function, remember that sequencer can see any parameters passed to the public function. So try to not pass any parameter that might leak privacy (e.g. `from` address)
145
165
146
166
PS: when calling from private to public, `msg_sender` is the contract address which is calling the public function.
147
167
148
168
### Deterministic nullifiers
169
+
149
170
In the [Prevent the same user flow from happening twice using nullifier](#prevent-the-same-user-flow-from-happening-twice-using-nullifiers), we recommended using nullifiers. But what you put in the nullifier is also as important.
150
171
151
-
E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](../../../../concepts/foundation/accounts/keys.md#nullifier-secrets). E.g.:
172
+
E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](../../../../concepts/foundation/accounts/keys.md#nullifier-secrets). E.g.:
Copy file name to clipboardexpand all lines: docs/docs/dev_docs/debugging/aztecnr-errors.md
+6
Original file line number
Diff line number
Diff line change
@@ -76,3 +76,9 @@ This error occurs when your contract is trying to get a secret via the `get_secr
76
76
77
77
This error might occur when you register an account only as a recipient and not as an account.
78
78
To address the error, register the account by calling `server.registerAccount(...)`.
79
+
80
+
#### `Failed to solve brillig function, reason: explicit trap hit in brillig 'self._is_some`
81
+
82
+
You may encounter this error when trying to send a transaction that is using an invalid contract. The contract may compile without errors and you only encounter this when sending the transaction.
83
+
84
+
This error may arise when function parameters are not properly formatted, when trying to "double-spend" a note, or it may indicate that there is a bug deeper in the stack (e.g. a bug in the Aztec.nr library or deeper). If you hit this error, double check your contract implementation, but also consider [opening an issue](https://github.com/AztecProtocol/aztec-packages/issues/new).
0 commit comments