11use protocol_types:: {
22 abis::function_selector::FunctionSelector ,
33 address::AztecAddress ,
4- traits ::{Deserialize , Packable },
4+ traits ::{Deserialize , Packable , Serialize },
55};
66
77use crate:: {
88 context ::{
99 PrivateCall , PrivateContext , PrivateStaticCall , PublicCall , PublicContext , PublicStaticCall ,
1010 UtilityCall , UtilityContext ,
1111 },
12+ event ::{event_interface::EventInterface , event_message::EventMessage },
1213 hash:: hash_args ,
1314 messages ::{
1415 discovery ::{
1516 ComputeNoteHashAndNullifier , NoteHashAndNullifier ,
1617 process_message:: process_message_plaintext ,
1718 },
18- logs::note:: private_note_to_message_plaintext ,
19+ encoding::MESSAGE_PLAINTEXT_LEN ,
20+ logs ::{event:: private_event_to_message_plaintext , note:: private_note_to_message_plaintext },
1921 processing ::{message_context::MessageContext , validate_enqueued_notes_and_events },
2022 },
2123 note ::{
@@ -128,6 +130,10 @@ struct NoteDiscoveryOptions {
128130 contract_address : Option <AztecAddress >,
129131}
130132
133+ struct EventDiscoveryOptions {
134+ contract_address : Option <AztecAddress >,
135+ }
136+
131137impl TestEnvironment {
132138 /// Creates a new `TestEnvironment`. This function should only be called once per test.
133139 pub unconstrained fn new () -> Self {
@@ -139,6 +145,12 @@ impl TestEnvironment {
139145 }
140146 }
141147
148+ /// Returns the default address used by [TestEnvironment::private_context] and other functions that do not take a
149+ /// contract address.
150+ pub (crate ) unconstrained fn get_default_address () -> AztecAddress {
151+ txe_oracles:: get_default_address ()
152+ }
153+
142154 /// Creates a `PublicContext`, which allows using aztec-nr features as if inside a public contract function. Useful
143155 /// for low-level testing of public state variables and utilities.
144156 ///
@@ -667,13 +679,13 @@ impl TestEnvironment {
667679 T ::deserialize (serialized_return_values )
668680 }
669681
670- /// Discovers a note from a [NewNoteMessage ], which is expected to have been created in the last transaction
671- /// (typically via ` private_context()`) so that it can be retrieved in later transactions. This mimics the normal
672- /// note discovery process that takes place automatically in contracts.
682+ /// Discovers a note from a [NoteMessage ], which is expected to have been created in the last transaction
683+ /// (typically via [TestEnvironment:: private_context]) so that it can be retrieved in later transactions. This
684+ /// mimics the normal message processing that takes place automatically in contracts.
673685 ///
674- /// [NewNoteMessage ] values are typically returned by aztec-nr state variables that create notes and need to notify
686+ /// [NoteMessage ] values are typically returned by aztec-nr state variables that create notes and need to notify
675687 /// a recipient of their existence. Instead of going through the message encoding, encryption and delivery that
676- /// would regularly take place in a contract, this function simply takes the [NewNoteMessage ] and processes it as
688+ /// would regularly take place in a contract, this function simply takes the [NoteMessage ] and processes it as
677689 /// needed to discover the underlying note.
678690 ///
679691 /// See [TestEnvironment::discover_note_at] for a variant that allows specifying the contract address the note
@@ -682,7 +694,7 @@ impl TestEnvironment {
682694 /// ### Sample usage
683695 ///
684696 /// The most common way to invoke this function is to obtain a note message created during the execution of a
685- /// ` private_context` :
697+ /// [TestEnvironment:: private_context] :
686698 ///
687699 /// ```noir
688700 /// let note_message = env.private_context(|context| create_note(context, storage_slot, note));
@@ -701,8 +713,9 @@ impl TestEnvironment {
701713 );
702714 }
703715
704- /// Variant of `discover_note` which allows specifying the contract address the note belongs to, which is required
705- /// when the note was not emitted in the default address used by `private_context`.
716+ /// Variant of [TestEnvironment::discover_note] which allows specifying the contract address the note belongs to,
717+ /// which is required when the note was not emitted in the default address used by
718+ /// [TestEnvironment::private_context].
706719 ///
707720 /// ```noir
708721 /// let note_message = env.private_context_at(contract_address, |context| {
@@ -740,7 +753,7 @@ impl TestEnvironment {
740753 // This function will emulate the message discovery and processing that would happen in a real contract, based
741754 // on a message created from the received note message.
742755
743- // First we produce the message itself . We skip encryption/decryption since we're not interested in that here.
756+ // First we produce the message plaintext . We skip encryption/decryption since we're not interested in that here.
744757 // Note that we need to convert the fixed-size array produced by the encoding functions into a BoundedVec, which
745758 // is what the decoding functions expect (because they are built to manage protocol logs, which are arbitrarily
746759 // sized).
@@ -751,24 +764,6 @@ impl TestEnvironment {
751764 note_message .new_note .randomness ,
752765 ));
753766
754- // Then we fetch the transaction effects from the latest transaction, in which the note from the message is
755- // expected to have been created. In a real contract this data would have either been supplied by the
756- // `process_message` caller, of retrieved along with the message from a tagged log.
757- let (tx_hash , unique_note_hashes_in_tx , nullifiers_in_tx ) =
758- txe_oracles:: get_last_tx_effects ();
759-
760- // Real messages would also have a recipient, a concept which does not translate to anything in
761- // `TestEnvironment` since it works with a single PXE with global scopes. We therefore simply set the zero
762- // address as the recipient, which PXE accepts as a note scope despite this not being a registered account.
763- let recipient = AztecAddress ::zero ();
764-
765- let message_context = MessageContext {
766- tx_hash ,
767- unique_note_hashes_in_tx ,
768- first_nullifier_in_tx : nullifiers_in_tx .get (0 ),
769- recipient ,
770- };
771-
772767 // We also need to provide an implementation for the `compute_note_hash_and_nullifier` function, which would
773768 // typically be created by the macros for the different notes in a given contract. Here we build one specialized
774769 // for `Note`.
@@ -796,21 +791,163 @@ impl TestEnvironment {
796791 Option ::some (NoteHashAndNullifier { note_hash , inner_nullifier })
797792 };
798793
799- // Both private and utility functions perform message processing and note discovery. We do it in an utility
800- // context here as that one is more lightweight and does not create new blocks, which also allows for
801- // `discover_notes` to be called repeatedly with multiple messages from the same transaction.
802- self .utility_context_opts (
803- UtilityContextOptions { contract_address : opts .contract_address },
804- |context | {
805- process_message_plaintext (
806- context .this_address (),
807- compute_note_hash_and_nullifier ,
808- message_plaintext ,
809- message_context ,
810- );
811-
812- validate_enqueued_notes_and_events (context .this_address ());
813- },
794+ self .discover_data_in_message_plaintext (
795+ message_plaintext ,
796+ opts .contract_address ,
797+ Option ::none (),
798+ compute_note_hash_and_nullifier ,
799+ );
800+ }
801+
802+ /// EXPERIMENTAL - not yet part of the public API
803+ ///
804+ /// Discovers an event from an [EventMessage], which is expected to have been created in the last transaction
805+ /// (typically via [TestEnvironment::private_context]) so that it can be retrieved in queries. This mimics the
806+ /// normal message processing that takes place automatically in contracts.
807+ ///
808+ /// [EventMessage] values are returned by aztec-nr private event emitting functions, like
809+ /// [crate::contract_self::ContractSelf::emit], which need to notify a `recipient` of their existence. Instead of
810+ /// going through the message encoding, encryption and delivery that would regularly take place in a contract, this
811+ /// function simply takes the [EventMessage] and processes it as needed to discover the underlying event.
812+ ///
813+ /// As this mimics regular event processing, only `recipient` will have knowledge of the event: other accounts will
814+ /// not be able to read it.
815+ ///
816+ /// See [TestEnvironment::discover_event_at] for a variant that allows specifying the contract address the event
817+ /// belongs to.
818+ ///
819+ /// ### Sample usage
820+ ///
821+ /// The most common way to invoke this function is to obtain a note message created during the execution of a
822+ /// [TestEnvironment::private_context]:
823+ ///
824+ /// ```noir
825+ /// let event_message = env.private_context(|context| emit_event_in_private(context, event));
826+ ///
827+ /// env.discover_event(event_message, recipient);
828+ /// ```
829+ pub (crate ) unconstrained fn discover_event <Event >(
830+ self : Self ,
831+ event_message : EventMessage <Event >,
832+ recipient : AztecAddress ,
833+ )
834+ where
835+ Event : Serialize + EventInterface ,
836+ {
837+ self .discover_event_opts (
838+ EventDiscoveryOptions { contract_address : Option ::none () },
839+ event_message ,
840+ recipient ,
841+ );
842+ }
843+
844+ /// EXPERIMENTAL - not yet part of the public API
845+ ///
846+ /// Variant of [TestEnvironment::discover_event] which allows specifying the contract address the event belongs to,
847+ /// which is required when the event was not emitted in the default address used by
848+ /// [TestEnvironment::private_context].
849+ ///
850+ /// ```noir
851+ /// let event_message = env.private_context_at(contract_address, |context| {
852+ /// emit_event_in_private(context, event)
853+ /// });
854+ ///
855+ /// env.discover_event_at(contract_address, event_message);
856+ /// ```
857+ pub (crate ) unconstrained fn discover_event_at <Event >(
858+ self : Self ,
859+ addr : AztecAddress ,
860+ event_message : EventMessage <Event >,
861+ recipient : AztecAddress ,
862+ )
863+ where
864+ Event : Serialize + EventInterface ,
865+ {
866+ self .discover_event_opts (
867+ EventDiscoveryOptions { contract_address : Option ::some (addr ) },
868+ event_message ,
869+ recipient ,
814870 );
815871 }
872+
873+ unconstrained fn discover_event_opts <Event >(
874+ self : Self ,
875+ opts : EventDiscoveryOptions ,
876+ event_message : EventMessage <Event >,
877+ recipient : AztecAddress ,
878+ )
879+ where
880+ Event : Serialize + EventInterface ,
881+ {
882+ // This function will emulate the message discovery and processing that would happen in a real contract, based
883+ // on a message created from the received event message.
884+
885+ // First we produce the message plaintext. We skip encryption/decryption since we're not interested in that here.
886+ // Note that we need to convert the fixed-size array produced by the encoding functions into a BoundedVec, which
887+ // is what the decoding functions expect (because they are built to manage protocol logs, which are arbitrarily
888+ // sized).
889+ let message_plaintext = BoundedVec ::from_array (private_event_to_message_plaintext (
890+ event_message .new_event .event ,
891+ event_message .new_event .randomness ,
892+ ));
893+
894+ // We also need to provide an implementation for the `compute_note_hash_and_nullifier` function, which would
895+ // typically be created by the macros for the different notes in a given contract. Here we build an empty one,
896+ // since it will never be invoked as this is an event and not a note message.
897+ let compute_note_hash_and_nullifier : ComputeNoteHashAndNullifier <_ > = |_packed_note , _owner , _storage_slot , _note_type_id , _contract_address , _randomness , _note_nonce | {
898+ panic (
899+ f"Unexpected compute_note_hash_and_nullifier invocation in TestEnvironment::discover_event" ,
900+ )
901+ };
902+
903+ self .discover_data_in_message_plaintext (
904+ message_plaintext ,
905+ opts .contract_address ,
906+ Option ::some (recipient ),
907+ compute_note_hash_and_nullifier ,
908+ );
909+ }
910+
911+ unconstrained fn discover_data_in_message_plaintext <Env >(
912+ self ,
913+ message_plaintext : BoundedVec <Field , MESSAGE_PLAINTEXT_LEN >,
914+ contract_address : Option <AztecAddress >,
915+ recipient : Option <AztecAddress >,
916+ compute_note_hash_and_nullifier : ComputeNoteHashAndNullifier <Env >,
917+ ) {
918+ // This function will emulate the message discovery and processing that would happen in a real contract, based
919+ // on a message plaintext.
920+
921+ // First we fetch the transaction effects from the latest transaction, which are required to create the
922+ // `MessageContext`, and might contain information about data (e.g. notes, events) contained in the message. In
923+ // a real contract this data would have either been supplied by the `process_message` caller, of retrieved
924+ // along with the message from a tagged log.
925+ let (tx_hash , unique_note_hashes_in_tx , nullifiers_in_tx ) =
926+ txe_oracles:: get_last_tx_effects ();
927+
928+ // Real messages would also have a recipient, a concept which is currently half-supported in `TestEnvironment`
929+ // as events are properly scoped by recipient, but notes use a global scope instead. We therefore simply set the
930+ // zero address as the recipient if one is not supplied, which PXE accepts as a scope despite this not being a
931+ // registered account.
932+ let message_context = MessageContext {
933+ tx_hash ,
934+ unique_note_hashes_in_tx ,
935+ first_nullifier_in_tx : nullifiers_in_tx .get (0 ),
936+ recipient : recipient .unwrap_or (AztecAddress ::zero ()),
937+ };
938+
939+ // Both private and utility functions perform message processing . We do it in an utility context here as that
940+ // one is more lightweight and does not create new blocks, which also allows for `discover_note` and
941+ // `discover_event` to be called repeatedly with multiple messages from the same transaction.
942+ self .utility_context_opts (UtilityContextOptions { contract_address }, |context | {
943+ process_message_plaintext (
944+ context .this_address (),
945+ compute_note_hash_and_nullifier ,
946+ message_plaintext ,
947+ message_context ,
948+ );
949+
950+ validate_enqueued_notes_and_events (context .this_address ());
951+ });
952+ }
816953}
0 commit comments