Skip to content

Commit ec124dc

Browse files
authored
feat: merge-train/fairies (#21182)
BEGIN_COMMIT_OVERRIDE fix: empty undefined offchain messages for batch calls (#21157) feat: add aztecaddress::is_valid (#21072) feat: add ergonomic conversions for Noir's `Option<T>` (#21107) chore: use returns `true` for boolean fns (#21186) feat: add salt and secret params to env.deploy (#21183) END_COMMIT_OVERRIDE
2 parents ceb3429 + c4abe8d commit ec124dc

32 files changed

Lines changed: 837 additions & 49 deletions

File tree

noir-projects/aztec-nr/aztec/src/note/note_metadata.nr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,21 @@ impl NoteMetadata {
6868
}
6969
}
7070

71-
/// Returns true if the note is pending **and** from the same phase, i.e. if it's been created in the current
71+
/// Returns `true` if the note is pending **and** from the same phase, i.e. if it's been created in the current
7272
/// transaction during the current execution phase (either non-revertible or revertible).
7373
pub fn is_pending_same_phase(self) -> bool {
7474
self.stage == NoteStage.PENDING_SAME_PHASE
7575
}
7676

77-
/// Returns true if the note is pending **and** from the previous phase, i.e. if it's been created in the current
77+
/// Returns `true` if the note is pending **and** from the previous phase, i.e. if it's been created in the current
7878
/// transaction during an execution phase prior to the current one. Because private execution only has two phases
7979
/// with strict ordering, this implies that the note was created in the non-revertible phase, and that the current
8080
/// phase is the revertible phase.
8181
pub fn is_pending_previous_phase(self) -> bool {
8282
self.stage == NoteStage.PENDING_PREVIOUS_PHASE
8383
}
8484

85-
/// Returns true if the note is settled, i.e. if it's been created in a prior transaction and is therefore already
85+
/// Returns `true` if the note is settled, i.e. if it's been created in a prior transaction and is therefore already
8686
/// in the note hash tree.
8787
pub fn is_settled(self) -> bool {
8888
self.stage == NoteStage.SETTLED

noir-projects/aztec-nr/aztec/src/oracle/nullifiers.nr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn notify_created_nullifier(inner_nullifier: Field) {
1414
#[oracle(aztec_prv_notifyCreatedNullifier)]
1515
unconstrained fn notify_created_nullifier_oracle(_inner_nullifier: Field) {}
1616

17-
/// Returns true if the nullifier has been emitted in the same transaction, i.e. if [`notify_created_nullifier`] has
17+
/// Returns `true` if the nullifier has been emitted in the same transaction, i.e. if [`notify_created_nullifier`] has
1818
/// been
1919
/// called for this inner nullifier from the contract with the specified address.
2020
///
@@ -29,7 +29,7 @@ pub unconstrained fn is_nullifier_pending(inner_nullifier: Field, contract_addre
2929
#[oracle(aztec_prv_isNullifierPending)]
3030
unconstrained fn is_nullifier_pending_oracle(_inner_nullifier: Field, _contract_address: AztecAddress) -> bool {}
3131

32-
/// Returns true if the nullifier exists. Note that a `true` value can be constrained by proving existence of the
32+
/// Returns `true` if the nullifier exists. Note that a `true` value can be constrained by proving existence of the
3333
/// nullifier, but a `false` value should not be relied upon since other transactions may emit this nullifier before
3434
/// the current transaction is included in a block. While this might seem of little use at first, certain design
3535
/// patterns benefit from this abstraction (see e.g. `PrivateMutable`).

noir-projects/aztec-nr/aztec/src/oracle/version.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
/// @dev Whenever a contract function or Noir test is run, the `aztec_utl_assertCompatibleOracleVersion` oracle is
66
/// called
77
/// and if the oracle version is incompatible an error is thrown.
8-
pub global ORACLE_VERSION: Field = 13;
8+
pub global ORACLE_VERSION: Field = 14;
99

1010
/// Asserts that the version of the oracle is compatible with the version expected by the contract.
1111
pub fn assert_compatible_oracle_version() {

noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ where
143143
self.compute_initialization_nullifier(secret)
144144
}
145145

146-
/// Returns whether this PrivateImmutable has been initialized.
146+
/// Returns `true` if this PrivateImmutable has been initialized.
147147
pub unconstrained fn is_initialized(self) -> bool {
148148
let nullifier = self.get_initialization_nullifier();
149149
check_nullifier_exists(nullifier)

noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ impl<T> PublicImmutable<T, PublicContext> {
214214
WithHash::public_storage_read(self.context, self.storage_slot)
215215
}
216216

217-
/// Returns true if the `PublicImmutable` has been initialized.
217+
/// Returns `true` if the `PublicImmutable` has been initialized.
218218
///
219219
/// ## Examples:
220220
///
@@ -263,7 +263,7 @@ impl<T> PublicImmutable<T, UtilityContext> {
263263
WithHash::utility_public_storage_read(self.context, self.storage_slot)
264264
}
265265

266-
/// Returns true if the `PublicImmutable` has been initialized.
266+
/// Returns `true` if the `PublicImmutable` has been initialized.
267267
pub unconstrained fn is_initialized(self) -> bool {
268268
let nullifier = self.compute_initialization_inner_nullifier();
269269
check_nullifier_exists(nullifier)

noir-projects/aztec-nr/aztec/src/state_vars/single_private_immutable.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ where
158158
self.compute_initialization_nullifier(secret)
159159
}
160160

161-
/// Returns whether this SinglePrivateImmutable has been initialized.
161+
/// Returns `true` if this SinglePrivateImmutable has been initialized.
162162
pub unconstrained fn is_initialized(self) -> bool {
163163
let nullifier = self.get_initialization_nullifier();
164164
check_nullifier_exists(nullifier)

noir-projects/aztec-nr/aztec/src/state_vars/single_private_mutable.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ where
249249
self.compute_initialization_nullifier(secret)
250250
}
251251

252-
/// Returns whether this SinglePrivateImmutable has been initialized.
252+
/// Returns `true` if this SinglePrivateMutable has been initialized.
253253
pub unconstrained fn is_initialized(self) -> bool {
254254
let nullifier = self.get_initialization_nullifier();
255255
check_nullifier_exists(nullifier)

noir-projects/aztec-nr/aztec/src/state_vars/single_use_claim.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ impl SingleUseClaim<&mut PrivateContext> {
132132
}
133133

134134
impl SingleUseClaim<UtilityContext> {
135-
/// Returns whether an owner has claimed this single use claim.
135+
/// Returns `true` if an owner has claimed this single use claim.
136136
pub unconstrained fn has_claimed(self) -> bool {
137137
let owner_nhk_app = get_nhk_app(get_public_keys(self.owner).npk_m.hash());
138138
check_nullifier_exists(self.compute_nullifier(owner_nhk_app))

noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,17 @@ impl Counter {
7676
/// }
7777
/// ```
7878
pub struct TestEnvironment {
79-
// The secrets to be used for light and contract account creation, as well as contract deployments. By keeping
80-
// track of the last used secret we can issue new ones automatically without requiring the user to provide
79+
// The secrets and salt to be used for light and contract account creation, as well as contract deployments. By
80+
// keeping track of the last used secret we can issue new ones automatically without requiring the user to provide
8181
// different ones.
8282
//
83-
// Additionally, having the secrets be deterministic for each set of accounts and all concurrent tests results in
84-
// TXE being able to maximize cache usage and not have to recompute account addresses and contract artifacts, which
85-
// are relatively expensive operations.
83+
// Additionally, having the secrets and salt be deterministic for each set of accounts and all concurrent tests
84+
// results in TXE being able to maximize cache usage and not have to recompute account addresses and contract
85+
// artifacts, which are relatively expensive operations.
8686
light_account_secret: Counter,
8787
contract_account_secret: Counter,
8888
contract_deployment_secret: Counter,
89+
contract_deployment_salt: Counter,
8990
}
9091

9192
/// Configuration values for [`TestEnvironment::private_context_opts`]. Meant to be used by calling `new` and then
@@ -138,6 +139,38 @@ struct EventDiscoveryOptions {
138139
contract_address: Option<AztecAddress>,
139140
}
140141

142+
/// Configuration values for [`TestEnvironment::deploy_opts`]. Meant to be used by calling `new` and then chaining
143+
/// methods setting each value, e.g.:
144+
/// ```noir
145+
/// env.deploy_opts(DeployOptions::new().with_salt(42).with_secret(100), "MyContract").without_initializer();
146+
/// ```
147+
pub struct DeployOptions {
148+
salt: Option<Field>,
149+
secret: Option<Field>,
150+
}
151+
152+
impl DeployOptions {
153+
/// Creates a new `DeployOptions` with default values, i.e. the same as if using the `deploy` method instead of
154+
/// `deploy_opts`. Use the `with_salt` and `with_secret` methods to set the desired configuration values.
155+
pub fn new() -> Self {
156+
Self { salt: Option::none(), secret: Option::none() }
157+
}
158+
159+
/// Sets the deployment salt. The salt affects the resulting contract address: the same contract deployed with
160+
/// different salts will have different addresses.
161+
pub fn with_salt(&mut self, salt: Field) -> Self {
162+
self.salt = Option::some(salt);
163+
*self
164+
}
165+
166+
/// Sets the secret used for key derivation. The secret affects the contract's public keys and therefore its
167+
/// address: the same contract deployed with different secrets will have different addresses.
168+
pub fn with_secret(&mut self, secret: Field) -> Self {
169+
self.secret = Option::some(secret);
170+
*self
171+
}
172+
}
173+
141174
impl TestEnvironment {
142175
/// Creates a new `TestEnvironment`. This function should only be called once per test.
143176
pub unconstrained fn new() -> Self {
@@ -150,6 +183,9 @@ impl TestEnvironment {
150183
light_account_secret: Counter::new(),
151184
contract_account_secret: Counter::new_with_offset(1_000),
152185
contract_deployment_secret: Counter::new_with_offset(2_000),
186+
// The salt counter does not need an offset because keys (derived from secret) and salt are unrelated: a
187+
// collision between a salt and a secret value has no effect on the resulting contract address.
188+
contract_deployment_salt: Counter::new(),
153189
}
154190
}
155191

@@ -477,7 +513,19 @@ impl TestEnvironment {
477513
/// );
478514
/// ```
479515
pub unconstrained fn deploy<let N: u32>(&mut self, path: str<N>) -> ContractDeployment<N> {
480-
ContractDeployment { env: *self, path, secret: self.contract_deployment_secret.next() }
516+
self.deploy_opts(DeployOptions::new(), path)
517+
}
518+
519+
/// Variant of `deploy` which allows specifying configuration values via `DeployOptions`, such as a custom salt
520+
/// or secret. If not specified, the salt and secret default to values from internal counters.
521+
pub unconstrained fn deploy_opts<let N: u32>(
522+
&mut self,
523+
opts: DeployOptions,
524+
path: str<N>,
525+
) -> ContractDeployment<N> {
526+
let secret = opts.secret.unwrap_or_else(|| self.contract_deployment_secret.next());
527+
let salt = opts.salt.unwrap_or_else(|| self.contract_deployment_salt.next());
528+
ContractDeployment { env: *self, path, secret, salt }
481529
}
482530

483531
/// Performs a private contract function call, including the processing of any nested private calls and enqueued

noir-projects/aztec-nr/aztec/src/test/helpers/test_environment/test/deployment.nr

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::test::helpers::test_environment::TestEnvironment;
1+
use crate::test::helpers::test_environment::{DeployOptions, TestEnvironment};
22

33
#[test]
44
unconstrained fn deploy_does_not_repeat_addresses() {
@@ -15,3 +15,43 @@ unconstrained fn deploy_does_not_repeat_addresses() {
1515
// This at least does test that the basics of the deployment mechanism work.
1616
assert(first_contract != second_contract);
1717
}
18+
19+
#[test(should_fail_with = "NullifierTree")]
20+
unconstrained fn deploy_with_same_salt_and_secret_fails() {
21+
let mut env = TestEnvironment::new();
22+
23+
let opts = DeployOptions::new().with_salt(42).with_secret(100);
24+
25+
let _ = env.deploy_opts(opts, "../noir-contracts/@test_contract/Test").without_initializer();
26+
// This will result in the exact same address preimage and hence same address, and so the initialization
27+
// nullifiers will be duplicated.
28+
let _ = env.deploy_opts(opts, "../noir-contracts/@test_contract/Test").without_initializer();
29+
}
30+
31+
#[test]
32+
unconstrained fn deploy_with_same_salt_does_not_repeat_addresses() {
33+
let mut env = TestEnvironment::new();
34+
35+
let first_contract = env
36+
.deploy_opts(DeployOptions::new().with_salt(42).with_secret(100), "../noir-contracts/@test_contract/Test")
37+
.without_initializer();
38+
let second_contract = env
39+
.deploy_opts(DeployOptions::new().with_salt(42).with_secret(200), "../noir-contracts/@test_contract/Test")
40+
.without_initializer();
41+
42+
assert(first_contract != second_contract);
43+
}
44+
45+
#[test]
46+
unconstrained fn deploy_with_same_secret_does_not_repeat_addresses() {
47+
let mut env = TestEnvironment::new();
48+
49+
let first_contract = env
50+
.deploy_opts(DeployOptions::new().with_salt(42).with_secret(100), "../noir-contracts/@test_contract/Test")
51+
.without_initializer();
52+
let second_contract = env
53+
.deploy_opts(DeployOptions::new().with_salt(43).with_secret(100), "../noir-contracts/@test_contract/Test")
54+
.without_initializer();
55+
56+
assert(first_contract != second_contract);
57+
}

0 commit comments

Comments
 (0)