Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Aug 8, 2024
1 parent 5ff3554 commit d5bd380
Show file tree
Hide file tree
Showing 14 changed files with 53 additions and 105 deletions.
20 changes: 20 additions & 0 deletions noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ impl<Note, let N: u32, let M: u32> PrivateSet<Note, &mut PrivateContext> where N
get_notes(self.context, self.storage_slot, options)
}
// docs:end:get_notes

pub fn pop_notes<FILTER_ARGS>(
self,
options: NoteGetterOptions<Note, N, M, FILTER_ARGS>
) -> BoundedVec<Note, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL> {
let notes = get_notes(self.context, self.storage_slot, options);
// We iterate in a range 0..options.limit instead of 0..notes.len() because options.limit is known at compile
// time and hence will result in less constraints when set to a lower value than
// MAX_NOTE_HASH_READ_REQUESTS_PER_CALL.
for i in 0..options.limit {
if i < notes.len() {
let note = notes.get_unchecked(i);
// We immediately destroy the note without doing any read request checks because we know that
// get_notes(...) above has placed the constraints.
destroy_note(self.context, note);
}
}

notes
}
}

impl<Note, let N: u32, let M: u32> PrivateSet<Note, UnconstrainedContext> where Note: NoteInterface<N, M> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,14 @@ impl<Context> EasyPrivateUint<&mut PrivateContext> {

// docs:start:get_notes
let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend as Field);
let notes = self.set.get_notes(options);
let notes = self.set.pop_notes(options);
// docs:end:get_notes

let mut minuend: u64 = 0;
for i in 0..options.limit {
if i < notes.len() {
let note = notes.get_unchecked(i);

// Removes the note from the owner's set of notes.
// docs:start:remove
self.set.remove(note);
// docs:end:remove

minuend += note.value as u64;
}
}
Expand Down
13 changes: 2 additions & 11 deletions noir-projects/aztec-nr/value-note/src/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,13 @@ pub fn decrement_by_at_most(
outgoing_viewer: AztecAddress
) -> Field {
let options = create_note_getter_options_for_decreasing_balance(max_amount);
let notes = balance.get_notes(options);
let notes = balance.pop_notes(options);

let mut decremented = 0;
for i in 0..options.limit {
if i < notes.len() {
let note = notes.get_unchecked(i);

decremented += destroy_note(balance, note);
decremented += note.value;
}
}

Expand All @@ -76,11 +75,3 @@ pub fn decrement_by_at_most(

decremented
}

// Removes the note from the owner's set of notes.
// Returns the value of the destroyed note.
pub fn destroy_note(balance: PrivateSet<ValueNote, &mut PrivateContext>, note: ValueNote) -> Field {
balance.remove(note);

note.value
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract Benchmarking {
increment(storage.notes.at(owner), value, owner, outgoing_viewer);
// docs:end:increment_valuenote
}
// Deletes a note at a specific index in the set and creates a new one with the same value.
// Pops a note at a specific index in the set and creates a new one with the same value.
// We explicitly pass in the note index so we can ensure we consume different notes when sending
// multiple txs that will land on the same block.
// See https://discourse.aztec.network/t/utxo-concurrency-issues-for-private-state/635
Expand All @@ -31,9 +31,8 @@ contract Benchmarking {
fn recreate_note(owner: AztecAddress, outgoing_viewer: AztecAddress, index: u32) {
let owner_notes = storage.notes.at(owner);
let mut getter_options = NoteGetterOptions::new();
let notes = owner_notes.get_notes(getter_options.set_limit(1).set_offset(index));
let note = notes.get(0);
owner_notes.remove(note);
let notes = owner_notes.pop_notes(getter_options.set_limit(1).set_offset(index));
let note = notes.get_unchecked(0);
increment(owner_notes, note.value, owner, outgoing_viewer);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ impl Deck<&mut PrivateContext> {
inserted_cards
}

pub fn get_cards<N>(&mut self, cards: [Card; N]) -> [CardNote; N] {
pub fn remove_cards<N>(&mut self, cards: [Card; N]) {
let options = NoteGetterOptions::with_filter(filter_cards, cards);
let notes = self.set.get_notes(options);
let notes = self.set.pop_notes(options);

// This array will hold the notes that correspond to each of the requested cards. It begins empty (with all the
// options being none) and we gradually fill it up as we find the matching notes.
Expand All @@ -149,14 +149,7 @@ impl Deck<&mut PrivateContext> {
assert(card_note.is_some(), "Card not found");
card_note.unwrap_unchecked()
}
)
}

pub fn remove_cards<N>(&mut self, cards: [Card; N]) {
let card_notes = self.get_cards(cards);
for card_note in card_notes {
self.set.remove(card_note.note);
}
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,7 @@ contract InclusionProofs {
let private_values = storage.private_values.at(owner);
let mut options = NoteGetterOptions::new();
options = options.set_limit(1);
let notes = private_values.get_notes(options);
let note = notes.get(0);

private_values.remove(note);
private_values.pop_notes(options);
}
// docs:end:nullify_note

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,12 @@ contract PendingNoteHashes {

let options = NoteGetterOptions::with_filter(filter_notes_min_sum, amount);
// get note inserted above
let notes = owner_balance.get_notes(options);
let notes = owner_balance.pop_notes(options);

let note0 = notes.get(0);
assert(note.value == note0.value);
assert(notes.len() == 1);

owner_balance.remove(note0);

note0.value
}

Expand Down Expand Up @@ -137,12 +135,9 @@ contract PendingNoteHashes {

let mut options = NoteGetterOptions::new();
options = options.set_limit(1);
let note = owner_balance.get_notes(options).get(0);
let note = owner_balance.pop_notes(options).get(0);

assert(expected_value == note.value);

owner_balance.remove(note);

expected_value
}

Expand Down Expand Up @@ -378,12 +373,7 @@ contract PendingNoteHashes {
#[contract_library_method]
fn destroy_max_notes(owner: AztecAddress, storage: Storage<&mut PrivateContext>) {
let owner_balance = storage.balances.at(owner);
let notes = owner_balance.get_notes(NoteGetterOptions::new());

for i in 0..max_notes_per_call() {
let note = notes.get(i);
owner_balance.remove(note);
}
owner_balance.pop_notes(NoteGetterOptions::new());
}

#[contract_library_method]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,7 @@ contract Test {
let secret_hash = compute_secret_hash(secret);
let mut options = NoteGetterOptions::new();
options = options.select(TestNote::properties().value, secret_hash, Option::none()).set_limit(1);
let notes = notes_set.get_notes(options);
let note = notes.get(0);
notes_set.remove(note);
notes_set.pop_notes(options);
}

unconstrained fn get_constant() -> pub Field {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,20 +162,18 @@ contract TokenBlacklist {
let to_roles = storage.roles.at(to).get_current_value_in_private();
assert(!to_roles.is_blacklisted, "Blacklisted: Recipient");

let pending_shields = storage.pending_shields;
let secret_hash = compute_secret_hash(secret);
// Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash
// stored in field with index 1 (select(1, secret_hash)).

// Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and
// a secret_hash stored in a field with index 1 (select(1, secret_hash)).
let mut options = NoteGetterOptions::new();
options = options.select(TransparentNote::properties().amount, amount, Option::none()).select(
TransparentNote::properties().secret_hash,
secret_hash,
Option::none()
).set_limit(1);
let notes = pending_shields.get_notes(options);
let note = notes.get(0);
// Remove the note from the pending shields set
pending_shields.remove(note);

storage.pending_shields.pop_notes(options);

// Add the token note to user's balances set
let caller = context.msg_sender();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,24 +81,13 @@ impl<T> BalancesMap<T, &mut PrivateContext> {
owner: AztecAddress,
subtrahend: U128
) -> OuterNoteEmission<T> where T: NoteInterface<T_SERIALIZED_LEN, T_SERIALIZED_BYTES_LEN> + OwnedNote + Eq {
// docs:start:get_notes
let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend);
let notes = self.map.at(owner).get_notes(options);
// docs:end:get_notes
let notes = self.map.at(owner).pop_notes(options);

let mut minuend: U128 = U128::from_integer(0);
for i in 0..options.limit {
if i < notes.len() {
let note = notes.get_unchecked(i);

// Removes the note from the owner's set of notes.
// This will call the `compute_nullifer` function of the `token_note`
// which require knowledge of the secret key (currently the users encryption key).
// The contract logic must ensure that the spending key is used as well.
// docs:start:remove
self.map.at(owner).remove(note);
// docs:end:remove

let note: T = notes.get_unchecked(i);
minuend = minuend + note.get_amount();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,20 +293,18 @@ contract Token {
// docs:start:redeem_shield
#[aztec(private)]
fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) {
let pending_shields = storage.pending_shields;
let secret_hash = compute_secret_hash(secret);
// Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash
// stored in field with index 1 (select(1, secret_hash)).

// Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and
// a secret_hash stored in a field with index 1 (select(1, secret_hash)).
let mut options = NoteGetterOptions::new();
options = options.select(TransparentNote::properties().amount, amount, Option::none()).select(
TransparentNote::properties().secret_hash,
secret_hash,
Option::none()
).set_limit(1);
let notes = pending_shields.get_notes(options);
let note = notes.get(0);
// Remove the note from the pending shields set
pending_shields.remove(note);

storage.pending_shields.pop_notes(options);

// Add the token note to user's balances set
// Note: Using context.msg_sender() as a sender below makes this incompatible with escrows because we send
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,22 +109,13 @@ impl<T> BalancesMap<T, &mut PrivateContext> {
) -> U128 where T: NoteInterface<T_SERIALIZED_LEN, T_SERIALIZED_BYTES_LEN> + OwnedNote + Eq {
// docs:start:get_notes
let options = NoteGetterOptions::with_filter(filter_notes_min_sum, target_amount).set_limit(max_notes);
let notes = self.map.at(owner).get_notes(options);
let notes = self.map.at(owner).pop_notes(options);
// docs:end:get_notes

let mut subtracted = U128::from_integer(0);
for i in 0..options.limit {
if i < notes.len() {
let note = notes.get_unchecked(i);

// Removes the note from the owner's set of notes.
// This will call the `compute_nullifer` function of the `token_note`
// which require knowledge of the secret key (currently the users encryption key).
// The contract logic must ensure that the spending key is used as well.
// docs:start:remove
self.map.at(owner).remove(note);
// docs:end:remove

subtracted = subtracted + note.get_amount();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,20 +280,18 @@ contract TokenWithRefunds {
// docs:start:redeem_shield
#[aztec(private)]
fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) {
let pending_shields = storage.pending_shields;
let secret_hash = compute_secret_hash(secret);
// Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash
// stored in field with index 1 (select(1, secret_hash)).

// Pop 1 note (set_limit(1)) which has an amount stored in a field with index 0 (select(0, amount)) and
// a secret_hash stored in a field with index 1 (select(1, secret_hash)).
let mut options = NoteGetterOptions::new();
options = options.select(TransparentNote::properties().amount, amount, Option::none()).select(
TransparentNote::properties().secret_hash,
secret_hash,
Option::none()
).set_limit(1);
let notes = pending_shields.get_notes(options);
let note = notes.get_unchecked(0);
// Remove the note from the pending shields set
pending_shields.remove(note);

storage.pending_shields.pop_notes(options);

// Add the token note to user's balances set
// Note: Using context.msg_sender() as a sender below makes this incompatible with escrows because we send
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,13 @@ impl<T> BalancesMap<T, &mut PrivateContext> {
) -> OuterNoteEmission<T> where T: NoteInterface<T_SERIALIZED_LEN, T_SERIALIZED_BYTES_LEN> + OwnedNote + Eq {
// docs:start:get_notes
let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend);
let notes = self.map.at(owner).get_notes(options);
let notes = self.map.at(owner).pop_notes(options);
// docs:end:get_notes

let mut minuend: U128 = U128::from_integer(0);
for i in 0..options.limit {
if i < notes.len() {
let note = notes.get_unchecked(i);

// Removes the note from the owner's set of notes.
// This will call the `compute_nullifer` function of the `token_note`
// which require knowledge of the secret key (currently the users encryption key).
// The contract logic must ensure that the spending key is used as well.
// docs:start:remove
self.map.at(owner).remove(note);
// docs:end:remove

minuend = minuend + note.get_amount();
}
}
Expand Down

0 comments on commit d5bd380

Please sign in to comment.