Skip to content

feat!: re-do partial notes#12391

Merged
nventuro merged 25 commits intomasterfrom
nv/redo-partial
Mar 12, 2025
Merged

feat!: re-do partial notes#12391
nventuro merged 25 commits intomasterfrom
nv/redo-partial

Conversation

@nventuro
Copy link
Contributor

Closes #9375.

This re-implements partial notes leveraging the work from #12122. We now emit a private log with all of the fields plus a 'public log completion tag', which is the tag of the public log that will contain the public fields. These two logs are merged when doing discovery, resulting in the note's packed representation.

All in all this means we need to store much less information in public storage (just one field), and we don't need to deal with publishing public logs with encrypted public content. It also removes a lot of PXE code that dealt with the destructuring of these logs, slicing off the public fields, etc. Once this is merged, moving decryption to NR should be trivial.

I iterated a bit on how the note structs are laid out and thing the current version is a reasonably good starting point. Eventually we'll autogenerate it via macros, but given we may want to introduce further changes I chose to not worry about that for now.

We're currently sort of hackily relying on the fact that note type ids are 7 bits long, and set the 8th bit to indicate the log is that of a partial note. Fixing this requires properly supporting events during log discovery (which would become message discovery), but that's out of scope for this PR.

@@ -1,25 +1,320 @@
use aztec::{macros::notes::partial_note, oracle::random::random, prelude::AztecAddress};
use dep::aztec::{
Copy link
Contributor Author

@nventuro nventuro Feb 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is a copy-paste of uint_note.nr except using field instead of u128. Read that one instead.

Comment on lines +150 to +157
let encrypted_log = default_aes128::note::compute_log(
*context,
private_log_content,
storage_slot,
recipient,
sender,
);
context.emit_private_log(encrypted_log);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way of not-choosing to use default_aes128 encryption strategy here?
can the fn partial have as input an encryption method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of today, encryption is hardcoded in PXE to be AES. We'll soon move it into aztec-nr, at which point it'd be possible to somehow configure which encryption algorithm the contracts wishes to use. But this is just a first step, so it'll take a while to get there. Keep in mind this is the very first attempt to do this this alternative way. We'd similarly want to allow for unconstrained encryption etc.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file imports encrypted_logs::log_assembly_strategies::default_aes128::note::encode_and_encrypt_note but could be using other encryption strategy, are both partial notes and full notes processed independently? (could they work with different setups?)

Copy link
Contributor

@benesjan benesjan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cute! LGTM

NFT::at(context.this_address())._store_nft_set_partial_note(partial_note).enqueue(context);

partial_note
}
Copy link
Contributor

@benesjan benesjan Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fanstastic how concise ^ this has become.

@benesjan benesjan force-pushed the nv/redo-partial branch 2 times, most recently from c6fc6cb to 106ce57 Compare March 3, 2025 15:40
Copy link
Contributor

benesjan commented Mar 3, 2025

@benesjan benesjan force-pushed the nv/redo-partial branch 3 times, most recently from 2a9675f to 35e25d2 Compare March 3, 2025 17:42
@benesjan benesjan marked this pull request as draft March 3, 2025 19:16
@benesjan benesjan marked this pull request as ready for review March 4, 2025 22:21
@nventuro
Copy link
Contributor Author

nventuro commented Mar 6, 2025

CI should pass once #12552 is merged.

nventuro added a commit that referenced this pull request Mar 7, 2025
Back when PXE was a service processing all blocks, we'd remove nullified
notes as we saw their nullifiers. This later got changed, and as of
#10722 we remove all
nullified notes whenever we 'sync' notes. However, note syncing is
becoming less and less a part of PXE, and as of
#12391 we even
deliver notes _outside_ of the PXE-led note syncing process (whenever we
complete partial note). This causes problems because we end up adding
notes, failing to realize they've been nullified and then returning them
via `get_notes` (which is what causes some tests in
#12391 to fail). The
next time a contract function is run we'll do note syncing again and
they'll be then removed, but we did have a full fn call in which they
were available.

This PR makes it so we always check if newly-added notes have been
nullified, and remove them if so. I also added some explanations re. why
we're doing things this way, created some follow-up issues (mostly
#12550 and
#12553), and
inlined `produceNoteDaos` to have the whole thing happen in a single
place. I think it's now more readable but potentially slightly large -
perhaps this will improve as we split `PxeOracleInterface` in multiple
files or modules.
Comment on lines +200 to +206
let partial_note = NFTNote::partial(
to,
storage.private_nfts.at(to).storage_slot,
context,
to,
context.msg_sender(),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not for this PR): It'd be cool if this could be created via the state variable. Like private_nfts.at(to).new_partial(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! This is on the roadmap.


// We prepare the private balance increase (the partial note).
let hiding_point_slot = _prepare_private_balance_increase(from, to, &mut context, storage);
let partial_note = _prepare_private_balance_increase(from, to, &mut context, storage);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's technically a partial_note_commitment, given that the partial_note is actually a struct of information. (Sorry - I was referring to this PR for another reason, then saw this).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is ultimately an issue due to us not neatly following Rust's newtype idiom. PartialUintNote is a struct with a single value.

nventuro added a commit that referenced this pull request Mar 11, 2025
Debugging #12391 led
me to discover that we cannot have concurrent simulations due to
contracts now being allowed to read and write to PXE's stores at
arbitrary moments. E.g.
#12391 was failing
CI due to multiple concurrent simulations deleting the same pending
partial note from a capsule array.

This PR disables that behavior by putting the problematic tasks in a
serial queue. Multiple tests still call PXE expecting concurrency
(typically via usage of `await Promise.all`), but I thought it made more
sense to disable the behavior this way and issue a warning (to unblock
#12391) and then
worry about removing attempts to achieve concurrent behavior.

I considered putting _all_ PXE functions in the serial queue, but
refrained from doing so to avoid introducing a larger than strictly
needed change. We may want to do this automatically via e.g.
monkey-patching to avoid accidentally forgetting a case.
…liver notes to be implemented on the txe level (#12667)

Resolves #12668

Co-authored-by: sklppy88 <esau@aztecprotocol.com>
@nventuro nventuro merged commit 66f0e4d into master Mar 12, 2025
7 checks passed
@nventuro nventuro deleted the nv/redo-partial branch March 12, 2025 18:25
LHerskind added a commit that referenced this pull request Mar 13, 2025
Fixes an issue in the cheatcode test that were introduced by #12391 when it updated the ordering of fields in the `UintNote` but not the test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid the need for defining setup log length manually

5 participants