Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/docs-developers/docs/resources/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,37 @@ Aztec is in active development. Each version may introduce breaking changes that

## TBD

### [PXE] `simulateTx`, `executeUtility`, `profileTx`, and `proveTx` no longer accept `scopes: 'ALL_SCOPES'`

The `AccessScopes` type (`'ALL_SCOPES' | AztecAddress[]`) has been removed. The `scopes` field in `SimulateTxOpts`,
`ExecuteUtilityOpts`, and `ProfileTxOpts` now requires an explicit `AztecAddress[]`. Callers that previously passed
`'ALL_SCOPES'` must now specify which addresses will be in scope for the call.

**Migration:**

```diff
+ const accounts = await pxe.getRegisteredAccounts();
+ const scopes = accounts.map(a => a.address);

// simulateTx
- await pxe.simulateTx(txRequest, { simulatePublic: true, scopes: 'ALL_SCOPES' });
+ await pxe.simulateTx(txRequest, { simulatePublic: true, scopes });

// executeUtility
- await pxe.executeUtility(call, { scopes: 'ALL_SCOPES' });
+ await pxe.executeUtility(call, { scopes });

// profileTx
- await pxe.profileTx(txRequest, { profileMode: 'full', scopes: 'ALL_SCOPES' });
+ await pxe.profileTx(txRequest, { profileMode: 'full', scopes });

// proveTx
- await pxe.proveTx(txRequest, 'ALL_SCOPES');
+ await pxe.proveTx(txRequest, scopes);
```

**Impact**: Any code passing `'ALL_SCOPES'` to `simulateTx`, `executeUtility`, `profileTx`, or `proveTx` will fail to compile. Replace with an explicit array of account addresses.

### [PXE] Capsule operations are now scope-enforced at the PXE level

The PXE now enforces that capsule operations can only access scopes that were authorized for the current execution. If a contract attempts to access a capsule scope that is not in its allowed scopes list, the PXE will throw an error:
Expand Down
63 changes: 36 additions & 27 deletions noir-projects/aztec-nr/aztec/src/capsules/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -149,42 +149,43 @@ impl<T> CapsuleArray<T> {
}

mod test {
use crate::protocol::address::AztecAddress;
use crate::test::helpers::test_environment::TestEnvironment;
use super::CapsuleArray;

global SLOT: Field = 1230;
global SCOPE: AztecAddress = AztecAddress { inner: 0xface };

#[test]
unconstrained fn empty_array() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array: CapsuleArray<Field> = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array: CapsuleArray<Field> = CapsuleArray::at(contract_address, SLOT, scope);
assert_eq(array.len(), 0);
});
}

#[test(should_fail_with = "Attempted to read past the length of a CapsuleArray")]
unconstrained fn empty_array_read() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);
let _: Field = array.get(0);
});
}

#[test]
unconstrained fn array_push() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);
array.push(5);

assert_eq(array.len(), 1);
Expand All @@ -194,11 +195,12 @@ mod test {

#[test(should_fail_with = "Attempted to read past the length of a CapsuleArray")]
unconstrained fn read_past_len() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);
array.push(5);

let _ = array.get(1);
Expand All @@ -207,11 +209,12 @@ mod test {

#[test]
unconstrained fn array_remove_last() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(5);
array.remove(0);
Expand All @@ -222,11 +225,12 @@ mod test {

#[test]
unconstrained fn array_remove_some() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(7);
array.push(8);
Expand All @@ -247,11 +251,12 @@ mod test {

#[test]
unconstrained fn array_remove_all() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();

let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(7);
array.push(8);
Expand All @@ -267,10 +272,11 @@ mod test {

#[test]
unconstrained fn for_each_called_with_all_elements() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();
let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(4);
array.push(5);
Expand All @@ -290,10 +296,11 @@ mod test {

#[test]
unconstrained fn for_each_remove_some() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();
let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(4);
array.push(5);
Expand All @@ -313,10 +320,11 @@ mod test {

#[test]
unconstrained fn for_each_remove_all() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();
let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(4);
array.push(5);
Expand All @@ -330,10 +338,11 @@ mod test {

#[test]
unconstrained fn for_each_remove_all_no_copy() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();
let array = CapsuleArray::at(contract_address, SLOT, SCOPE);
let array = CapsuleArray::at(contract_address, SLOT, scope);

array.push(4);
array.push(5);
Expand All @@ -351,11 +360,11 @@ mod test {

#[test]
unconstrained fn different_scopes_are_isolated() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope_a = env.create_light_account();
let scope_b = env.create_light_account();
env.private_context(|context| {
let contract_address = context.this_address();
let scope_a = AztecAddress { inner: 0xaaa };
let scope_b = AztecAddress { inner: 0xbbb };

let array_a = CapsuleArray::at(contract_address, SLOT, scope_a);
let array_b = CapsuleArray::at(contract_address, SLOT, scope_b);
Expand Down
9 changes: 4 additions & 5 deletions noir-projects/aztec-nr/aztec/src/history/test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@ use crate::{
},
test::{helpers::test_environment::TestEnvironment, mocks::mock_note::MockNote},
};
use crate::protocol::{address::AztecAddress, traits::FromField};

pub(crate) global NOTE_STORAGE_SLOT: Field = 420;
pub(crate) global NOTE_CREATED_AT: u32 = 2;
pub(crate) global NOTE_NULLIFIED_AT: u32 = 3;
pub(crate) global NOTE_OWNER: AztecAddress = AztecAddress::from_field(50);

pub(crate) unconstrained fn create_note() -> (TestEnvironment, HintedNote<MockNote>) {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let note_owner = env.create_light_account();

let note_message = env.private_context(|context| {
let mock_note = MockNote::new(69);

lifecycle_create_note(
context,
NOTE_OWNER,
note_owner,
NOTE_STORAGE_SLOT,
mock_note.build_note(),
)
Expand All @@ -32,7 +31,7 @@ pub(crate) unconstrained fn create_note() -> (TestEnvironment, HintedNote<MockNo

env.discover_note(note_message);

let hinted_note = env.utility_context(|_| view_note(Option::some(NOTE_OWNER), NOTE_STORAGE_SLOT));
let hinted_note = env.utility_context(|_| view_note(Option::some(note_owner), NOTE_STORAGE_SLOT));

(env, hinted_note)
}
Expand Down
20 changes: 3 additions & 17 deletions noir-projects/aztec-nr/aztec/src/macros/events.nr
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ pub comptime mut global EVENT_SELECTORS: CHashMap<Field, Quoted> = CHashMap::new

comptime fn generate_event_interface_and_get_selector(s: TypeDefinition) -> (Quoted, Field) {
let name = s.name();
let typ = s.as_type();
let event_type_name: str<_> = f"{name}".as_quoted_str!();
let max_event_serialized_len = crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;

let event_selector = compute_struct_selector(s, quote { crate::event::EventSelector::from_signature });

Expand All @@ -26,18 +23,6 @@ comptime fn generate_event_interface_and_get_selector(s: TypeDefinition) -> (Quo
quote {
impl aztec::event::event_interface::EventInterface for $name {
fn get_event_type_id() -> aztec::event::EventSelector {
// This static assertion ensures the event's serialized length doesn't exceed the maximum
// allowed size. While this check would ideally live in the Serialize trait implementation, we
// place it here since this function is always generated by our macros and the Serialize trait
// implementation is not.
//
// Note: We set the event type name and max serialized length as local variables because
// injecting them directly into the error message doesn't work.
let event_type_name = $event_type_name;
let max_event_serialized_len: u32 = $max_event_serialized_len;
let event_serialized_len = <$typ as aztec::protocol::traits::Serialize>::N;
std::static_assert(event_serialized_len <= $max_event_serialized_len, f"{event_type_name} has a serialized length of {event_serialized_len} fields, which exceeds the maximum allowed length of {max_event_serialized_len} fields. See https://docs.aztec.network/errors/5");

$from_field($event_selector)
}
}
Expand All @@ -63,8 +48,9 @@ comptime fn register_event_selector(event_selector: Field, event_name: Quoted) {
///
/// ## Requirements
///
/// The event struct must not exceed
/// [`MAX_EVENT_SERIALIZED_LEN`](crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN) when serialized.
/// Events can be emitted both privately and publicly. Public emission imposes no requirements, but for an event to be
/// emittable privately its serialization length must not exceeed
/// [`MAX_EVENT_SERIALIZED_LEN`](crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN).
pub comptime fn event(s: TypeDefinition) -> Quoted {
let (event_interface_impl, event_selector) = generate_event_interface_and_get_selector(s);
register_event_selector(event_selector, s.name());
Expand Down
9 changes: 4 additions & 5 deletions noir-projects/aztec-nr/aztec/src/messages/discovery/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -200,18 +200,17 @@ mod test {
};
use crate::protocol::address::AztecAddress;

global SCOPE: AztecAddress = AztecAddress { inner: 0xcafe };

#[test]
unconstrained fn do_sync_state_does_not_panic_on_empty_logs() {
let env = TestEnvironment::new();
let mut env = TestEnvironment::new();
let scope = env.create_light_account();

let contract_address = AztecAddress { inner: 0xdeadbeef };

env.utility_context_at(contract_address, |_| {
let base_slot = PENDING_TAGGED_LOG_ARRAY_BASE_SLOT;

let logs: CapsuleArray<PendingTaggedLog> = CapsuleArray::at(contract_address, base_slot, SCOPE);
let logs: CapsuleArray<PendingTaggedLog> = CapsuleArray::at(contract_address, base_slot, scope);
logs.push(PendingTaggedLog { log: BoundedVec::new(), context: std::mem::zeroed() });
assert_eq(logs.len(), 1);

Expand All @@ -223,7 +222,7 @@ mod test {
dummy_compute_note_nullifier,
no_handler,
no_inbox_sync,
SCOPE,
scope,
);

assert_eq(logs.len(), 0);
Expand Down
5 changes: 5 additions & 0 deletions noir-projects/aztec-nr/aztec/src/messages/logs/event.nr
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ pub fn encode_private_event_message<Event>(
where
Event: EventInterface + Serialize,
{
std::static_assert(
<Event as Serialize>::N <= MAX_EVENT_SERIALIZED_LEN,
"event's serialized length exceeds the maximum allowed for private events",
);

// We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,
// wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility
// functions in order to unpack events, which would introduce a level of complexity we don't currently think is
Expand Down
19 changes: 19 additions & 0 deletions noir-projects/aztec-nr/aztec/src/messages/logs/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ pub(crate) fn compute_discovery_tag(recipient: AztecAddress) -> Field {
}

mod test {
use crate::oracle::notes::set_sender_for_tags;
use crate::protocol::{address::AztecAddress, traits::FromField};
use crate::test::helpers::test_environment::TestEnvironment;
use super::compute_discovery_tag;
use std::test::OracleMock;

Expand All @@ -42,4 +44,21 @@ mod test {
let _ = OracleMock::mock("aztec_prv_getNextAppTagAsSender").returns(expected_tag);
assert_eq(compute_discovery_tag(recipient), expected_tag);
}

#[test]
unconstrained fn does_not_fail_on_an_invalid_recipient() {
let mut env = TestEnvironment::new();

let sender = env.create_light_account();

env.private_context(|_context| {
set_sender_for_tags(sender);

// The recipient is an invalid address
let recipient = AztecAddress { inner: 3 };
assert(!recipient.is_valid());

let _ = compute_discovery_tag(recipient);
});
}
}
Loading
Loading