@@ -132,21 +132,22 @@ struct UtilityContextOptions {
132132/// ```noir
133133/// env.call_private_opts(from, CallPrivateOptions::new().with_additional_scopes([other]), call);
134134/// ```
135- pub struct CallPrivateOptions <let N : u32 > {
135+ pub struct CallPrivateOptions <let N : u32 , let T : u32 > {
136136 additional_scopes : [AztecAddress ; N ],
137+ authorized_utility_call_targets : [AztecAddress ; T ],
137138}
138139
139- impl CallPrivateOptions <0 > {
140+ impl CallPrivateOptions <0 , 0 > {
140141 /// Creates default `CallPrivateOptions`.
141142 ///
142143 /// The default values are the same as if using [`TestEnvironment::call_private`] instead of
143144 /// [`TestEnvironment::call_private_opts`].
144145 pub fn new () -> Self {
145- CallPrivateOptions { additional_scopes : [] }
146+ CallPrivateOptions { additional_scopes : [], authorized_utility_call_targets : [] }
146147 }
147148}
148149
149- impl <let N : u32 > CallPrivateOptions <N > {
150+ impl <let N : u32 , let T : u32 > CallPrivateOptions <N , T > {
150151 /// Grants access to secrets of additional accounts.
151152 ///
152153 /// By default only the secrets that belong to the `from` account can be accessed: this function lets contracts
@@ -155,10 +156,27 @@ impl<let N: u32> CallPrivateOptions<N> {
155156 /// Example usage includes accounts withdrawing from an escrow, which may require accessing the escrow's own notes
156157 /// and secrets.
157158 pub fn with_additional_scopes <let N_2 : u32 >(
158- _self : Self ,
159+ self ,
159160 additional_scopes : [AztecAddress ; N_2 ],
160- ) -> CallPrivateOptions <N_2 > {
161- CallPrivateOptions { additional_scopes }
161+ ) -> CallPrivateOptions <N_2 , T > {
162+ CallPrivateOptions {
163+ additional_scopes ,
164+ authorized_utility_call_targets : self .authorized_utility_call_targets ,
165+ }
166+ }
167+
168+ /// Authorizes cross-contract utility calls to the given target contracts during this call.
169+ ///
170+ /// By default, cross-contract utility calls are denied. This method lets the test author specify which target
171+ /// contracts are allowed to be called via utility functions during execution.
172+ pub fn with_authorized_utility_call_targets <let T_2 : u32 >(
173+ self ,
174+ targets : [AztecAddress ; T_2 ],
175+ ) -> CallPrivateOptions <N , T_2 > {
176+ CallPrivateOptions {
177+ additional_scopes : self .additional_scopes ,
178+ authorized_utility_call_targets : targets ,
179+ }
162180 }
163181}
164182
@@ -169,21 +187,22 @@ impl<let N: u32> CallPrivateOptions<N> {
169187/// ```noir
170188/// env.view_private_opts(from, ViewPrivateOptions::new().with_additional_scopes([other]), call);
171189/// ```
172- pub struct ViewPrivateOptions <let S : u32 > {
190+ pub struct ViewPrivateOptions <let S : u32 , let T : u32 > {
173191 additional_scopes : [AztecAddress ; S ],
192+ authorized_utility_call_targets : [AztecAddress ; T ],
174193}
175194
176- impl ViewPrivateOptions <0 > {
195+ impl ViewPrivateOptions <0 , 0 > {
177196 /// Creates default `ViewPrivateOptions`.
178197 ///
179198 /// The default values are the same as if using [`TestEnvironment::view_private`] instead of
180199 /// [`TestEnvironment::view_private_opts`].
181200 pub fn new () -> Self {
182- ViewPrivateOptions { additional_scopes : [] }
201+ ViewPrivateOptions { additional_scopes : [], authorized_utility_call_targets : [] }
183202 }
184203}
185204
186- impl <let S : u32 > ViewPrivateOptions <S > {
205+ impl <let S : u32 , let T : u32 > ViewPrivateOptions <S , T > {
187206 /// Grants access to secrets of additional accounts.
188207 ///
189208 /// By default only the secrets that belong to the `from` account can be accessed: this function lets contracts
@@ -192,10 +211,27 @@ impl<let S: u32> ViewPrivateOptions<S> {
192211 /// Example usage includes accounts querying an escrow's balance, which may require accessing the escrow's own
193212 /// notes.
194213 pub fn with_additional_scopes <let S2 : u32 >(
195- _self : Self ,
214+ self ,
196215 additional_scopes : [AztecAddress ; S2 ],
197- ) -> ViewPrivateOptions <S2 > {
198- ViewPrivateOptions { additional_scopes }
216+ ) -> ViewPrivateOptions <S2 , T > {
217+ ViewPrivateOptions {
218+ additional_scopes ,
219+ authorized_utility_call_targets : self .authorized_utility_call_targets ,
220+ }
221+ }
222+
223+ /// Authorizes cross-contract utility calls to the given target contracts during this call.
224+ ///
225+ /// By default, cross-contract utility calls are denied. This method lets the test author specify which target
226+ /// contracts are allowed to be called via utility functions during execution.
227+ pub fn with_authorized_utility_call_targets <let T_2 : u32 >(
228+ self ,
229+ targets : [AztecAddress ; T_2 ],
230+ ) -> ViewPrivateOptions <S , T_2 > {
231+ ViewPrivateOptions {
232+ additional_scopes : self .additional_scopes ,
233+ authorized_utility_call_targets : targets ,
234+ }
199235 }
200236}
201237
@@ -207,6 +243,40 @@ struct EventDiscoveryOptions {
207243 contract_address : Option <AztecAddress >,
208244}
209245
246+ /// Configuration for [`TestEnvironment::execute_utility_opts`].
247+ ///
248+ /// Constructed by calling [`ExecuteUtilityOptions::new`] and then chaining methods:
249+ ///
250+ /// ```noir
251+ /// env.execute_utility_opts(
252+ /// ExecuteUtilityOptions::new().with_authorized_utility_call_targets([target]),
253+ /// SomeContract::at(addr).some_utility_function(),
254+ /// );
255+ /// ```
256+ pub struct ExecuteUtilityOptions <let T : u32 > {
257+ authorized_utility_call_targets : [AztecAddress ; T ],
258+ }
259+
260+ impl ExecuteUtilityOptions <0 > {
261+ /// Creates default `ExecuteUtilityOptions`.
262+ pub fn new () -> Self {
263+ ExecuteUtilityOptions { authorized_utility_call_targets : [] }
264+ }
265+ }
266+
267+ impl <let T : u32 > ExecuteUtilityOptions <T > {
268+ /// Authorizes cross-contract utility calls to the given target contracts during this call.
269+ ///
270+ /// By default, cross-contract utility calls are denied. This method lets the test author specify which target
271+ /// contracts are allowed to be called via utility functions during execution.
272+ pub fn with_authorized_utility_call_targets <let T_2 : u32 >(
273+ _self : Self ,
274+ targets : [AztecAddress ; T_2 ],
275+ ) -> ExecuteUtilityOptions <T_2 > {
276+ ExecuteUtilityOptions { authorized_utility_call_targets : targets }
277+ }
278+ }
279+
210280/// Configuration values for [`TestEnvironment::deploy_opts`]. Meant to be used by calling `new` and then chaining
211281/// methods setting each value, e.g.:
212282/// ```noir
@@ -629,10 +699,10 @@ impl TestEnvironment {
629699 }
630700
631701 /// Variant of `call_private` which allows specifying multiple configuration values via `CallPrivateOptions`.
632- pub unconstrained fn call_private_opts <let M : u32 , let N : u32 , let S : u32 , T >(
702+ pub unconstrained fn call_private_opts <let M : u32 , let N : u32 , let S : u32 , let U : u32 , T >(
633703 _self : Self ,
634704 from : AztecAddress ,
635- opts : CallPrivateOptions <S >,
705+ opts : CallPrivateOptions <S , U >,
636706 call : PrivateCall <M , N , T >,
637707 ) -> T
638708 where
@@ -646,6 +716,7 @@ impl TestEnvironment {
646716 hash_args (call .args ),
647717 /*is_static=*/ false ,
648718 opts .additional_scopes ,
719+ opts .authorized_utility_call_targets ,
649720 );
650721
651722 T ::deserialize (serialized_return_values )
@@ -670,10 +741,10 @@ impl TestEnvironment {
670741 }
671742
672743 /// Variant of `view_private` which allows specifying multiple configuration values via `ViewPrivateOptions`.
673- pub unconstrained fn view_private_opts <let M : u32 , let N : u32 , let S : u32 , T >(
744+ pub unconstrained fn view_private_opts <let M : u32 , let N : u32 , let S : u32 , let U : u32 , T >(
674745 _self : Self ,
675746 from : AztecAddress ,
676- opts : ViewPrivateOptions <S >,
747+ opts : ViewPrivateOptions <S , U >,
677748 call : PrivateStaticCall <M , N , T >,
678749 ) -> T
679750 where
@@ -687,6 +758,7 @@ impl TestEnvironment {
687758 hash_args (call .args ),
688759 /*is_static=*/ true ,
689760 opts .additional_scopes ,
761+ opts .authorized_utility_call_targets ,
690762 );
691763
692764 T ::deserialize (serialized_return_values )
@@ -701,12 +773,32 @@ impl TestEnvironment {
701773 /// let contract_addr = env.deploy("SampleContract").without_initializer();
702774 /// let return_value = env.execute_utility(SampleContract::at(contract_addr).sample_utility_function());
703775 /// ```
704- pub unconstrained fn execute_utility <let M : u32 , let N : u32 , T >(_self : Self , call : UtilityCall <M , N , T >) -> T
776+ pub unconstrained fn execute_utility <let M : u32 , let N : u32 , T >(
777+ self : Self ,
778+ call : UtilityCall <M , N , T >,
779+ ) -> T
705780 where
706781 T : Deserialize ,
707782 {
708- let serialized_return_values =
709- txe_oracles:: execute_utility_function (call .target_contract , call .selector , call .args );
783+ self .execute_utility_opts (ExecuteUtilityOptions ::new (), call )
784+ }
785+
786+ /// Variant of `execute_utility` which allows specifying configuration values via `ExecuteUtilityOptions`, such as
787+ /// authorizing cross-contract utility calls.
788+ pub unconstrained fn execute_utility_opts <let M : u32 , let N : u32 , let U : u32 , T >(
789+ _self : Self ,
790+ opts : ExecuteUtilityOptions <U >,
791+ call : UtilityCall <M , N , T >,
792+ ) -> T
793+ where
794+ T : Deserialize ,
795+ {
796+ let serialized_return_values = txe_oracles:: execute_utility_function (
797+ call .target_contract ,
798+ call .selector ,
799+ call .args ,
800+ opts .authorized_utility_call_targets ,
801+ );
710802
711803 T ::deserialize (serialized_return_values )
712804 }
0 commit comments