@aztec/txe 5.0.0-rc.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dest/AuthRegistry-56AMRLSQ.js +3 -0
  2. package/dest/AuthRegistry-56AMRLSQ.js.map +7 -0
  3. package/dest/ContractClassRegistry-N6NA3SFA.js +3 -0
  4. package/dest/ContractClassRegistry-N6NA3SFA.js.map +7 -0
  5. package/dest/ContractInstanceRegistry-NADDSLGL.js +3 -0
  6. package/dest/ContractInstanceRegistry-NADDSLGL.js.map +7 -0
  7. package/dest/FeeJuice-QBH5JWJV.js +3 -0
  8. package/dest/FeeJuice-QBH5JWJV.js.map +7 -0
  9. package/dest/HandshakeRegistry-D2W3AOPD.js +3 -0
  10. package/dest/HandshakeRegistry-D2W3AOPD.js.map +7 -0
  11. package/dest/MultiCallEntrypoint-MIDICLQB.js +3 -0
  12. package/dest/MultiCallEntrypoint-MIDICLQB.js.map +7 -0
  13. package/dest/SchnorrAccount-HNL7EN7Y.js +3 -0
  14. package/dest/SchnorrAccount-HNL7EN7Y.js.map +7 -0
  15. package/dest/SchnorrInitializerlessAccount-TFAFXZW6.js +3 -0
  16. package/dest/SchnorrInitializerlessAccount-TFAFXZW6.js.map +7 -0
  17. package/dest/bin/index.js +1 -1
  18. package/dest/bin/oracle_test_server.js +1 -1
  19. package/dest/chunk-EKHK6CRD.js +268 -0
  20. package/dest/chunk-EKHK6CRD.js.map +7 -0
  21. package/dest/{chunk-I6DL4FT2.js → chunk-RELAEYUE.js} +2 -2
  22. package/dest/{chunk-I6DL4FT2.js.map → chunk-RELAEYUE.js.map} +3 -3
  23. package/dest/index.d.ts +1 -1
  24. package/dest/index.d.ts.map +1 -1
  25. package/dest/index.js +5 -3
  26. package/dest/metafile.json +3677 -3076
  27. package/dest/oracle/interfaces.d.ts +15 -7
  28. package/dest/oracle/interfaces.d.ts.map +1 -1
  29. package/dest/oracle/tagging_secret_strategy.d.ts +12 -0
  30. package/dest/oracle/tagging_secret_strategy.d.ts.map +1 -0
  31. package/dest/oracle/tagging_secret_strategy.js +12 -0
  32. package/dest/oracle/test-resolver/default_fixtures.d.ts +3 -3
  33. package/dest/oracle/test-resolver/default_fixtures.d.ts.map +1 -1
  34. package/dest/oracle/test-resolver/default_fixtures.js +54 -11
  35. package/dest/oracle/test-resolver/resolver.d.ts +1 -1
  36. package/dest/oracle/test-resolver/resolver.js +39 -2
  37. package/dest/oracle/txe_oracle_public_context.d.ts +6 -6
  38. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  39. package/dest/oracle/txe_oracle_public_context.js +15 -9
  40. package/dest/oracle/txe_oracle_registry.d.ts +21 -16
  41. package/dest/oracle/txe_oracle_registry.d.ts.map +1 -1
  42. package/dest/oracle/txe_oracle_registry.js +59 -17
  43. package/dest/oracle/txe_oracle_top_level_context.d.ts +22 -7
  44. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  45. package/dest/oracle/txe_oracle_top_level_context.js +67 -35
  46. package/dest/oracle/txe_oracle_version.d.ts +3 -3
  47. package/dest/oracle/txe_oracle_version.js +3 -3
  48. package/dest/rpc_translator.d.ts +9 -5
  49. package/dest/rpc_translator.d.ts.map +1 -1
  50. package/dest/rpc_translator.js +44 -12
  51. package/dest/server.bundle.js +1 -1
  52. package/dest/state_machine/dummy_p2p_client.d.ts +2 -1
  53. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  54. package/dest/state_machine/dummy_p2p_client.js +3 -0
  55. package/dest/state_machine/index.d.ts +4 -3
  56. package/dest/state_machine/index.d.ts.map +1 -1
  57. package/dest/state_machine/index.js +7 -4
  58. package/dest/state_machine/synchronizer.d.ts +3 -1
  59. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  60. package/dest/state_machine/synchronizer.js +3 -0
  61. package/dest/txe_session.d.ts +3 -2
  62. package/dest/txe_session.d.ts.map +1 -1
  63. package/dest/txe_session.js +35 -15
  64. package/dest/utils/encoding.d.ts +4 -3
  65. package/dest/utils/encoding.d.ts.map +1 -1
  66. package/dest/utils/tx_effect_creation.d.ts +1 -1
  67. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  68. package/dest/utils/tx_effect_creation.js +0 -1
  69. package/dest/utils/txe_public_contract_data_source.d.ts +1 -1
  70. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -1
  71. package/dest/utils/txe_public_contract_data_source.js +7 -4
  72. package/dest/worker.bundle.js +1 -1
  73. package/package.json +17 -17
  74. package/src/bin/oracle_test_server.ts +1 -1
  75. package/src/index.ts +5 -3
  76. package/src/oracle/interfaces.ts +17 -6
  77. package/src/oracle/tagging_secret_strategy.ts +25 -0
  78. package/src/oracle/test-resolver/default_fixtures.ts +73 -17
  79. package/src/oracle/test-resolver/resolver.ts +49 -2
  80. package/src/oracle/txe_oracle_public_context.ts +13 -11
  81. package/src/oracle/txe_oracle_registry.ts +58 -9
  82. package/src/oracle/txe_oracle_top_level_context.ts +108 -31
  83. package/src/oracle/txe_oracle_version.ts +3 -3
  84. package/src/rpc_translator.ts +51 -13
  85. package/src/state_machine/dummy_p2p_client.ts +4 -0
  86. package/src/state_machine/index.ts +19 -2
  87. package/src/state_machine/synchronizer.ts +5 -0
  88. package/src/txe_session.ts +63 -15
  89. package/src/utils/tx_effect_creation.ts +0 -2
  90. package/src/utils/txe_public_contract_data_source.ts +6 -4
  91. package/dest/AuthRegistry-URXCCPYF.js +0 -3
  92. package/dest/AuthRegistry-URXCCPYF.js.map +0 -7
  93. package/dest/ContractClassRegistry-5RDBM6TC.js +0 -3
  94. package/dest/ContractClassRegistry-5RDBM6TC.js.map +0 -7
  95. package/dest/ContractInstanceRegistry-GCR4G4D7.js +0 -3
  96. package/dest/ContractInstanceRegistry-GCR4G4D7.js.map +0 -7
  97. package/dest/FeeJuice-O3KOSZO5.js +0 -3
  98. package/dest/FeeJuice-O3KOSZO5.js.map +0 -7
  99. package/dest/HandshakeRegistry-TXSMHMNY.js +0 -3
  100. package/dest/HandshakeRegistry-TXSMHMNY.js.map +0 -7
  101. package/dest/MultiCallEntrypoint-P4FSRXAD.js +0 -3
  102. package/dest/MultiCallEntrypoint-P4FSRXAD.js.map +0 -7
  103. package/dest/SchnorrAccount-AQZX7ROU.js +0 -3
  104. package/dest/SchnorrAccount-AQZX7ROU.js.map +0 -7
  105. package/dest/SchnorrInitializerlessAccount-KMX2H3J6.js +0 -3
  106. package/dest/SchnorrInitializerlessAccount-KMX2H3J6.js.map +0 -7
  107. package/dest/chunk-IAO54JS2.js +0 -266
  108. package/dest/chunk-IAO54JS2.js.map +0 -7
@@ -53,7 +53,7 @@ export class OracleTestResolver {
53
53
 
54
54
  /**
55
55
  * Builds a resolver whose fixtures are the default scenarios synthesized from the registry's type mappings. The
56
- * matching Noir serialization tests are auto-generated by `#[auto_serialization_test]` from the same convention.
56
+ * matching Noir serialization tests are auto-generated by `#[generate_oracle_tests]` from the same convention.
57
57
  */
58
58
  static fromRegistry(registry: Record<string, OracleRegistryEntry>, logger?: Logger): OracleTestResolver {
59
59
  return new OracleTestResolver(registry, synthesizeDefaultFixtures(registry), logger);
@@ -179,6 +179,11 @@ function decodeScenarioName(inputs: ForeignCallArgs): string {
179
179
  }
180
180
 
181
181
  function valuesEqual(actual: unknown, expected: unknown): boolean {
182
+ if (!isNonNullObject(actual) || !isNonNullObject(expected)) {
183
+ // Primitive scalars; String() bridges bigint vs number representations of the same seed. A primitive compared
184
+ // against an object is never equal.
185
+ return isNonNullObject(actual) === isNonNullObject(expected) && String(actual) === String(expected);
186
+ }
182
187
  if (actual instanceof Option && expected instanceof Option) {
183
188
  return actual.equals(expected, valuesEqual);
184
189
  }
@@ -188,7 +193,49 @@ function valuesEqual(actual: unknown, expected: unknown): boolean {
188
193
  if (Array.isArray(actual) && Array.isArray(expected)) {
189
194
  return actual.length === expected.length && actual.every((v, i) => valuesEqual(v, expected[i]));
190
195
  }
191
- return String(actual) === String(expected);
196
+ if (isPlainObject(actual) && isPlainObject(expected)) {
197
+ const expectedKeys = Object.keys(expected);
198
+ return (
199
+ Object.keys(actual).length === expectedKeys.length &&
200
+ expectedKeys.every(key => valuesEqual(actual[key], expected[key]))
201
+ );
202
+ }
203
+ if (actual.constructor !== expected.constructor) {
204
+ return false;
205
+ }
206
+ if (hasEquals(actual)) {
207
+ return actual.equals(expected);
208
+ }
209
+ const actualStr = customStringForm(actual);
210
+ const expectedStr = customStringForm(expected);
211
+ if (actualStr !== undefined && expectedStr !== undefined) {
212
+ return actualStr === expectedStr;
213
+ }
214
+ // Comparing blindly here could pass vacuously (e.g. two '[object Object]' strings), so refuse instead.
215
+ throw new Error(
216
+ `valuesEqual cannot compare a '${actual.constructor?.name}' against a '${expected.constructor?.name}'. Add a branch for the type.`,
217
+ );
218
+ }
219
+
220
+ function isNonNullObject(value: unknown): value is object {
221
+ return typeof value === 'object' && value !== null;
222
+ }
223
+
224
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
225
+ return isNonNullObject(value) && value.constructor === Object;
226
+ }
227
+
228
+ function hasEquals(value: object): value is { equals(other: unknown): boolean } {
229
+ return typeof (value as { equals?: unknown }).equals === 'function';
230
+ }
231
+
232
+ /** The value's string form when its class overrides `toString` (a meaningful representation), undefined otherwise. */
233
+ function customStringForm(value: object): string | undefined {
234
+ const { toString } = value;
235
+ if (typeof toString !== 'function' || toString === Object.prototype.toString) {
236
+ return undefined;
237
+ }
238
+ return toString.call(value);
192
239
  }
193
240
 
194
241
  function versionBumpHint(oracle: string): string {
@@ -5,7 +5,7 @@ import type { ContractStore } from '@aztec/pxe/server';
5
5
  import { PublicDataWrite } from '@aztec/stdlib/avm';
6
6
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
7
7
  import type { L2Block } from '@aztec/stdlib/block';
8
- import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
8
+ import type { ContractInstancePreimageWithAddress } from '@aztec/stdlib/contract';
9
9
  import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
10
10
  import {
11
11
  MerkleTreeId,
@@ -125,34 +125,36 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
125
125
  return value;
126
126
  }
127
127
 
128
- getContractInstanceDeployer(address: AztecAddress): Promise<{ member: Fr; exists: boolean }> {
128
+ getContractInstanceDeployer(address: AztecAddress): Promise<{ member: Fr; exists: boolean }[]> {
129
129
  return this.getContractInstanceMember(address, i => i.deployer.toField());
130
130
  }
131
131
 
132
- getContractInstanceClassId(address: AztecAddress): Promise<{ member: Fr; exists: boolean }> {
133
- return this.getContractInstanceMember(address, i => i.currentContractClassId);
132
+ getContractInstanceClassId(address: AztecAddress): Promise<{ member: Fr; exists: boolean }[]> {
133
+ // TXE has no contract updates, so the current class always equals the original.
134
+ return this.getContractInstanceMember(address, i => i.originalContractClassId);
134
135
  }
135
136
 
136
- getContractInstanceInitializationHash(address: AztecAddress): Promise<{ member: Fr; exists: boolean }> {
137
+ getContractInstanceInitializationHash(address: AztecAddress): Promise<{ member: Fr; exists: boolean }[]> {
137
138
  return this.getContractInstanceMember(address, i => i.initializationHash);
138
139
  }
139
140
 
140
- getContractInstanceImmutablesHash(address: AztecAddress): Promise<{ member: Fr; exists: boolean }> {
141
+ getContractInstanceImmutablesHash(address: AztecAddress): Promise<{ member: Fr; exists: boolean }[]> {
141
142
  return this.getContractInstanceMember(address, i => i.immutablesHash);
142
143
  }
143
144
 
145
+ // The one-element array mirrors the oracles' Noir return type, `[GetContractInstanceResult; 1]`.
144
146
  private async getContractInstanceMember(
145
147
  address: AztecAddress,
146
- accessor: (instance: ContractInstanceWithAddress) => Fr,
147
- ): Promise<{ member: Fr; exists: boolean }> {
148
+ accessor: (instance: ContractInstancePreimageWithAddress) => Fr,
149
+ ): Promise<{ member: Fr; exists: boolean }[]> {
148
150
  const instance = await this.contractStore.getContractInstance(address);
149
151
  if (!instance) {
150
- return { member: Fr.ZERO, exists: false };
152
+ return [{ member: Fr.ZERO, exists: false }];
151
153
  }
152
- return { member: accessor(instance), exists: true };
154
+ return [{ member: accessor(instance), exists: true }];
153
155
  }
154
156
 
155
- returndataSize(): Promise<Fr> {
157
+ returndataSize(): Promise<number> {
156
158
  throw new Error(
157
159
  'Contract calls are forbidden inside a `TestEnvironment::public_context`, use `public_call` instead',
158
160
  );
@@ -19,17 +19,21 @@ import {
19
19
  BOOL,
20
20
  ETH_ADDRESS,
21
21
  FIELD,
22
+ FIXED_ARRAY,
22
23
  FUNCTION_SELECTOR,
23
24
  type InputSlot,
24
25
  type MaybePromise,
25
26
  OPTION,
26
27
  ORACLE_REGISTRY,
27
28
  type OracleRegistryEntry,
29
+ type OutputSlot,
28
30
  type ParamTypes,
29
31
  STR,
32
+ STRUCT,
30
33
  type SlotShape,
31
34
  type TypeMapping,
32
35
  U32,
36
+ buildACIRCallback,
33
37
  makeEntry,
34
38
  } from '@aztec/pxe/simulator';
35
39
  import { EventSelector } from '@aztec/stdlib/abi';
@@ -63,11 +67,12 @@ const GAS_SETTINGS: TypeMapping<GasSettings> = {
63
67
  };
64
68
 
65
69
  // Tagging secret strategy discriminants. Must match the Noir test helper `TaggingSecretStrategy` in
66
- // aztec-nr `test/helpers/tagging_secret_strategy.nr`. This is a test-only oracle (only `set_tagging_secret_strategy`
70
+ // aztec-nr `test/helpers/tagging_secret_strategy.nr`. This is a test-only oracle (only `set_tagging_secret_strategies`
67
71
  // reads it), so the mapping lives here on the TXE side rather than in the production oracle type mappings.
68
72
  const STRATEGY_NON_INTERACTIVE_HANDSHAKE = 1;
69
73
  const STRATEGY_ARBITRARY_SECRET = 2;
70
74
  const STRATEGY_ADDRESS_DERIVED = 3;
75
+ const STRATEGY_INTERACTIVE_HANDSHAKE = 4;
71
76
 
72
77
  const TAGGING_SECRET_STRATEGY: TypeMapping<TaggingSecretStrategy> = {
73
78
  serialization: {
@@ -75,6 +80,8 @@ const TAGGING_SECRET_STRATEGY: TypeMapping<TaggingSecretStrategy> = {
75
80
  switch (strategy.type) {
76
81
  case 'non-interactive-handshake':
77
82
  return [new Fr(STRATEGY_NON_INTERACTIVE_HANDSHAKE), Fr.ZERO, Fr.ZERO];
83
+ case 'interactive-handshake':
84
+ return [new Fr(STRATEGY_INTERACTIVE_HANDSHAKE), Fr.ZERO, Fr.ZERO];
78
85
  case 'address-derived':
79
86
  return [new Fr(STRATEGY_ADDRESS_DERIVED), Fr.ZERO, Fr.ZERO];
80
87
  case 'arbitrary-secret':
@@ -89,6 +96,8 @@ const TAGGING_SECRET_STRATEGY: TypeMapping<TaggingSecretStrategy> = {
89
96
  switch (kind) {
90
97
  case STRATEGY_NON_INTERACTIVE_HANDSHAKE:
91
98
  return { type: 'non-interactive-handshake' };
99
+ case STRATEGY_INTERACTIVE_HANDSHAKE:
100
+ return { type: 'interactive-handshake' };
92
101
  case STRATEGY_ADDRESS_DERIVED:
93
102
  return { type: 'address-derived' };
94
103
  case STRATEGY_ARBITRARY_SECRET:
@@ -191,10 +200,13 @@ const TXE_CALL_CONTEXT: TypeMapping<{ txHash: Fr; anchorBlockTimestamp: bigint }
191
200
  shape: ['scalar', 'scalar', 'scalar'], // discriminant, txHash, anchor block timestamp
192
201
  };
193
202
 
194
- const CONTRACT_INSTANCE_MEMBER: TypeMapping<{ member: Fr; exists: boolean }> = {
195
- serialization: { fn: ({ member, exists }) => [member, new Fr(exists)] },
196
- shape: ['scalar', 'scalar'],
197
- };
203
+ const CONTRACT_INSTANCE_MEMBER: TypeMapping<{ exists: boolean; member: Fr }[]> = FIXED_ARRAY(
204
+ STRUCT([
205
+ { name: 'exists', type: BOOL },
206
+ { name: 'member', type: FIELD },
207
+ ]),
208
+ 1,
209
+ );
198
210
 
199
211
  const EVENT_SELECTOR: TypeMapping<EventSelector> = {
200
212
  serialization: { fn: v => [v.toField()] },
@@ -308,8 +320,15 @@ export const TXE_ORACLE_REGISTRY = {
308
320
  returnType: FIELD,
309
321
  }),
310
322
 
311
- aztec_txe_setTaggingSecretStrategy: makeEntry({
312
- params: [{ name: 'strategy', type: OPTION(TAGGING_SECRET_STRATEGY) }],
323
+ aztec_txe_setTaggingSecretStrategies: makeEntry({
324
+ params: [
325
+ { name: 'unconstrainedStrategy', type: OPTION(TAGGING_SECRET_STRATEGY) },
326
+ { name: 'constrainedStrategy', type: OPTION(TAGGING_SECRET_STRATEGY) },
327
+ ],
328
+ }),
329
+
330
+ aztec_txe_setAuthorizeAllUtilityCallTargets: makeEntry({
331
+ params: [{ name: 'authorizeAll', type: BOOL }],
313
332
  }),
314
333
 
315
334
  aztec_txe_getLastBlockTimestamp: makeEntry({
@@ -412,7 +431,7 @@ export const TXE_ORACLE_REGISTRY = {
412
431
  params: [{ name: 'message', type: ARRAY(FIELD) }],
413
432
  }),
414
433
 
415
- aztec_avm_returndataSize: makeEntry({ returnType: FIELD }),
434
+ aztec_avm_returndataSize: makeEntry({ returnType: U32 }),
416
435
 
417
436
  aztec_avm_returndataCopy: makeEntry({
418
437
  params: [
@@ -487,7 +506,37 @@ export async function callTxeHandler<K extends keyof typeof TXE_ORACLE_REGISTRY>
487
506
  const named = entry.deserializeParams(toInputSlots(inputs));
488
507
  const positional = named.map((p: { value: unknown }) => p.value);
489
508
  const result = await handler(positional as any);
490
- const outputSlots = entry.serializeReturn(result);
509
+ return outputSlotsToForeignCallResult(entry.serializeReturn(result));
510
+ }
511
+
512
+ /**
513
+ * Dispatches an oracle that has been retired into the PXE legacy registry. TXE has no explicit handler method for such
514
+ * names; this runs them through the same `buildACIRCallback` legacy path that contract execution already uses, so
515
+ * TXE's top-level oracle path and its in-contract path treat the legacy registry identically.
516
+ */
517
+ const legacyCallbacksByHandler = new WeakMap<object, ReturnType<typeof buildACIRCallback>>();
518
+
519
+ export async function callTxeLegacyHandler(
520
+ oracle: string,
521
+ inputs: ForeignCallArgs,
522
+ oracleHandler: Parameters<typeof buildACIRCallback>[0],
523
+ ): Promise<ForeignCallResult> {
524
+ // `buildACIRCallback` materializes the whole real+legacy closure set, so memoize it per handler rather than
525
+ // rebuilding on every call (TXE routes one legacy oracle through here on each top-level discovery).
526
+ let callback = legacyCallbacksByHandler.get(oracleHandler);
527
+ if (!callback) {
528
+ callback = buildACIRCallback(oracleHandler);
529
+ legacyCallbacksByHandler.set(oracleHandler, callback);
530
+ }
531
+ const outputSlots = await callback[oracle](...toInputSlots(inputs));
532
+ return outputSlotsToForeignCallResult(outputSlots);
533
+ }
534
+
535
+ /**
536
+ * Strips the `0x` prefix from each serialized output slot (TXE foreign calls use bare hex strings) and wraps them in a
537
+ * `ForeignCallResult`.
538
+ */
539
+ function outputSlotsToForeignCallResult(outputSlots: OutputSlot[]): ForeignCallResult {
491
540
  return {
492
541
  values: outputSlots.map(slot => (Array.isArray(slot) ? slot.map(withoutHexPrefix) : withoutHexPrefix(slot))),
493
542
  };
@@ -12,6 +12,7 @@ import { TestDateProvider } from '@aztec/foundation/timer';
12
12
  import type { KeyStore } from '@aztec/key-store';
13
13
  import {
14
14
  AddressStore,
15
+ AnchoredContractData,
15
16
  CapsuleService,
16
17
  CapsuleStore,
17
18
  type ContractStore,
@@ -70,7 +71,9 @@ import {
70
71
  PrivateToPublicAccumulatedData,
71
72
  PublicCallRequest,
72
73
  } from '@aztec/stdlib/kernel';
73
- import { hashPublicKey } from '@aztec/stdlib/keys';
74
+ import { deriveKeys, hashPublicKey } from '@aztec/stdlib/keys';
75
+ import type { PrivateLog } from '@aztec/stdlib/logs';
76
+ import { AppTaggingSecretKind } from '@aztec/stdlib/logs';
74
77
  import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/stdlib/messaging';
75
78
  import { ChonkProof } from '@aztec/stdlib/proofs';
76
79
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
@@ -97,6 +100,7 @@ import type { TXEAccountStore } from '../utils/txe_account_store.js';
97
100
  import type { TXEArtifactResolver } from '../utils/txe_artifact_resolver.js';
98
101
  import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
99
102
  import type { ITxeExecutionOracle } from './interfaces.js';
103
+ import { type TXETaggingSecretStrategies, makeResolveTaggingSecretStrategyHook } from './tagging_secret_strategy.js';
100
104
 
101
105
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
102
106
  isMisc = true as const;
@@ -121,7 +125,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
121
125
  private version: Fr,
122
126
  private chainId: Fr,
123
127
  private authwits: Map<string, AuthWitness>,
124
- private taggingSecretStrategy: TaggingSecretStrategy | undefined,
128
+ private taggingSecretStrategies: TXETaggingSecretStrategies,
129
+ private authorizeAllUtilityCallTargets: boolean,
125
130
  private readonly artifactResolver: TXEArtifactResolver,
126
131
  private readonly rootPath: string,
127
132
  private readonly packageName: string,
@@ -183,7 +188,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
183
188
  return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
184
189
  }
185
190
 
186
- async getLastTxEffects() {
191
+ async getLastTxEffects(): Promise<{ txHash: TxHash; noteHashes: Fr[]; nullifiers: Fr[]; privateLogs: PrivateLog[] }> {
187
192
  const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
188
193
  const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
189
194
 
@@ -323,7 +328,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
323
328
  await this.contractStore.addContractInstance(instance);
324
329
  await this.contractStore.addContractArtifact(artifact);
325
330
 
326
- const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
331
+ const completeAddress = await this.keyStore.addAccount(await deriveKeys(secret), partialAddress);
327
332
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
328
333
  await this.addressStore.addCompleteAddress(completeAddress);
329
334
  this.logger.debug(`Created account ${completeAddress.address}`);
@@ -333,7 +338,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
333
338
 
334
339
  async createAccount(secret: Fr) {
335
340
  // This is a foot gun !
336
- const completeAddress = await this.keyStore.addAccount(secret, secret);
341
+ const completeAddress = await this.keyStore.addAccount(await deriveKeys(secret), secret);
337
342
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
338
343
  await this.addressStore.addCompleteAddress(completeAddress);
339
344
  this.logger.debug(`Created account ${completeAddress.address}`);
@@ -354,8 +359,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
354
359
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
355
360
  }
356
361
 
357
- setTaggingSecretStrategy(strategy: Option<TaggingSecretStrategy>): void {
358
- this.taggingSecretStrategy = strategy.value;
362
+ setTaggingSecretStrategies(
363
+ unconstrainedStrategy: Option<TaggingSecretStrategy>,
364
+ constrainedStrategy: Option<TaggingSecretStrategy>,
365
+ ): void {
366
+ const apply = (mode: AppTaggingSecretKind, strategy: Option<TaggingSecretStrategy>) => {
367
+ if (strategy.isSome()) {
368
+ this.taggingSecretStrategies.set(mode, strategy.value);
369
+ } else {
370
+ this.taggingSecretStrategies.delete(mode);
371
+ }
372
+ };
373
+ apply(AppTaggingSecretKind.UNCONSTRAINED, unconstrainedStrategy);
374
+ apply(AppTaggingSecretKind.CONSTRAINED, constrainedStrategy);
375
+ }
376
+
377
+ setAuthorizeAllUtilityCallTargets(authorizeAll: boolean): void {
378
+ this.authorizeAllUtilityCallTargets = authorizeAll;
359
379
  }
360
380
 
361
381
  async sendL1ToL2Message(content: Fr, secretHash: Fr, sender: EthAddress, recipient: AztecAddress): Promise<Fr> {
@@ -415,11 +435,18 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
415
435
  authorizedUtilityCallTargets: AztecAddress[],
416
436
  gasSettings: GasSettings,
417
437
  ) {
438
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
439
+ const anchoredContractData = new AnchoredContractData(
440
+ this.contractStore,
441
+ this.stateMachine.contractClassService,
442
+ blockHeader,
443
+ );
444
+
418
445
  this.logger.verbose(
419
- `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
446
+ `Executing external function ${await anchoredContractData.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
420
447
  );
421
448
 
422
- const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
449
+ const artifact = await anchoredContractData.getFunctionArtifact(targetContractAddress, functionSelector);
423
450
  if (!artifact) {
424
451
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
425
452
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -434,7 +461,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
434
461
  await this.executeUtilityCall(call, { scopes: execScopes, jobId });
435
462
  };
436
463
 
437
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
438
464
  await this.stateMachine.contractSyncService.ensureContractSynced(
439
465
  targetContractAddress,
440
466
  functionSelector,
@@ -463,10 +489,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
463
489
  const simulator = new WASMSimulator();
464
490
 
465
491
  const transientArrayService = new TransientArrayService();
466
- const taggingSecretStrategy = this.taggingSecretStrategy;
467
492
  const privateExecutionOracle = new PrivateExecutionOracle({
468
493
  argsHash,
469
494
  txContext,
495
+ // The TXE does not run the init kernel's salt binding, so no tx-request salt is in scope.
496
+ txRequestSalt: Fr.ZERO,
470
497
  callContext,
471
498
  anchorBlockHeader: blockHeader,
472
499
  utilityExecutor,
@@ -475,7 +502,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
475
502
  executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
476
503
  noteCache,
477
504
  taggingIndexCache,
478
- contractStore: this.contractStore,
505
+ anchoredContractData,
479
506
  noteStore: this.noteStore,
480
507
  keyStore: this.keyStore,
481
508
  addressStore: this.addressStore,
@@ -502,9 +529,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
502
529
  isStaticCall ? 'private view' : 'private',
503
530
  authorizedUtilityCallTargets,
504
531
  ),
505
- // Only configure the hook when a strategy was explicitly set, so that otherwise the default tagging secret
506
- // strategy is exercised.
507
- resolveTaggingSecretStrategy: taggingSecretStrategy ? () => Promise.resolve(taggingSecretStrategy) : undefined,
532
+ resolveTaggingSecretStrategy: makeResolveTaggingSecretStrategyHook(this.taggingSecretStrategies),
508
533
  }),
509
534
  transientArrayService,
510
535
  });
@@ -534,7 +559,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
534
559
  }),
535
560
  );
536
561
 
537
- noteCache.finish();
538
562
  const nonceGenerator = noteCache.getNonceGenerator();
539
563
  result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
540
564
  } catch (err) {
@@ -546,7 +570,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
546
570
  // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
547
571
  const { publicInputs } = await generateSimulatedProvingResult(
548
572
  result,
549
- (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
573
+ (addr, sel) => anchoredContractData.getDebugFunctionName(addr, sel),
550
574
  this.stateMachine.node,
551
575
  minRevertibleSideEffectCounter,
552
576
  );
@@ -605,7 +629,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
605
629
  } else if (!processedTx.revertCode.isOK()) {
606
630
  if (processedTx.revertReason) {
607
631
  try {
608
- await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
632
+ await enrichPublicSimulationError(
633
+ processedTx.revertReason,
634
+ this.contractStore,
635
+ this.stateMachine.contractClassService,
636
+ await this.stateMachine.anchorBlockStore.getBlockHeader(),
637
+ this.logger,
638
+ );
609
639
  // eslint-disable-next-line no-empty
610
640
  } catch {}
611
641
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -656,16 +686,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
656
686
  isStaticCall: boolean,
657
687
  gasSettings: GasSettings,
658
688
  ) {
689
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
690
+ const anchoredContractData = new AnchoredContractData(
691
+ this.contractStore,
692
+ this.stateMachine.contractClassService,
693
+ anchorBlockHeader,
694
+ );
695
+
659
696
  this.logger.verbose(
660
- `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
697
+ `Executing public function ${await anchoredContractData.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
661
698
  );
662
699
 
663
700
  const blockNumber = await this.getNextBlockNumber();
664
701
 
665
702
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
666
703
 
667
- const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
668
-
669
704
  const calldataHash = await computeCalldataHash(calldata);
670
705
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
671
706
 
@@ -758,7 +793,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
758
793
  } else if (!processedTx.revertCode.isOK()) {
759
794
  if (processedTx.revertReason) {
760
795
  try {
761
- await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
796
+ await enrichPublicSimulationError(
797
+ processedTx.revertReason,
798
+ this.contractStore,
799
+ this.stateMachine.contractClassService,
800
+ anchorBlockHeader,
801
+ this.logger,
802
+ );
762
803
  // eslint-disable-next-line no-empty
763
804
  } catch {}
764
805
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -807,13 +848,19 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
807
848
  jobId: string,
808
849
  authorizedUtilityCallTargets: AztecAddress[],
809
850
  ) {
810
- const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
851
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
852
+ const anchoredContractData = new AnchoredContractData(
853
+ this.contractStore,
854
+ this.stateMachine.contractClassService,
855
+ blockHeader,
856
+ );
857
+
858
+ const artifact = await anchoredContractData.getFunctionArtifact(targetContractAddress, functionSelector);
811
859
  if (!artifact) {
812
860
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
813
861
  }
814
862
 
815
863
  // Sync notes before executing utility function to discover notes from previous transactions
816
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
817
864
  await this.stateMachine.contractSyncService.ensureContractSynced(
818
865
  targetContractAddress,
819
866
  functionSelector,
@@ -853,7 +900,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
853
900
  authorizedUtilityCallTargets = [],
854
901
  }: { from?: AztecAddress; scopes: AztecAddress[]; jobId: string; authorizedUtilityCallTargets?: AztecAddress[] },
855
902
  ): Promise<Fr[]> {
856
- const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
903
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
904
+ const anchoredContractData = new AnchoredContractData(
905
+ this.contractStore,
906
+ this.stateMachine.contractClassService,
907
+ anchorBlockHeader,
908
+ );
909
+
910
+ const entryPointArtifact = await anchoredContractData.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
911
+ if (!entryPointArtifact) {
912
+ throw new Error(`Cannot run function ${call.selector} on ${call.to}: the contract is not registered.`);
913
+ }
857
914
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
858
915
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
859
916
  }
@@ -864,10 +921,9 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
864
921
  });
865
922
 
866
923
  try {
867
- const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
868
924
  const simulator = new WASMSimulator();
869
925
  const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
870
- await this.executeUtilityCall(syncCall, { scopes: execScopes, jobId });
926
+ await this.executeUtilityCall(syncCall, { scopes: execScopes, jobId, authorizedUtilityCallTargets });
871
927
  };
872
928
  const oracle = new UtilityExecutionOracle({
873
929
  callContext: CallContext.from({
@@ -879,7 +935,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
879
935
  authWitnesses: [],
880
936
  capsules: [],
881
937
  anchorBlockHeader,
882
- contractStore: this.contractStore,
938
+ anchoredContractData,
883
939
  noteStore: this.noteStore,
884
940
  keyStore: this.keyStore,
885
941
  addressStore: this.addressStore,
@@ -895,10 +951,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
895
951
  jobId,
896
952
  scopes,
897
953
  simulator,
954
+ utilityExecutor,
898
955
  hooks: composeHooks({
899
956
  authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
900
957
  }),
901
- utilityExecutor,
902
958
  // Execution-tree root (top-level utility run or contract sync): own store; nested frames inherit it.
903
959
  transientArrayService: new TransientArrayService(),
904
960
  });
@@ -924,9 +980,19 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
924
980
  }
925
981
  }
926
982
 
927
- close(): [bigint, Map<string, AuthWitness>, TaggingSecretStrategy | undefined] {
983
+ close(): {
984
+ nextBlockTimestamp: bigint;
985
+ authwits: Map<string, AuthWitness>;
986
+ taggingSecretStrategies: TXETaggingSecretStrategies;
987
+ authorizeAllUtilityCallTargets: boolean;
988
+ } {
928
989
  this.logger.debug('Exiting Top Level Context');
929
- return [this.nextBlockTimestamp, this.authwits, this.taggingSecretStrategy];
990
+ return {
991
+ nextBlockTimestamp: this.nextBlockTimestamp,
992
+ authwits: this.authwits,
993
+ taggingSecretStrategies: this.taggingSecretStrategies,
994
+ authorizeAllUtilityCallTargets: this.authorizeAllUtilityCallTargets,
995
+ };
930
996
  }
931
997
 
932
998
  private async getLastBlockNumber(): Promise<BlockNumber> {
@@ -938,6 +1004,9 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
938
1004
  callerContext: 'private' | 'private view' | 'utility',
939
1005
  authorizedTargets: AztecAddress[],
940
1006
  ): ExecutionHooks['authorizeUtilityCall'] | undefined {
1007
+ if (this.authorizeAllUtilityCallTargets) {
1008
+ return authorizeAllUtilityCallsHook;
1009
+ }
941
1010
  if (authorizedTargets.length === 0) {
942
1011
  return undefined;
943
1012
  }
@@ -947,3 +1016,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
947
1016
  });
948
1017
  }
949
1018
  }
1019
+
1020
+ /**
1021
+ * An `authorizeUtilityCall` hook that authorizes every cross-contract utility call.
1022
+ *
1023
+ * Backs the `aztec_txe_setAuthorizeAllUtilityCallTargets` oracle.
1024
+ */
1025
+ export const authorizeAllUtilityCallsHook: NonNullable<ExecutionHooks['authorizeUtilityCall']> = () =>
1026
+ Promise.resolve({ authorized: true });
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * The Noir counterparts are in `noir-projects/aztec-nr/aztec/src/test/helpers/txe_oracles.nr`.
7
7
  */
8
- export const TXE_ORACLE_VERSION_MAJOR = 2;
9
- export const TXE_ORACLE_VERSION_MINOR = 2;
8
+ export const TXE_ORACLE_VERSION_MAJOR = 3;
9
+ export const TXE_ORACLE_VERSION_MINOR = 1;
10
10
 
11
11
  /**
12
12
  * This hash is computed from the TXE oracle interfaces (IAvmExecutionOracle and ITxeExecutionOracle) and is used to
@@ -14,4 +14,4 @@ export const TXE_ORACLE_VERSION_MINOR = 2;
14
14
  * - TXE_ORACLE_VERSION_MAJOR (and reset MINOR to 0) for breaking changes, or
15
15
  * - TXE_ORACLE_VERSION_MINOR for additive changes (new oracle method added).
16
16
  */
17
- export const TXE_ORACLE_INTERFACE_HASH = '118698345ea9d368ca82ea574a051e72f4df0b85454539ade14838a934976b62';
17
+ export const TXE_ORACLE_INTERFACE_HASH = '89c60f191f8f60ef72d592e46dd6c4afff10dc47a9e14f4f8d37e31e40857d9c';