You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Public functions execute after all private execution completes. Return values are not available in the private context. Learn more about [call types](../../foundational-topics/call_types.md).
69
69
:::
70
+
71
+
## Utility calls
72
+
73
+
Utility functions can call other utility functions. These calls run entirely offchain in PXE and are never proven, so no guarantees are made on the correctness of their results.
74
+
75
+
### Utility-to-utility calls
76
+
77
+
From a utility function, use `self.call()` as with other call types:
To call a utility function of your own contract, use the `self.call_self` stubs instead:
84
+
85
+
```rust
86
+
self.call_self.my_utility_function(args)
87
+
```
88
+
89
+
### Private-to-utility calls
90
+
91
+
Private functions can also call utility functions, through `self.utility`. The call executes unconstrained code, so it must be wrapped in `unsafe`, and its result is not proven: use it to inform logic, never as an input to a constrained assertion without validating it first.
Public functions cannot call utility functions: they run on the sequencer, which has no access to private state or PXE.
105
+
106
+
### Cross-contract authorization
107
+
108
+
A utility call to the calling contract itself always succeeds. A call to a _different_ contract can expose that contract's private state to the caller, so PXE asks the wallet to authorize it before proceeding. If the wallet denies the call, or no `authorizeUtilityCall` hook is configured, the simulation fails with `Cross-contract utility call denied`. See [execution hooks](../../foundational-topics/pxe/execution_hooks.md#authorizeutilitycall) for how wallets handle these requests, and for authorizing targets in Noir tests with `with_authorized_utility_call_targets`.
109
+
110
+
### `msg_sender` in nested utility calls
111
+
112
+
A utility function called from another contract can read the calling contract's address via `self.msg_sender()`, mirroring private and public functions. A utility function invoked directly by an application has no caller: `self.msg_sender()` panics, and `self.context.maybe_msg_sender()` returns `Option::none()`. Within a simulation PXE takes this value from the actual call graph, but utility execution as a whole is unconstrained, so contracts must not rely on it as a security guarantee.
Copy file name to clipboardExpand all lines: docs/docs-developers/docs/aztec-nr/framework-description/functions/how_to_define_functions.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,7 +49,7 @@ Public functions operate on public state, similar to EVM contracts. They can wri
49
49
50
50
Create offchain query functions using the `#[external("utility")]` annotation with `unconstrained`.
51
51
52
-
Utility functions are standalone unconstrained functions that cannot be called from private or public functions. They are meant to be called by _applications_ to perform auxiliary tasks like querying contract state or processing offchain messages. Example:
52
+
Utility functions are unconstrained functions that applications call to perform auxiliary tasks, like querying contract state or processing offchain messages. Their execution is never proven, so no guarantees are made on the correctness of their results. They can also be called from other utility functions and from private functions. See [utility calls](../calling_contracts.md#utility-calls). Public functions cannot call them. Example:
Copy file name to clipboardExpand all lines: docs/docs-developers/docs/foundational-topics/call_types.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -187,11 +187,13 @@ Public functions can be called either directly in a public context (as shown abo
187
187
188
188
### Utility
189
189
190
-
Contract functions marked with `#[external("utility")]`cannot be called as part of a transaction. They are only invoked by applications that interact with contracts for:
190
+
Contract functions marked with `#[external("utility")]`are never proven as part of a transaction, even when called from a private function. They are invoked by applications that interact with contracts for:
191
191
192
192
-**State queries**: Reading from both private and public state via an offchain client
193
193
-**Local state management**: Modifying contract-related PXE state (e.g., processing logs in Aztec.nr)
194
194
195
+
Utility functions can also be called from other utility functions, and from private functions as unconstrained code. Calls that cross a contract boundary require wallet authorization. See [utility calls](../aztec-nr/framework-description/calling_contracts.md#utility-calls) for how to make them.
196
+
195
197
Since utility execution is unconstrained and relies heavily on oracle calls, no guarantees are made on the correctness of results. However, you can verify that the bytecode being executed is correct, since a contract's address includes a commitment to all of its utility functions.
`Registered account address ${address.toString()} does not match contract instance address ${instance.address.toString()}: the provided keys do not correspond to this account.`,
377
+
`Registered account address ${address.toString()} does not match contract instance address ${contractAddress.toString()}: the provided keys do not correspond to this account.`,
0 commit comments