Skip to content

Commit 80a9e03

Browse files
authored
chore!: noir contracts, notes and note abstractions cleanup (#18782)
Fixes #15959 Partially addresses #15966 There was a lot of mess lying around the codebase which had a real cost when it comes to maintenance. In this PR I: - moved `BalanceSet` from token contract to a separate `balance_set` crate, - drop the copies of `balance_set.nr` and use the one shared crate, - drop `BalancesMap` from token blacklist and use there `BalanceSet`, - drop `EasyPrivateUint` and use `BalanceSet` instead, - drop the ugly utils from `ValueNote` and either use `BalanceSet` instead or I copy the utils to the test contracts where they were used (those test contracts are an ugly mess already so hiding it there seems fine), - renamed `ValueNote` as `FieldNote`, - dropped stale `DocsExample` contract and pointed readers to run `nargo expand` instead. Now I can live in peace.
2 parents 29f2d4e + d5031ca commit 80a9e03

File tree

81 files changed

+316
-1076
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+316
-1076
lines changed

boxes/boxes/react/src/contracts/Nargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ type = "contract"
66

77
[dependencies]
88
aztec = { path = "../../../../../noir-projects/aztec-nr/aztec" }
9-
value_note = { path = "../../../../../noir-projects/aztec-nr/value-note" }
9+
field_note = { path = "../../../../../noir-projects/aztec-nr/field-note" }

boxes/boxes/react/src/contracts/src/main.nr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ contract BoxReact {
88
protocol_types::address::AztecAddress,
99
state_vars::{Owned, PrivateMutable},
1010
};
11-
use value_note::value_note::ValueNote;
11+
use field_note::field_note::FieldNote;
1212

1313
#[storage]
1414
struct Storage<Context> {
15-
numbers: Owned<PrivateMutable<ValueNote, Context>, Context>,
15+
numbers: Owned<PrivateMutable<FieldNote, Context>, Context>,
1616
}
1717

1818
#[external("private")]
1919
#[initializer]
2020
fn constructor(number: Field, owner: AztecAddress) {
21-
let new_number = ValueNote::new(number);
21+
let new_number = FieldNote::new(number);
2222

2323
self.storage.numbers.at(owner).initialize(new_number).emit(
2424
owner,
@@ -28,14 +28,14 @@ contract BoxReact {
2828

2929
#[external("private")]
3030
fn setNumber(number: Field, owner: AztecAddress) {
31-
self.storage.numbers.at(owner).replace(|_old| ValueNote::new(number)).emit(
31+
self.storage.numbers.at(owner).replace(|_old| FieldNote::new(number)).emit(
3232
owner,
3333
MessageDelivery.CONSTRAINED_ONCHAIN,
3434
);
3535
}
3636

3737
#[external("utility")]
38-
unconstrained fn getNumber(owner: AztecAddress) -> ValueNote {
38+
unconstrained fn getNumber(owner: AztecAddress) -> FieldNote {
3939
self.storage.numbers.at(owner).view_note()
4040
}
4141
}

boxes/boxes/vanilla/contracts/Nargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ type = "contract"
44

55
[dependencies]
66
aztec = { path = "../../../../noir-projects/aztec-nr/aztec" }
7-
value_note = { path = "../../../../noir-projects/aztec-nr/value-note" }
8-
easy_private_state = { path = "../../../../noir-projects/aztec-nr/easy-private-state" }
7+
field_note = { path = "../../../../noir-projects/aztec-nr/field-note" }

boxes/boxes/vite/src/contracts/Nargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ type = "contract"
66

77
[dependencies]
88
aztec = { path = "../../../../../noir-projects/aztec-nr/aztec" }
9-
value_note = { path = "../../../../../noir-projects/aztec-nr/value-note" }
9+
field_note = { path = "../../../../../noir-projects/aztec-nr/field-note" }

boxes/boxes/vite/src/contracts/src/main.nr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ contract BoxReact {
88
protocol_types::address::AztecAddress,
99
state_vars::{Owned, PrivateMutable},
1010
};
11-
use value_note::value_note::ValueNote;
11+
use field_note::field_note::FieldNote;
1212

1313
#[storage]
1414
struct Storage<Context> {
15-
numbers: Owned<PrivateMutable<ValueNote, Context>, Context>,
15+
numbers: Owned<PrivateMutable<FieldNote, Context>, Context>,
1616
}
1717

1818
#[external("private")]
1919
#[initializer]
2020
fn constructor(number: Field, owner: AztecAddress) {
21-
let new_number = ValueNote::new(number);
21+
let new_number = FieldNote::new(number);
2222

2323
self.storage.numbers.at(owner).initialize(new_number).emit(
2424
owner,
@@ -28,14 +28,14 @@ contract BoxReact {
2828

2929
#[external("private")]
3030
fn setNumber(number: Field, owner: AztecAddress) {
31-
self.storage.numbers.at(owner).replace(|_old| ValueNote::new(number)).emit(
31+
self.storage.numbers.at(owner).replace(|_old| FieldNote::new(number)).emit(
3232
owner,
3333
MessageDelivery.CONSTRAINED_ONCHAIN,
3434
);
3535
}
3636

3737
#[external("utility")]
38-
unconstrained fn getNumber(owner: AztecAddress) -> ValueNote {
38+
unconstrained fn getNumber(owner: AztecAddress) -> FieldNote {
3939
self.storage.numbers.at(owner).view_note()
4040
}
4141
}

docs/docs/developers/docs/aztec-cli/local-network-reference.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ ContractClassRegistryContractArtifact
106106
ContractInstanceRegistryContractArtifact
107107
CounterContractArtifact
108108
CrowdfundingContractArtifact
109-
DocsExampleContractArtifact
110109
PrivateTokenContractArtifact
111110
PrivateVotingContractArtifact
112111
EcdsaAccountContractArtifact

docs/docs/developers/docs/aztec-nr/framework-description/functions/attributes.md

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,42 @@ A private function operates on private information, and is executed by the user
2121

2222
`#[external("private")]` is just syntactic sugar. At compile time, the Aztec.nr framework inserts code that allows the function to interact with the [kernel](../../../foundational-topics/advanced/circuits/kernels/private_kernel.md).
2323

24-
To help illustrate how this interacts with the internals of Aztec and its kernel circuits, we can take an example private function, and explore what it looks like after Aztec.nr's macro expansion.
24+
If you are interested in what exactly the macros are doing we encourage you to run `nargo expand` on your contract.
25+
This will display your contract's code after the transformations are performed.
2526

26-
#### Before expansion
27-
28-
#include_code simple_macro_example /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
29-
30-
#### After expansion
31-
32-
#include_code simple_macro_example_expanded /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
27+
(If you are using VSCode you can display the expanded code by pressing `CMD + Shift + P` and typing `nargo expand` and selecting `Noir: nargo expand on current package.)
3328

3429
#### The expansion broken down
3530

3631
Viewing the expanded Aztec contract uncovers a lot about how Aztec contracts interact with the kernel. To aid with developing intuition, we will break down each inserted line.
3732

3833
**Receiving context from the kernel.**
39-
#include_code context-example-inputs /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
4034

4135
Private function calls are able to interact with each other through orchestration from within the kernel circuits. The kernel circuit forwards information to each contract function (recall each contract function is a circuit). This information then becomes part of the private context.
42-
For example, within each private function we can access some global variables. To access them we can call on the `context`, e.g. `context.chain_id()`. The value of the chain ID comes from the values passed into the circuit from the kernel.
36+
For example, within each private function we can access some global variables. To access them we can call on the `self.context`, e.g. `self.context.chain_id()`. The value of the chain ID comes from the values passed into the circuit from the kernel.
4337

4438
The kernel checks that all of the values passed to each circuit in a function call are the same.
4539

46-
**Returning the context to the kernel.**
47-
#include_code context-example-return /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
48-
49-
The contract function must return information about the execution back to the kernel. This is done through a rigid structure we call the `PrivateCircuitPublicInputs`.
50-
51-
> _Why is it called the `PrivateCircuitPublicInputs`?_
52-
> When verifying zk programs, return values are not computed at verification runtime, rather expected return values are provided as inputs and checked for correctness. Hence, the return values are considered public inputs.
53-
54-
This structure contains a host of information about the executed program. It will contain any newly created nullifiers, any messages to be sent to l2 and most importantly it will contain the return values of the function.
55-
56-
5740
**Creating the function's `self.`**
58-
#include_code contract_self_creation /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
5941

6042
Each Aztec function has access to a `self` object. Upon creation it accepts storage and context. Context is initialized from the inputs provided by the kernel, and a hash of the function's inputs.
6143

62-
#include_code context-example-context-return /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
63-
6444
We use the kernel to pass information between circuits. This means that the return values of functions must also be passed to the kernel (where they can be later passed on to another function).
6545
We achieve this by pushing return values to the execution context, which we then pass to the kernel.
6646

6747
**Hashing the function inputs.**
6848

6949
Inside the kernel circuits, the inputs to functions are reduced to a single value; the inputs hash. This prevents the need for multiple different kernel circuits; each supporting differing numbers of inputs. Hashing the inputs allows to reduce all of the inputs to a single value.
7050

51+
**Returning the context to the kernel.**
52+
53+
The contract function must return information about the execution back to the kernel. This is done through a rigid structure we call the `PrivateCircuitPublicInputs`.
54+
55+
> _Why is it called the `PrivateCircuitPublicInputs`?_
56+
> When verifying zk programs, return values are not computed at verification runtime, rather expected return values are provided as inputs and checked for correctness. Hence, the return values are considered public inputs.
57+
58+
This structure contains a host of information about the executed program. It will contain any newly created nullifiers, any messages to be sent to l2 and most importantly it will contain the return values of the function.
59+
7160
**Making the contract's storage available**
7261

7362
Each `self` has a `storage` variable exposed on it.
@@ -78,7 +67,6 @@ If Storage is note defined `self.storage` contains only a placeholder value.
7867
Any state variables declared in the `Storage` struct can now be accessed as normal struct members.
7968

8069
**Returning the function context to the kernel.**
81-
#include_code context-example-finish /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust
8270

8371
This function takes the application context, and converts it into the `PrivateCircuitPublicInputs` structure. This structure is then passed to the kernel circuit.
8472

docs/docs/developers/docs/resources/migration_notes.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,68 @@ Aztec is in full-speed development. Literally every version breaks compatibility
99

1010
## TBD
1111

12+
### [Aztec.nr] `ValueNote` renamed to `FieldNote` and `value-note` crate renamed to `field-note`
13+
14+
The `ValueNote` struct has been renamed to `FieldNote` to better reflect that it stores a `Field` value. The crate has also been renamed from `value-note` to `field-note`.
15+
16+
**Migration:**
17+
18+
- Update your `Nargo.toml` dependencies: `value_note = { path = "..." }``field_note = { path = "..." }`
19+
- Update imports: `use value_note::value_note::ValueNote``use field_note::field_note::FieldNote`
20+
- Update type references: `ValueNote``FieldNote`
21+
- Update generic parameters: `PrivateSet<ValueNote, ...>``PrivateSet<FieldNote, ...>`
22+
23+
### [Aztec.nr] New `balance-set` library for managing token balances
24+
25+
A new `balance-set` library has been created that provides `BalanceSet<Context>` for managing u128 token balances with `UintNote`. This consolidates balance management functionality that was previously duplicated across contracts.
26+
27+
**Features:**
28+
29+
- `add(amount: u128)` - Add to balance
30+
- `sub(amount: u128)` - Subtract from balance (with change note)
31+
- `try_sub(amount: u128, max_notes: u32)` - Attempt to subtract with configurable note limit
32+
- `balance_of()` - Get total balance (unconstrained)
33+
34+
**Usage:**
35+
36+
```rust
37+
use balance_set::BalanceSet;
38+
39+
#[storage]
40+
struct Storage<Context> {
41+
balances: Owned<BalanceSet<Context>, Context>,
42+
}
43+
44+
// In a private function:
45+
self.storage.balances.at(owner).add(amount).emit(owner, MessageDelivery.CONSTRAINED_ONCHAIN);
46+
self.storage.balances.at(owner).sub(amount).emit(owner, MessageDelivery.CONSTRAINED_ONCHAIN);
47+
48+
// In an unconstrained function:
49+
let balance = self.storage.balances.at(owner).balance_of();
50+
```
51+
52+
### [Aztec.nr] `EasyPrivateUint` deprecated and removed
53+
54+
The `EasyPrivateUint` type and `easy-private-state` crate have been deprecated and removed. Use `BalanceSet` from the `balance-set` crate instead.
55+
56+
**Migration:**
57+
58+
- Remove `easy_private_state` dependency from `Nargo.toml`
59+
- Add `balance_set = { path = "../../../../aztec-nr/balance-set" }` to `Nargo.toml`
60+
- Update storage: `EasyPrivateUint<Context>``Owned<BalanceSet<Context>, Context>`
61+
- Update method calls:
62+
- `add(amount, owner)``at(owner).add(amount).emit(owner, MessageDelivery.CONSTRAINED_ONCHAIN)`
63+
- `sub(amount, owner)``at(owner).sub(amount).emit(owner, MessageDelivery.CONSTRAINED_ONCHAIN)`
64+
- `get_value(owner)``at(owner).balance_of()` (returns `u128` instead of `Field`)
65+
66+
### [Aztec.nr] `balance_utils` removed from `value-note` (now `field-note`)
67+
68+
The `balance_utils` module has been removed from the `field-note` crate (formerly `value-note`). If you need similar functionality, implement it locally in your contract or use `BalanceSet` for u128 balances.
69+
70+
### [Aztec.nr] `filter_notes_min_sum` removed from `value-note` (now `field-note`)
71+
72+
The `filter_notes_min_sum` function has been removed from the `field-note` crate (formerly in `value-note`). If you need this functionality, copy it to your contract locally. This function was only used in specific test contracts and doesn't belong in the general-purpose note library.
73+
1274
### [Aztec.nr] `derive_ecdh_shared_secret_using_aztec_address` removed
1375

1476
This function made it annoying to deal with invalid addresses in circuits. If you were using it, replace it with `derive_ecdh_shared_secret` instead:

docs/examples/contracts/bob_token_contract/Nargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ type = "contract"
44

55
[dependencies]
66
aztec = { path = "../../../../noir-projects/aztec-nr/aztec" }
7-
easy_private_state = { path = "../../../../noir-projects/aztec-nr/easy-private-state" }
7+
balance_set = { path = "../../../../noir-projects/aztec-nr/balance-set" }

docs/examples/contracts/bob_token_contract/src/main.nr

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ pub contract BobToken {
77
// docs:end:start
88
use aztec::{
99
macros::{functions::{external, initializer, only_self}, storage::storage},
10-
protocol_types::address::AztecAddress, state_vars::Map,
10+
messages::message_delivery::MessageDelivery,
11+
protocol_types::address::AztecAddress,
12+
state_vars::{Map, Owned},
1113
state_vars::public_mutable::PublicMutable,
1214
};
1315
// docs:end:imports
1416

15-
use easy_private_state::EasyPrivateUint;
17+
use balance_set::BalanceSet;
1618

1719
// docs:start:public_storage
1820
// docs:start:storage
@@ -24,7 +26,7 @@ pub contract BobToken {
2426
public_balances: Map<AztecAddress, PublicMutable<u64, Context>, Context>,
2527
// docs:end:public_storage
2628
// Private balances - only the owner can see these
27-
private_balances: EasyPrivateUint<Context>,
29+
private_balances: Owned<BalanceSet<Context>, Context>,
2830
}
2931
// docs:end:storage
3032

@@ -80,7 +82,10 @@ pub contract BobToken {
8082
// This will enqueue a public function to deduct from public balance
8183
self.enqueue_self._deduct_public_balance(sender, amount);
8284
// Add to private balance
83-
self.storage.private_balances.add(amount, sender);
85+
self.storage.private_balances.at(sender).add(amount as u128).emit(
86+
sender,
87+
MessageDelivery.CONSTRAINED_ONCHAIN,
88+
);
8489
}
8590
// docs:end:public_to_private
8691

@@ -100,16 +105,22 @@ pub contract BobToken {
100105
fn transfer_private(to: AztecAddress, amount: u64) {
101106
let sender = self.msg_sender().unwrap();
102107
// Spend sender's notes (consumes existing notes)
103-
self.storage.private_balances.sub(amount, sender);
108+
self.storage.private_balances.at(sender).sub(amount as u128).emit(
109+
sender,
110+
MessageDelivery.CONSTRAINED_ONCHAIN,
111+
);
104112
// Create new notes for recipient
105-
self.storage.private_balances.add(amount, to);
113+
self.storage.private_balances.at(to).add(amount as u128).emit(
114+
to,
115+
MessageDelivery.CONSTRAINED_ONCHAIN,
116+
);
106117
}
107118
// docs:end:transfer_private
108119

109120
// docs:start:check_balances
110121
#[external("utility")]
111-
unconstrained fn private_balance_of(owner: AztecAddress) -> Field {
112-
self.storage.private_balances.get_value(owner)
122+
unconstrained fn private_balance_of(owner: AztecAddress) -> pub u128 {
123+
self.storage.private_balances.at(owner).balance_of()
113124
}
114125

115126
#[external("utility")]
@@ -133,7 +144,10 @@ pub contract BobToken {
133144
self.enqueue_self._assert_is_owner(self.msg_sender().unwrap());
134145

135146
// If check passes, mint tokens privately
136-
self.storage.private_balances.add(amount, employee);
147+
self.storage.private_balances.at(employee).add(amount as u128).emit(
148+
employee,
149+
MessageDelivery.CONSTRAINED_ONCHAIN,
150+
);
137151
}
138152
// docs:end:mint_private
139153

@@ -143,7 +157,10 @@ pub contract BobToken {
143157
fn private_to_public(amount: u64) {
144158
let sender = self.msg_sender().unwrap();
145159
// Remove from private balance
146-
self.storage.private_balances.sub(amount, sender);
160+
self.storage.private_balances.at(sender).sub(amount as u128).emit(
161+
sender,
162+
MessageDelivery.CONSTRAINED_ONCHAIN,
163+
);
147164
// Enqueue public credit
148165
self.enqueue_self._credit_public_balance(sender, amount);
149166
}

0 commit comments

Comments
 (0)