Skip to content

Commit 2b932d6

Browse files
authored
chore(port): forward-port v5-next pxe/client/txe backlog to next (#24932)
Forward-ports the **pxe / client / txe** slice of the v5-next → next backlog (work merged to `v5-next` after the ~2026-07-08 cut that reshaped `next`). ## Applied (clean cherry-picks, chronological) - fix: tweak depositToAztec gas config (#24607) - refactor: cache Aztec node reads per execution (#24630) - fix: prevent access to secrets not in scope (#24616) - docs: fee readme improvements (#24666) - fix(pxe): widen tracked sender tagging ranges with onchain discovery evidence (#24655) - fix: tagging secrets not being scoped by sender (#24772) ## Conflict resolutions (cherry-picked with `-x`, resolved against reshaped `next`) - fix(txe): align tagging strategy oracle with PXE (#24561) — TXE oracle version bumped to 4.0 (breaking rename `setTaggingSecretStrategy` -> `setTaggingSecretStrategies`; `next` was at 3.0 with its own hash), interface hash recomputed on the merged registry. Migration note dropped: already on `next` under 5.0.0. - feat(pxe)!: Add AppTaggingSecret kinds to keys in tagging stores (#24604) — `PXE_DATA_SCHEMA_VERSION` 12 -> 13 applies cleanly on `next`. Migration note dropped: already on `next` under 5.0.0. - feat: add batch is block in archive oracle (#24634) — applied cleanly on top of #24561; contract oracle version 30.6 -> 30.7, v5 interface hash matched the merged registry. - feat: getTxEffects oracle (#24636) — applied cleanly. - ~~feat: preserve stores on schema version or rollup address change (#24631)~~ — ported separately via #24947 together with the rest of the sqlite/OPFS line - feat(txe): add option to authorize all utility call targets (#24662) — additive on our 4.0 -> TXE oracle version 4.1 (was 3.0 -> 3.1 on v5), hash recomputed. - refactor(pxe): compute oracle interface hash from wire-structural mapping labels (#24752) — TXE hash recomputed under the new wire-structural scheme; PXE hash from the pick matched. Verified locally: full `yarn build`, `check_oracle_version` + `check_txe_oracle_version`, TXE unit suite (21), pxe tagging/type-mapping/utility-oracle suites, and 29 targeted aztec-nr + onchain_delivery_test_contract TXE tests — all green. Part of the manual v5-next → next backlog sweep. ## Added after review - #24627 fix(aztec.js): give waitForNode a bounded default timeout — missed by the initial sweep (merge-commit wrapper + non-`(#N)` leaf); genuinely absent from `next`.
2 parents dfcf16f + 26a976e commit 2b932d6

80 files changed

Lines changed: 2392 additions & 1309 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/docs-developers/docs/foundational-topics/pxe/execution_hooks.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,23 @@ For an unconstrained self-send (the recipient is one of the wallet's own account
8282

8383
### In Noir tests
8484

85-
When testing in Noir, leaving the strategy unset makes `TestEnvironment` fall back to the bare PXE default. Set a strategy when creating the environment to exercise a specific one; it affects message delivery in private executions:
85+
When testing in Noir, leaving the strategy unset makes `TestEnvironment` fall back to the bare PXE default. Set a strategy
86+
when creating the environment to exercise a specific one; it affects message delivery in private executions that use the
87+
default wallet strategy hook. Use `with_default_tag_secret_strategy` to configure the strategy for a specific delivery
88+
mode:
8689

8790
```rust
8891
let env = TestEnvironment::new_opts(
89-
TestEnvironmentOptions::new().with_tagging_secret_strategy(TaggingSecretStrategy::non_interactive_handshake()),
92+
TestEnvironmentOptions::new().with_default_tag_secret_strategy(
93+
MessageDelivery::onchain_unconstrained(),
94+
TaggingSecretStrategy::non_interactive_handshake(),
95+
),
9096
);
9197
```
9298

99+
Use `with_default_tag_secret_strategy_all_modes` only when the same strategy should apply to both constrained and
100+
unconstrained delivery. Contract-fixed delivery derivations bypass this default strategy.
101+
93102
### In production
94103

95104
Pass a `resolveTaggingSecretStrategy` hook when [creating the PXE](#configuring-hooks). It receives a `TaggingSecretStrategyRequest` with the executing contract's address and the message's sender, recipient, and delivery mode (`'constrained'` or `'unconstrained'`), so a wallet can apply per-application or per-recipient policies, or surface the decision to the user, instead of returning a fixed value.

noir-projects/aztec-nr/aztec/src/messages/delivery/tag.nr

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,29 @@ mod test {
180180
});
181181
}
182182

183+
#[test(should_fail_with = "an unconstrained tagging secret cannot back constrained delivery")]
184+
unconstrained fn constrained_delivery_rejects_a_resolved_unconstrained_secret() {
185+
let env = TestEnvironment::new();
186+
let secret: Field = 7;
187+
let index: u32 = 0;
188+
189+
env.private_context(|context| {
190+
mock_existing_handshake_secrets(Option::none());
191+
let _ = OracleMock::mock("aztec_prv_resolveTaggingStrategy").returns(
192+
ResolvedTaggingStrategy::unconstrained_secret(secret),
193+
);
194+
let _ = OracleMock::mock("aztec_prv_getNextTaggingIndex").returns(index);
195+
196+
let _ = derive_log_tag(
197+
context,
198+
OnchainDeliveryMode::onchain_constrained(),
199+
SENDER,
200+
RECIPIENT,
201+
Option::none(),
202+
);
203+
});
204+
}
205+
183206
#[test]
184207
unconstrained fn constrained_delivery_emits_the_sequence_nullifier_and_constrained_tag() {
185208
let env = TestEnvironment::new();

noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use crate::protocol::{
2-
abis::block_header::BlockHeader,
3-
constants::{ARCHIVE_HEIGHT, NOTE_HASH_TREE_HEIGHT},
4-
merkle_tree::MembershipWitness,
5-
traits::Hash,
1+
use crate::{
2+
ephemeral::EphemeralArray,
3+
protocol::{
4+
abis::block_header::BlockHeader,
5+
constants::{ARCHIVE_HEIGHT, NOTE_HASH_TREE_HEIGHT},
6+
merkle_tree::MembershipWitness,
7+
traits::Hash,
8+
},
69
};
710

811
#[oracle(aztec_utl_getNoteHashMembershipWitness)]
@@ -17,6 +20,12 @@ unconstrained fn get_block_hash_membership_witness_oracle(
1720
block_hash: Field,
1821
) -> Option<MembershipWitness<ARCHIVE_HEIGHT>> {}
1922

23+
#[oracle(aztec_utl_areBlockHashesInArchive)]
24+
unconstrained fn are_block_hashes_in_archive_oracle(
25+
anchor_block_hash: Field,
26+
block_hashes: EphemeralArray<Field>,
27+
) -> EphemeralArray<bool> {}
28+
2029
// Note: get_nullifier_membership_witness function is implemented in get_nullifier_membership_witness.nr
2130

2231
/// Returns a membership witness for a `note_hash` in the note hash tree whose root is defined in
@@ -53,6 +62,15 @@ pub unconstrained fn get_maybe_block_hash_membership_witness(
5362
get_block_hash_membership_witness_oracle(anchor_block_hash, block_hash)
5463
}
5564

65+
/// Returns whether each block hash is present in the archive tree whose root is defined in `anchor_block_header`.
66+
pub unconstrained fn are_block_hashes_in_archive(
67+
anchor_block_header: BlockHeader,
68+
block_hashes: EphemeralArray<Field>,
69+
) -> EphemeralArray<bool> {
70+
let anchor_block_hash = anchor_block_header.hash();
71+
are_block_hashes_in_archive_oracle(anchor_block_hash, block_hashes)
72+
}
73+
5674
mod test {
5775
use crate::history::test::{create_note, NOTE_CREATED_AT};
5876
use crate::note::note_interface::NoteHash;

noir-projects/aztec-nr/aztec/src/oracle/message_processing.nr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,11 @@ pub unconstrained fn get_tx_effect(tx_hash: Field) -> Option<TxEffect> {
6666

6767
#[oracle(aztec_utl_getTxEffect)]
6868
unconstrained fn get_tx_effect_oracle(tx_hash: Field) -> Option<TxEffect> {}
69+
70+
/// Fetches all effects of settled transactions by hash, preserving request order.
71+
pub unconstrained fn get_tx_effects(tx_hashes: EphemeralArray<Field>) -> EphemeralArray<Option<TxEffect>> {
72+
get_tx_effects_oracle(tx_hashes)
73+
}
74+
75+
#[oracle(aztec_utl_getTxEffects)]
76+
unconstrained fn get_tx_effects_oracle(tx_hashes: EphemeralArray<Field>) -> EphemeralArray<Option<TxEffect>> {}

noir-projects/aztec-nr/aztec/src/oracle/mod.nr

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,7 @@ use crate::macros::oracle_testing::{generate_oracle_tests, generate_oracle_tests
2222
],
2323
)]
2424
pub mod avm;
25-
#[generate_oracle_tests_excluding(
26-
@[
27-
// TODO: cover once the iv/sym_key BUFFER mapping is expressible as a plain fixed array of bytes, so the
28-
// fixture synthesizer does not need to special-case it.
29-
quote { aes128_decrypt_oracle },
30-
],
31-
)]
25+
#[generate_oracle_tests]
3226
pub mod aes128_decrypt;
3327
#[generate_oracle_tests]
3428
pub mod auth_witness;
@@ -99,7 +93,12 @@ pub mod get_nullifier_membership_witness;
9993
],
10094
)]
10195
pub mod get_public_data_witness;
102-
#[generate_oracle_tests]
96+
#[generate_oracle_tests_excluding(
97+
@[
98+
// TODO: cover once the test resolver can serve EphemeralArray contents.
99+
quote { are_block_hashes_in_archive_oracle },
100+
],
101+
)]
103102
pub mod get_membership_witness;
104103
#[generate_oracle_tests]
105104
pub mod keys;

noir-projects/aztec-nr/aztec/src/oracle/tx_resolution.nr

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -18,104 +18,3 @@ pub(crate) unconstrained fn get_resolved_txs(requests: EphemeralArray<Field>) ->
1818

1919
#[oracle(aztec_utl_getResolvedTxs)]
2020
unconstrained fn get_resolved_txs_oracle(requests: EphemeralArray<Field>) -> EphemeralArray<Option<ResolvedTx>> {}
21-
22-
mod test {
23-
use crate::oracle::tx_resolution::ResolvedTx;
24-
use crate::protocol::traits::Deserialize;
25-
26-
#[test]
27-
unconstrained fn resolved_tx_serialization_matches_typescript() {
28-
// Setup test data
29-
let tx_hash = 123;
30-
let unique_note_hashes = BoundedVec::from_array([4, 5]);
31-
let first_nullifier = 6;
32-
let block_number: u32 = 7;
33-
let block_hash = 8;
34-
35-
// Create a ResolvedTx instance
36-
let resolved_tx = ResolvedTx {
37-
tx_hash,
38-
unique_note_hashes_in_tx: unique_note_hashes,
39-
first_nullifier_in_tx: first_nullifier,
40-
block_number,
41-
block_hash,
42-
};
43-
44-
// Expected output generated from TypeScript's `ResolvedTx.toFields()`
45-
let serialized_resolved_tx_from_typescript = [
46-
0x000000000000000000000000000000000000000000000000000000000000007b,
47-
0x0000000000000000000000000000000000000000000000000000000000000004,
48-
0x0000000000000000000000000000000000000000000000000000000000000005,
49-
0x0000000000000000000000000000000000000000000000000000000000000000,
50-
0x0000000000000000000000000000000000000000000000000000000000000000,
51-
0x0000000000000000000000000000000000000000000000000000000000000000,
52-
0x0000000000000000000000000000000000000000000000000000000000000000,
53-
0x0000000000000000000000000000000000000000000000000000000000000000,
54-
0x0000000000000000000000000000000000000000000000000000000000000000,
55-
0x0000000000000000000000000000000000000000000000000000000000000000,
56-
0x0000000000000000000000000000000000000000000000000000000000000000,
57-
0x0000000000000000000000000000000000000000000000000000000000000000,
58-
0x0000000000000000000000000000000000000000000000000000000000000000,
59-
0x0000000000000000000000000000000000000000000000000000000000000000,
60-
0x0000000000000000000000000000000000000000000000000000000000000000,
61-
0x0000000000000000000000000000000000000000000000000000000000000000,
62-
0x0000000000000000000000000000000000000000000000000000000000000000,
63-
0x0000000000000000000000000000000000000000000000000000000000000000,
64-
0x0000000000000000000000000000000000000000000000000000000000000000,
65-
0x0000000000000000000000000000000000000000000000000000000000000000,
66-
0x0000000000000000000000000000000000000000000000000000000000000000,
67-
0x0000000000000000000000000000000000000000000000000000000000000000,
68-
0x0000000000000000000000000000000000000000000000000000000000000000,
69-
0x0000000000000000000000000000000000000000000000000000000000000000,
70-
0x0000000000000000000000000000000000000000000000000000000000000000,
71-
0x0000000000000000000000000000000000000000000000000000000000000000,
72-
0x0000000000000000000000000000000000000000000000000000000000000000,
73-
0x0000000000000000000000000000000000000000000000000000000000000000,
74-
0x0000000000000000000000000000000000000000000000000000000000000000,
75-
0x0000000000000000000000000000000000000000000000000000000000000000,
76-
0x0000000000000000000000000000000000000000000000000000000000000000,
77-
0x0000000000000000000000000000000000000000000000000000000000000000,
78-
0x0000000000000000000000000000000000000000000000000000000000000000,
79-
0x0000000000000000000000000000000000000000000000000000000000000000,
80-
0x0000000000000000000000000000000000000000000000000000000000000000,
81-
0x0000000000000000000000000000000000000000000000000000000000000000,
82-
0x0000000000000000000000000000000000000000000000000000000000000000,
83-
0x0000000000000000000000000000000000000000000000000000000000000000,
84-
0x0000000000000000000000000000000000000000000000000000000000000000,
85-
0x0000000000000000000000000000000000000000000000000000000000000000,
86-
0x0000000000000000000000000000000000000000000000000000000000000000,
87-
0x0000000000000000000000000000000000000000000000000000000000000000,
88-
0x0000000000000000000000000000000000000000000000000000000000000000,
89-
0x0000000000000000000000000000000000000000000000000000000000000000,
90-
0x0000000000000000000000000000000000000000000000000000000000000000,
91-
0x0000000000000000000000000000000000000000000000000000000000000000,
92-
0x0000000000000000000000000000000000000000000000000000000000000000,
93-
0x0000000000000000000000000000000000000000000000000000000000000000,
94-
0x0000000000000000000000000000000000000000000000000000000000000000,
95-
0x0000000000000000000000000000000000000000000000000000000000000000,
96-
0x0000000000000000000000000000000000000000000000000000000000000000,
97-
0x0000000000000000000000000000000000000000000000000000000000000000,
98-
0x0000000000000000000000000000000000000000000000000000000000000000,
99-
0x0000000000000000000000000000000000000000000000000000000000000000,
100-
0x0000000000000000000000000000000000000000000000000000000000000000,
101-
0x0000000000000000000000000000000000000000000000000000000000000000,
102-
0x0000000000000000000000000000000000000000000000000000000000000000,
103-
0x0000000000000000000000000000000000000000000000000000000000000000,
104-
0x0000000000000000000000000000000000000000000000000000000000000000,
105-
0x0000000000000000000000000000000000000000000000000000000000000000,
106-
0x0000000000000000000000000000000000000000000000000000000000000000,
107-
0x0000000000000000000000000000000000000000000000000000000000000000,
108-
0x0000000000000000000000000000000000000000000000000000000000000000,
109-
0x0000000000000000000000000000000000000000000000000000000000000000,
110-
0x0000000000000000000000000000000000000000000000000000000000000000,
111-
0x0000000000000000000000000000000000000000000000000000000000000002,
112-
0x0000000000000000000000000000000000000000000000000000000000000006,
113-
0x0000000000000000000000000000000000000000000000000000000000000007,
114-
0x0000000000000000000000000000000000000000000000000000000000000008,
115-
];
116-
117-
let deserialized = ResolvedTx::deserialize(serialized_resolved_tx_from_typescript);
118-
119-
assert_eq(deserialized, resolved_tx);
120-
}
121-
}

noir-projects/aztec-nr/aztec/src/oracle/version.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
/// immediately if AZTEC_NR_MINOR > PXE_MINOR because if a contract is updated to use a newer Aztec.nr dependency
1212
/// without actually using any of the new oracles then there is no reason to throw.
1313
pub global ORACLE_VERSION_MAJOR: Field = 30;
14-
pub global ORACLE_VERSION_MINOR: Field = 6;
14+
pub global ORACLE_VERSION_MINOR: Field = 8;
1515

1616
/// Asserts that the version of the oracle is compatible with the version expected by the contract.
1717
pub fn assert_compatible_oracle_version() {

noir-projects/aztec-nr/aztec/src/test/helpers/mod.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub mod test_environment;
1313
quote { private_call_new_flow_oracle }, // TODO: implement once we support more complex types
1414
quote { public_call_new_flow_oracle }, // TODO: implement once we support more complex types
1515
quote { set_private_txe_context_oracle }, // TODO: implement once we support more complex types
16-
quote { set_tagging_secret_strategy }, // TODO: implement once we support more complex types
16+
quote { set_tagging_secret_strategies }, // TODO: implement once we support more complex types
1717
],
1818
)]
1919
pub mod txe_oracles;

noir-projects/aztec-nr/aztec/src/test/helpers/tagging_secret_strategy.nr

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
use crate::protocol::{point::EmbeddedCurvePoint, traits::{Deserialize, Serialize}, utils::reader::Reader};
1+
use crate::keys::ecdh_shared_secret::compute_app_siloed_shared_secret;
2+
use crate::protocol::{
3+
address::AztecAddress,
4+
hash::poseidon2_hash,
5+
point::EmbeddedCurvePoint,
6+
traits::{Deserialize, Serialize, ToField},
7+
utils::reader::Reader,
8+
};
29

310
global NON_INTERACTIVE_HANDSHAKE: u8 = 1;
411
global ARBITRARY_SECRET: u8 = 2;
@@ -7,7 +14,7 @@ global INTERACTIVE_HANDSHAKE: u8 = 4;
714

815
/// How a message's tagging secret is chosen: the wallet's strategy.
916
///
10-
/// This type only exists for tests: a Noir test sets it via `with_tagging_secret_strategy` on
17+
/// This type only exists for tests: a Noir test sets it via `with_default_tag_secret_strategy` on
1118
/// [`TestEnvironmentOptions`](crate::test::helpers::test_environment::TestEnvironmentOptions).
1219
/// Production wallets express the strategy in PXE; the Noir path only consumes the resolved
1320
/// [`ResolvedTaggingStrategy`](crate::messages::delivery::ResolvedTaggingStrategy).
@@ -45,18 +52,26 @@ impl TaggingSecretStrategy {
4552
/// Validates a raw discriminant, as deserialization must always reject unknown values.
4653
fn from_parts(kind: u8, secret: EmbeddedCurvePoint) -> Self {
4754
let strategy = Self { kind, secret };
55+
let is_no_payload_strategy =
56+
(kind == NON_INTERACTIVE_HANDSHAKE) | (kind == INTERACTIVE_HANDSHAKE) | (kind == ADDRESS_DERIVED);
4857
assert(
49-
(
50-
((kind == NON_INTERACTIVE_HANDSHAKE) | (kind == ADDRESS_DERIVED) | (kind == INTERACTIVE_HANDSHAKE))
51-
& secret.is_infinite()
52-
)
53-
| (kind == ARBITRARY_SECRET),
58+
(is_no_payload_strategy & secret.is_infinite()) | (kind == ARBITRARY_SECRET),
5459
f"unrecognized tagging secret strategy kind: {kind}",
5560
);
5661
strategy
5762
}
5863
}
5964

65+
/// Computes the directional tagging secret PXE derives from an arbitrary shared secret point: the point is app-siloed
66+
/// and the recipient is folded in for direction. Mirrors `AppTaggingSecret.computeDirectional` on the PXE side; tests
67+
/// use it to derive the secret they expect an [`arbitrary_secret`](TaggingSecretStrategy::arbitrary_secret) strategy
68+
/// to produce.
69+
pub fn compute_directional_app_secret(secret: EmbeddedCurvePoint, app: AztecAddress, recipient: AztecAddress) -> Field {
70+
poseidon2_hash(
71+
[compute_app_siloed_shared_secret(secret, app), recipient.to_field()],
72+
)
73+
}
74+
6075
impl Deserialize for TaggingSecretStrategy {
6176
let N: u32 = 3;
6277

@@ -81,14 +96,14 @@ mod test {
8196
#[test]
8297
fn strategy_roundtrips_through_serialization() {
8398
let non_interactive = TaggingSecretStrategy::non_interactive_handshake();
99+
let interactive = TaggingSecretStrategy::interactive_handshake();
84100
let address = TaggingSecretStrategy::address_derived();
85101
let provided = TaggingSecretStrategy::arbitrary_secret(EmbeddedCurvePoint { x: 7, y: 11 });
86-
let interactive = TaggingSecretStrategy::interactive_handshake();
87102

88103
assert(TaggingSecretStrategy::deserialize(non_interactive.serialize()) == non_interactive);
104+
assert(TaggingSecretStrategy::deserialize(interactive.serialize()) == interactive);
89105
assert(TaggingSecretStrategy::deserialize(address.serialize()) == address);
90106
assert(TaggingSecretStrategy::deserialize(provided.serialize()) == provided);
91-
assert(TaggingSecretStrategy::deserialize(interactive.serialize()) == interactive);
92107
}
93108

94109
#[test(should_fail_with = "unrecognized tagging secret strategy kind")]
@@ -98,16 +113,22 @@ mod test {
98113

99114
#[test(should_fail_with = "unrecognized tagging secret strategy kind")]
100115
fn deserializing_handshake_with_noninfinite_point_fails() {
101-
let _ = TaggingSecretStrategy::deserialize([1, 7, 11]);
116+
let _ = TaggingSecretStrategy::deserialize([
117+
TaggingSecretStrategy::non_interactive_handshake().kind as Field,
118+
7,
119+
11,
120+
]);
102121
}
103122

104123
#[test(should_fail_with = "unrecognized tagging secret strategy kind")]
105124
fn deserializing_address_derived_with_noninfinite_point_fails() {
106-
let _ = TaggingSecretStrategy::deserialize([3, 7, 11]);
125+
let _ = TaggingSecretStrategy::deserialize(
126+
[TaggingSecretStrategy::address_derived().kind as Field, 7, 11],
127+
);
107128
}
108129

109130
#[test(should_fail_with = "unrecognized tagging secret strategy kind")]
110131
fn deserializing_interactive_handshake_with_noninfinite_point_fails() {
111-
let _ = TaggingSecretStrategy::deserialize([4, 7, 11]);
132+
let _ = TaggingSecretStrategy::deserialize([TaggingSecretStrategy::interactive_handshake().kind as Field, 7, 11]);
112133
}
113134
}

0 commit comments

Comments
 (0)