Skip to content

Commit c2ef6e8

Browse files
nventurobenesjan
andcommitted
refactor!: improve the aztec::history module
Long overdue. This clears up the `history` mod, removing the unnecessary traits and exposing functions instead, fixing lots of bad naming that confused people, addressing some clarifications re. siloed vs unsiloed params, and adding some docs where it was most needed. Fixes F-240. Built with Claude 🤖 (the docs are mine) Co-authored-by: Jan Beneš <[email protected]> Co-authored-by: Nicolás Venturo <[email protected]>
1 parent 60b84cc commit c2ef6e8

File tree

28 files changed

+641
-628
lines changed

28 files changed

+641
-628
lines changed

docs/docs-developers/docs/aztec-nr/framework-description/advanced/how_to_prove_history.md

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ You can create proofs for these elements at any past block height:
2020
- **Note inclusion** - prove a note existed in the note hash tree
2121
- **Note validity** - prove a note existed and wasn't nullified at a specific block
2222
- **Nullifier inclusion/non-inclusion** - prove a nullifier was or wasn't in the nullifier tree
23-
- **Contract deployment** - prove a contract was deployed or initialized
23+
- **Contract deployment** - prove a contract's bytecode was published or initialized
2424

2525
Common use cases:
2626
- Verify ownership of an asset from another contract without revealing which specific note
@@ -29,7 +29,7 @@ Common use cases:
2929

3030
## Prove note inclusion
3131

32-
Import the trait:
32+
Import the function:
3333

3434
#include_code history_import noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr rust
3535

@@ -42,10 +42,10 @@ Prove a note exists in the note hash tree:
4242
To prove a note was valid (existed AND wasn't nullified) at a historical block:
4343

4444
```rust
45-
use dep::aztec::history::note_validity::ProveNoteValidity;
45+
use dep::aztec::history::note::assert_note_was_valid_by;
4646

4747
let header = self.context.get_anchor_block_header();
48-
header.prove_note_validity(hinted_note, &mut self.context);
48+
assert_note_was_valid_by(header, hinted_note, &mut self.context);
4949
```
5050

5151
This verifies both:
@@ -57,8 +57,10 @@ This verifies both:
5757
To prove against state at a specific past block (not just the anchor block):
5858

5959
```rust
60+
use dep::aztec::history::note::assert_note_existed_by;
61+
6062
let historical_header = self.context.get_block_header_at(block_number);
61-
historical_header.prove_note_inclusion(hinted_note);
63+
assert_note_existed_by(historical_header, hinted_note);
6264
```
6365

6466
:::warning
@@ -70,45 +72,45 @@ Using `get_block_header_at` adds ~3k constraints to prove Archive tree membershi
7072
To prove a note has been spent/nullified:
7173

7274
```rust
73-
use dep::aztec::history::nullifier_inclusion::ProveNoteIsNullified;
75+
use dep::aztec::history::note::assert_note_was_nullified_by;
7476

7577
let header = self.context.get_anchor_block_header();
76-
header.prove_note_is_nullified(hinted_note, &mut self.context);
78+
assert_note_was_nullified_by(header, confirmed_note, &mut self.context);
7779
```
7880

79-
## Prove contract deployment
81+
## Prove contract bytecode was published
8082

81-
To prove a contract was deployed at a historical block:
83+
To prove a contract's bytecode was published at a historical block:
8284

8385
```rust
84-
use dep::aztec::history::contract_inclusion::ProveContractDeployment;
86+
use dep::aztec::history::deployment::assert_contract_bytecode_was_published_by;
8587

8688
let header = self.context.get_anchor_block_header();
87-
header.prove_contract_deployment(contract_address);
89+
assert_contract_bytecode_was_published_by(header, contract_address);
8890
```
8991

9092
You can also prove a contract was initialized (constructor was called):
9193

9294
```rust
93-
use dep::aztec::history::contract_inclusion::ProveContractInitialization;
95+
use dep::aztec::history::deployment::assert_contract_was_initialized_by;
9496

9597
let header = self.context.get_anchor_block_header();
96-
header.prove_contract_initialization(contract_address);
98+
assert_contract_was_initialized_by(header, contract_address);
9799
```
98100

99-
## Available proof traits
100-
101-
The `aztec::history` module provides these traits:
102-
103-
| Trait | Purpose |
104-
|-------|---------|
105-
| `ProveNoteInclusion` | Prove note exists in note hash tree |
106-
| `ProveNoteValidity` | Prove note exists and is not nullified |
107-
| `ProveNoteIsNullified` | Prove note's nullifier is in nullifier tree |
108-
| `ProveNoteNotNullified` | Prove note's nullifier is not in nullifier tree |
109-
| `ProveNullifierInclusion` | Prove a raw nullifier exists |
110-
| `ProveNullifierNonInclusion` | Prove a raw nullifier does not exist |
111-
| `ProveContractDeployment` | Prove a contract was deployed |
112-
| `ProveContractNonDeployment` | Prove a contract was not deployed |
113-
| `ProveContractInitialization` | Prove a contract was initialized |
114-
| `ProveContractNonInitialization` | Prove a contract was not initialized |
101+
## Available proof functions
102+
103+
The `aztec::history` module provides these functions:
104+
105+
| Function | Module | Purpose |
106+
|----------|--------|---------|
107+
| `assert_note_existed_by` | `history::note` | Prove note exists in note hash tree |
108+
| `assert_note_was_valid_by` | `history::note` | Prove note exists and is not nullified |
109+
| `assert_note_was_nullified_by` | `history::note` | Prove note's nullifier is in nullifier tree |
110+
| `assert_note_was_not_nullified_by` | `history::note` | Prove note's nullifier is not in nullifier tree |
111+
| `assert_nullifier_existed_by` | `history::nullifier` | Prove a raw nullifier exists |
112+
| `assert_nullifier_did_not_exist_by` | `history::nullifier` | Prove a raw nullifier does not exist |
113+
| `assert_contract_bytecode_was_published_by` | `history::deployment` | Prove a contract's bytecode was published |
114+
| `assert_contract_bytecode_was_not_published_by` | `history::deployment` | Prove a contract's bytecode was not published |
115+
| `assert_contract_was_initialized_by` | `history::deployment` | Prove a contract was initialized |
116+
| `assert_contract_was_not_initialized_by` | `history::deployment` | Prove a contract was not initialized |

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,35 @@ Aztec is in active development. Each version may introduce breaking changes that
99

1010
## TBD
1111

12+
### [aztec-nr] History module refactored to use standalone functions
13+
14+
The `aztec::history` module has been refactored to use standalone functions instead of traits. This changes the calling convention from method syntax to function syntax.
15+
16+
```diff
17+
- use dep::aztec::history::note_inclusion::ProveNoteInclusion;
18+
+ use dep::aztec::history::note::assert_note_existed_by;
19+
20+
let block_header = context.get_anchor_block_header();
21+
- let confirmed_note = block_header.prove_note_inclusion(hinted_note);
22+
+ let confirmed_note = assert_note_existed_by(block_header, hinted_note);
23+
```
24+
25+
**Function name and module mapping:**
26+
27+
| Old (trait method) | New (standalone function) |
28+
|--------------------|---------------------------|
29+
| `history::note_inclusion::prove_note_inclusion` | `history::note::assert_note_existed_by` |
30+
| `history::note_validity::prove_note_validity` | `history::note::assert_note_was_valid_by` |
31+
| `history::nullifier_inclusion::prove_nullifier_inclusion` | `history::nullifier::assert_nullifier_existed_by` |
32+
| `history::nullifier_inclusion::prove_note_is_nullified` | `history::note::assert_note_was_nullified_by` |
33+
| `history::nullifier_non_inclusion::prove_nullifier_non_inclusion` | `history::nullifier::assert_nullifier_did_not_exist_by` |
34+
| `history::nullifier_non_inclusion::prove_note_not_nullified` | `history::note::assert_note_was_not_nullified_by` |
35+
| `history::contract_inclusion::prove_contract_deployment` | `history::deployment::assert_contract_bytecode_was_published_by` |
36+
| `history::contract_inclusion::prove_contract_non_deployment` | `history::deployment::assert_contract_bytecode_was_not_published_by` |
37+
| `history::contract_inclusion::prove_contract_initialization` | `history::deployment::assert_contract_was_initialized_by` |
38+
| `history::contract_inclusion::prove_contract_non_initialization` | `history::deployment::assert_contract_was_not_initialized_by` |
39+
| `history::public_storage::public_storage_historical_read` | `history::storage::public_storage_historical_read` |
40+
1241
### [Aztec.js] Transaction sending API redesign
1342

1443
The old chained `.send().wait()` pattern has been replaced with a single `.send(options)` call that handles both sending and waiting.
@@ -4308,7 +4337,7 @@ await expect(
43084337

43094338
### [Aztec.nr] Public storage historical read API improvement
43104339

4311-
`history::public_value_inclusion::prove_public_value_inclusion` has been renamed to `history::public_storage::public_storage_historical_read`, and its API changed slightly. Instead of receiving a `value` parameter it now returns the historical value stored at that slot.
4340+
`history::public_value_inclusion::prove_public_value_inclusion` has been renamed to `history::storage::public_storage_historical_read`, and its API changed slightly. Instead of receiving a `value` parameter it now returns the historical value stored at that slot.
43124341

43134342
If you were using an oracle to get the value to pass to `prove_public_value_inclusion`, drop the oracle and use the return value from `public_storage_historical_read` instead:
43144343

noir-projects/aztec-nr/aztec/src/context/private_context.nr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -746,9 +746,9 @@ impl PrivateContext {
746746
///
747747
/// ## Historical Notes
748748
///
749-
/// If you need to assert that a note existed _at some specific time in the past_, instead of simply proving that it
750-
/// exists in the current anchor block, use
751-
/// [crate::history::note_inclusion::ProveNoteInclusion::prove_note_inclusion] instead.
749+
/// If you need to assert that a note existed _by some specific block in the past_, instead of simply proving that it
750+
/// exists by the current anchor block, use
751+
/// [crate::history::note::assert_note_existed_by] instead.
752752
///
753753
/// ## Cost
754754
///
@@ -784,9 +784,9 @@ impl PrivateContext {
784784
///
785785
/// ## Historical Nullifiers
786786
///
787-
/// If you need to assert that a nullifier existed _at some specific time in the past_, instead of simply proving
788-
/// that it exists in the current anchor block, use
789-
/// [crate::history::nullifier_inclusion::ProveNullifierInclusion::prove_nullifier_inclusion] instead.
787+
/// If you need to assert that a nullifier existed _by some specific block in the past_, instead of simply proving
788+
/// that it exists by the current anchor block, use
789+
/// [crate::history::nullifier::assert_nullifier_existed_by] instead.
790790
///
791791
/// ## Public vs Private
792792
///

noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//! Contract deployments.
2+
3+
use dep::protocol_types::{
4+
abis::block_header::BlockHeader, address::AztecAddress,
5+
constants::CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, hash::compute_siloed_nullifier,
6+
traits::ToField,
7+
};
8+
9+
use crate::history::nullifier::{assert_nullifier_did_not_exist_by, assert_nullifier_existed_by};
10+
11+
// This is tested in `noir-projects/noir-contracts/test_contract/src/test.nr because we cannot define a contract
12+
// from within aztec.nr (due to the contract macro).
13+
14+
pub fn assert_contract_bytecode_was_published_by(
15+
block_header: BlockHeader,
16+
contract_address: AztecAddress,
17+
) {
18+
let bytecode_publishing_nullifier = compute_siloed_nullifier(
19+
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
20+
contract_address.to_field(),
21+
);
22+
23+
assert_nullifier_existed_by(block_header, bytecode_publishing_nullifier);
24+
}
25+
26+
pub fn assert_contract_bytecode_was_not_published_by(
27+
block_header: BlockHeader,
28+
contract_address: AztecAddress,
29+
) {
30+
let bytecode_publishing_nullifier = compute_siloed_nullifier(
31+
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
32+
contract_address.to_field(),
33+
);
34+
35+
assert_nullifier_did_not_exist_by(block_header, bytecode_publishing_nullifier);
36+
}
37+
38+
pub fn assert_contract_was_initialized_by(
39+
block_header: BlockHeader,
40+
contract_address: AztecAddress,
41+
) {
42+
let initialization_nullifier =
43+
compute_siloed_nullifier(contract_address, contract_address.to_field());
44+
45+
assert_nullifier_existed_by(block_header, initialization_nullifier);
46+
}
47+
48+
pub fn assert_contract_was_not_initialized_by(
49+
block_header: BlockHeader,
50+
contract_address: AztecAddress,
51+
) {
52+
let initialization_nullifier =
53+
compute_siloed_nullifier(contract_address, contract_address.to_field());
54+
55+
assert_nullifier_did_not_exist_by(block_header, initialization_nullifier);
56+
}
Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
//! Proofs of Aztec history.
2+
//!
3+
//! ## Data Availability
4+
//!
5+
//! Functions in these modules assert statements about the past state of the Aztec network. While this is possible in
6+
//! theory, actual network nodes might not have the information required to produce proofs at relatively old blocks.
7+
//!
8+
//! In particular, many nodes prune old state and do not keep records of the different state trees (note hashes,
9+
//! nullifiers, public storage, etc.) at blocks older than a couple hours, which are required in order to produce the
10+
//! sibling paths these functions need.
11+
//!
12+
//! An archive node is therefore required when using any of these functions on non-recent blocks.
213

3-
pub mod contract_inclusion;
4-
pub mod note_inclusion;
5-
pub mod note_validity;
6-
pub mod nullifier_inclusion;
7-
pub mod nullifier_non_inclusion;
8-
pub mod public_storage;
14+
pub mod deployment;
15+
pub mod note;
16+
pub mod nullifier;
17+
pub mod storage;
918
mod test;

0 commit comments

Comments
 (0)