@aztec/pxe 0.0.1-commit.b64cb54f6 → 0.0.1-commit.b6e433891
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.
- package/dest/contract_function_simulator/contract_function_simulator.d.ts +6 -3
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +21 -3
- package/dest/contract_function_simulator/oracle/interfaces.d.ts +3 -2
- package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts +1 -1
- package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.js +22 -32
- package/dest/contract_function_simulator/oracle/oracle.d.ts +3 -2
- package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/oracle.js +25 -4
- package/dest/contract_function_simulator/oracle/private_execution.js +3 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -12
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.js +0 -14
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +14 -2
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +22 -0
- package/dest/contract_sync/contract_sync_service.d.ts +5 -3
- package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
- package/dest/contract_sync/contract_sync_service.js +47 -30
- package/dest/oracle_version.d.ts +2 -2
- package/dest/oracle_version.js +2 -2
- package/dest/pxe.d.ts +5 -3
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +19 -10
- package/package.json +16 -16
- package/src/contract_function_simulator/contract_function_simulator.ts +30 -4
- package/src/contract_function_simulator/oracle/interfaces.ts +2 -1
- package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +103 -45
- package/src/contract_function_simulator/oracle/oracle.ts +25 -4
- package/src/contract_function_simulator/oracle/private_execution.ts +1 -1
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +0 -17
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +27 -1
- package/src/contract_sync/contract_sync_service.ts +67 -38
- package/src/oracle_version.ts +2 -2
- package/src/pxe.ts +39 -12
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
MAX_NULLIFIERS_PER_TX,
|
|
18
18
|
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
19
19
|
MAX_PRIVATE_LOGS_PER_TX,
|
|
20
|
+
MAX_TX_LIFETIME,
|
|
20
21
|
PRIVATE_TX_L2_GAS_OVERHEAD,
|
|
21
22
|
PUBLIC_TX_L2_GAS_OVERHEAD,
|
|
22
23
|
TX_DA_GAS_OVERHEAD,
|
|
@@ -79,6 +80,7 @@ import {
|
|
|
79
80
|
BlockHeader,
|
|
80
81
|
CallContext,
|
|
81
82
|
HashedValues,
|
|
83
|
+
type OffchainEffect,
|
|
82
84
|
PrivateExecutionResult,
|
|
83
85
|
TxConstantData,
|
|
84
86
|
TxExecutionRequest,
|
|
@@ -319,7 +321,7 @@ export class ContractFunctionSimulator {
|
|
|
319
321
|
anchorBlockHeader: BlockHeader,
|
|
320
322
|
scopes: AccessScopes,
|
|
321
323
|
jobId: string,
|
|
322
|
-
): Promise<Fr[]> {
|
|
324
|
+
): Promise<{ result: Fr[]; offchainEffects: OffchainEffect[] }> {
|
|
323
325
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
324
326
|
|
|
325
327
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
@@ -341,6 +343,7 @@ export class ContractFunctionSimulator {
|
|
|
341
343
|
capsuleStore: this.capsuleStore,
|
|
342
344
|
privateEventStore: this.privateEventStore,
|
|
343
345
|
messageContextService: this.messageContextService,
|
|
346
|
+
contractSyncService: this.contractSyncService,
|
|
344
347
|
jobId,
|
|
345
348
|
scopes,
|
|
346
349
|
});
|
|
@@ -368,7 +371,10 @@ export class ContractFunctionSimulator {
|
|
|
368
371
|
});
|
|
369
372
|
|
|
370
373
|
this.log.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
371
|
-
return
|
|
374
|
+
return {
|
|
375
|
+
result: witnessMapToFields(acirExecutionResult.returnWitness),
|
|
376
|
+
offchainEffects: oracle.getOffchainEffects(),
|
|
377
|
+
};
|
|
372
378
|
} catch (err) {
|
|
373
379
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
374
380
|
}
|
|
@@ -438,14 +444,34 @@ export async function generateSimulatedProvingResult(
|
|
|
438
444
|
|
|
439
445
|
let publicTeardownCallRequest;
|
|
440
446
|
|
|
447
|
+
// We set expiration timestamp to anchor_block_timestamp + MAX_TX_LIFETIME (24h) just like kernels do
|
|
448
|
+
let expirationTimestamp =
|
|
449
|
+
privateExecutionResult.entrypoint.publicInputs.anchorBlockHeader.globalVariables.timestamp +
|
|
450
|
+
BigInt(MAX_TX_LIFETIME);
|
|
451
|
+
|
|
452
|
+
let feePayer = AztecAddress.zero();
|
|
453
|
+
|
|
441
454
|
const executions = [privateExecutionResult.entrypoint];
|
|
442
455
|
|
|
443
456
|
while (executions.length !== 0) {
|
|
444
457
|
const execution = executions.shift()!;
|
|
445
458
|
executions.unshift(...execution!.nestedExecutionResults);
|
|
446
459
|
|
|
460
|
+
// Just like kernels we overwrite the default value if the call sets it.
|
|
461
|
+
const callExpirationTimestamp = execution.publicInputs.expirationTimestamp;
|
|
462
|
+
if (callExpirationTimestamp !== 0n && callExpirationTimestamp < expirationTimestamp) {
|
|
463
|
+
expirationTimestamp = callExpirationTimestamp;
|
|
464
|
+
}
|
|
465
|
+
|
|
447
466
|
const { contractAddress } = execution.publicInputs.callContext;
|
|
448
467
|
|
|
468
|
+
if (execution.publicInputs.isFeePayer) {
|
|
469
|
+
if (!feePayer.isZero()) {
|
|
470
|
+
throw new Error('Multiple fee payers found in private execution result');
|
|
471
|
+
}
|
|
472
|
+
feePayer = contractAddress;
|
|
473
|
+
}
|
|
474
|
+
|
|
449
475
|
scopedNoteHashes.push(
|
|
450
476
|
...execution.publicInputs.noteHashes
|
|
451
477
|
.getActiveItems()
|
|
@@ -666,8 +692,8 @@ export async function generateSimulatedProvingResult(
|
|
|
666
692
|
daGas: TX_DA_GAS_OVERHEAD,
|
|
667
693
|
}),
|
|
668
694
|
),
|
|
669
|
-
/*feePayer=*/
|
|
670
|
-
/*expirationTimestamp=*/
|
|
695
|
+
/*feePayer=*/ feePayer,
|
|
696
|
+
/*expirationTimestamp=*/ expirationTimestamp,
|
|
671
697
|
hasPublicCalls ? inputsForPublic : undefined,
|
|
672
698
|
!hasPublicCalls ? inputsForRollup : undefined,
|
|
673
699
|
);
|
|
@@ -143,6 +143,8 @@ export interface IUtilityExecutionOracle {
|
|
|
143
143
|
copyCapsule(contractAddress: AztecAddress, srcKey: Fr, dstKey: Fr, numEntries: number): Promise<void>;
|
|
144
144
|
aes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer>;
|
|
145
145
|
getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point>;
|
|
146
|
+
invalidateContractSyncCache(contractAddress: AztecAddress, scopes: AztecAddress[]): void;
|
|
147
|
+
emitOffchainEffect(data: Fr[]): Promise<void>;
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
/**
|
|
@@ -180,5 +182,4 @@ export interface IPrivateExecutionOracle {
|
|
|
180
182
|
getSenderForTags(): Promise<AztecAddress | undefined>;
|
|
181
183
|
setSenderForTags(senderForTags: AztecAddress): Promise<void>;
|
|
182
184
|
getNextAppTagAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<Tag>;
|
|
183
|
-
emitOffchainEffect(data: Fr[]): Promise<void>;
|
|
184
185
|
}
|
|
@@ -11,39 +11,101 @@ import type { Oracle } from './oracle.js';
|
|
|
11
11
|
export function buildLegacyOracleCallbacks(oracle: Oracle): ACIRCallback {
|
|
12
12
|
return {
|
|
13
13
|
// Simple prefix renames (privateXxx/utilityXxx → aztec_prv_/aztec_utl_)
|
|
14
|
-
utilityLog: (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
oracle.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
14
|
+
utilityLog: (
|
|
15
|
+
level: ACVMField[],
|
|
16
|
+
message: ACVMField[],
|
|
17
|
+
_ignoredFieldsSize: ACVMField[],
|
|
18
|
+
fields: ACVMField[],
|
|
19
|
+
): Promise<ACVMField[]> => oracle.aztec_utl_log(level, message, _ignoredFieldsSize, fields),
|
|
20
|
+
utilityAssertCompatibleOracleVersion: (version: ACVMField[]): Promise<ACVMField[]> =>
|
|
21
|
+
oracle.aztec_utl_assertCompatibleOracleVersion(version),
|
|
22
|
+
utilityLoadCapsule: (
|
|
23
|
+
contractAddress: ACVMField[],
|
|
24
|
+
slot: ACVMField[],
|
|
25
|
+
tSize: ACVMField[],
|
|
26
|
+
): Promise<(ACVMField | ACVMField[])[]> => oracle.aztec_utl_loadCapsule(contractAddress, slot, tSize),
|
|
27
|
+
privateStoreInExecutionCache: (values: ACVMField[], hash: ACVMField[]): Promise<ACVMField[]> =>
|
|
28
|
+
oracle.aztec_prv_storeInExecutionCache(values, hash),
|
|
29
|
+
privateLoadFromExecutionCache: (returnsHash: ACVMField[]): Promise<ACVMField[][]> =>
|
|
30
|
+
oracle.aztec_prv_loadFromExecutionCache(returnsHash),
|
|
31
|
+
privateCallPrivateFunction: (
|
|
32
|
+
contractAddress: ACVMField[],
|
|
33
|
+
functionSelector: ACVMField[],
|
|
34
|
+
argsHash: ACVMField[],
|
|
35
|
+
sideEffectCounter: ACVMField[],
|
|
36
|
+
isStaticCall: ACVMField[],
|
|
37
|
+
): Promise<ACVMField[][]> =>
|
|
38
|
+
oracle.aztec_prv_callPrivateFunction(
|
|
39
|
+
contractAddress,
|
|
40
|
+
functionSelector,
|
|
41
|
+
argsHash,
|
|
42
|
+
sideEffectCounter,
|
|
43
|
+
isStaticCall,
|
|
44
|
+
),
|
|
45
|
+
privateIsNullifierPending: (innerNullifier: ACVMField[], contractAddress: ACVMField[]): Promise<ACVMField[]> =>
|
|
46
|
+
oracle.aztec_prv_isNullifierPending(innerNullifier, contractAddress),
|
|
47
|
+
privateNotifyCreatedNullifier: (innerNullifier: ACVMField[]): Promise<ACVMField[]> =>
|
|
48
|
+
oracle.aztec_prv_notifyCreatedNullifier(innerNullifier),
|
|
49
|
+
privateNotifyCreatedContractClassLog: (
|
|
50
|
+
contractAddress: ACVMField[],
|
|
51
|
+
message: ACVMField[],
|
|
52
|
+
length: ACVMField[],
|
|
53
|
+
counter: ACVMField[],
|
|
54
|
+
): Promise<ACVMField[]> =>
|
|
55
|
+
oracle.aztec_prv_notifyCreatedContractClassLog(contractAddress, message, length, counter),
|
|
56
|
+
utilityGetUtilityContext: (): Promise<(ACVMField | ACVMField[])[]> => oracle.aztec_utl_getUtilityContext(),
|
|
57
|
+
utilityStorageRead: (
|
|
58
|
+
blockHash: ACVMField[],
|
|
59
|
+
contractAddress: ACVMField[],
|
|
60
|
+
startStorageSlot: ACVMField[],
|
|
61
|
+
numberOfElements: ACVMField[],
|
|
62
|
+
): Promise<ACVMField[][]> =>
|
|
63
|
+
oracle.aztec_utl_storageRead(blockHash, contractAddress, startStorageSlot, numberOfElements),
|
|
64
|
+
utilityStoreCapsule: (
|
|
65
|
+
contractAddress: ACVMField[],
|
|
66
|
+
slot: ACVMField[],
|
|
67
|
+
capsule: ACVMField[],
|
|
68
|
+
): Promise<ACVMField[]> => oracle.aztec_utl_storeCapsule(contractAddress, slot, capsule),
|
|
69
|
+
utilityCopyCapsule: (
|
|
70
|
+
contractAddress: ACVMField[],
|
|
71
|
+
srcSlot: ACVMField[],
|
|
72
|
+
dstSlot: ACVMField[],
|
|
73
|
+
numEntries: ACVMField[],
|
|
74
|
+
): Promise<ACVMField[]> => oracle.aztec_utl_copyCapsule(contractAddress, srcSlot, dstSlot, numEntries),
|
|
75
|
+
utilityDeleteCapsule: (contractAddress: ACVMField[], slot: ACVMField[]): Promise<ACVMField[]> =>
|
|
76
|
+
oracle.aztec_utl_deleteCapsule(contractAddress, slot),
|
|
77
|
+
utilityGetSharedSecret: (
|
|
78
|
+
address: ACVMField[],
|
|
79
|
+
ephPKField0: ACVMField[],
|
|
80
|
+
ephPKField1: ACVMField[],
|
|
81
|
+
ephPKField2: ACVMField[],
|
|
82
|
+
): Promise<ACVMField[]> => oracle.aztec_utl_getSharedSecret(address, ephPKField0, ephPKField1, ephPKField2),
|
|
83
|
+
utilityFetchTaggedLogs: (pendingTaggedLogArrayBaseSlot: ACVMField[]): Promise<ACVMField[]> =>
|
|
84
|
+
oracle.aztec_utl_fetchTaggedLogs(pendingTaggedLogArrayBaseSlot),
|
|
85
|
+
utilityBulkRetrieveLogs: (
|
|
86
|
+
contractAddress: ACVMField[],
|
|
87
|
+
logRetrievalRequestsArrayBaseSlot: ACVMField[],
|
|
88
|
+
logRetrievalResponsesArrayBaseSlot: ACVMField[],
|
|
89
|
+
): Promise<ACVMField[]> =>
|
|
90
|
+
oracle.aztec_utl_bulkRetrieveLogs(
|
|
91
|
+
contractAddress,
|
|
92
|
+
logRetrievalRequestsArrayBaseSlot,
|
|
93
|
+
logRetrievalResponsesArrayBaseSlot,
|
|
94
|
+
),
|
|
95
|
+
utilityGetL1ToL2MembershipWitness: (
|
|
96
|
+
contractAddress: ACVMField[],
|
|
97
|
+
messageHash: ACVMField[],
|
|
98
|
+
secret: ACVMField[],
|
|
99
|
+
): Promise<(ACVMField | ACVMField[])[]> =>
|
|
100
|
+
oracle.aztec_utl_getL1ToL2MembershipWitness(contractAddress, messageHash, secret),
|
|
101
|
+
utilityEmitOffchainEffect: (data: ACVMField[]): Promise<ACVMField[]> => oracle.aztec_utl_emitOffchainEffect(data),
|
|
40
102
|
// Adapter: old 3-param signature → new 5-param with injected constants.
|
|
41
103
|
// Values derived from: MAX_MESSAGE_CONTENT_LEN(11) - RESERVED_FIELDS (3 for notes, 1 for events).
|
|
42
104
|
utilityValidateAndStoreEnqueuedNotesAndEvents: (
|
|
43
105
|
contractAddress: ACVMField[],
|
|
44
106
|
noteValidationRequestsArrayBaseSlot: ACVMField[],
|
|
45
107
|
eventValidationRequestsArrayBaseSlot: ACVMField[],
|
|
46
|
-
) =>
|
|
108
|
+
): Promise<ACVMField[]> =>
|
|
47
109
|
oracle.aztec_utl_validateAndStoreEnqueuedNotesAndEvents(
|
|
48
110
|
contractAddress,
|
|
49
111
|
noteValidationRequestsArrayBaseSlot,
|
|
@@ -51,27 +113,23 @@ export function buildLegacyOracleCallbacks(oracle: Oracle): ACIRCallback {
|
|
|
51
113
|
[new Fr(8).toString()],
|
|
52
114
|
[new Fr(10).toString()],
|
|
53
115
|
),
|
|
54
|
-
utilityGetL1ToL2MembershipWitness: (...args: ACVMField[][]) =>
|
|
55
|
-
oracle.aztec_utl_getL1ToL2MembershipWitness(args[0], args[1], args[2]),
|
|
56
|
-
utilityCheckNullifierExists: (...args: ACVMField[][]) => oracle.aztec_utl_checkNullifierExists(args[0]),
|
|
57
|
-
utilityGetRandomField: () => oracle.aztec_utl_getRandomField(),
|
|
58
|
-
utilityEmitOffchainEffect: (...args: ACVMField[][]) => oracle.aztec_utl_emitOffchainEffect(args[0]),
|
|
59
116
|
// Renames (same signature, different oracle name)
|
|
60
|
-
privateNotifySetMinRevertibleSideEffectCounter: (
|
|
61
|
-
oracle.aztec_prv_notifyRevertiblePhaseStart(
|
|
62
|
-
privateIsSideEffectCounterRevertible: (
|
|
117
|
+
privateNotifySetMinRevertibleSideEffectCounter: (counter: ACVMField[]): Promise<ACVMField[]> =>
|
|
118
|
+
oracle.aztec_prv_notifyRevertiblePhaseStart(counter),
|
|
119
|
+
privateIsSideEffectCounterRevertible: (sideEffectCounter: ACVMField[]): Promise<ACVMField[]> =>
|
|
120
|
+
oracle.aztec_prv_inRevertiblePhase(sideEffectCounter),
|
|
63
121
|
// Signature changes: old 4-param oracles → new 1-param validatePublicCalldata
|
|
64
122
|
privateNotifyEnqueuedPublicFunctionCall: (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
) => oracle.aztec_prv_validatePublicCalldata(
|
|
123
|
+
_contractAddress: ACVMField[],
|
|
124
|
+
calldataHash: ACVMField[],
|
|
125
|
+
_sideEffectCounter: ACVMField[],
|
|
126
|
+
_isStaticCall: ACVMField[],
|
|
127
|
+
): Promise<ACVMField[]> => oracle.aztec_prv_validatePublicCalldata(calldataHash),
|
|
70
128
|
privateNotifySetPublicTeardownFunctionCall: (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
) => oracle.aztec_prv_validatePublicCalldata(
|
|
129
|
+
_contractAddress: ACVMField[],
|
|
130
|
+
calldataHash: ACVMField[],
|
|
131
|
+
_sideEffectCounter: ACVMField[],
|
|
132
|
+
_isStaticCall: ACVMField[],
|
|
133
|
+
): Promise<ACVMField[]> => oracle.aztec_prv_validatePublicCalldata(calldataHash),
|
|
76
134
|
};
|
|
77
135
|
}
|
|
@@ -605,7 +605,7 @@ export class Oracle {
|
|
|
605
605
|
}
|
|
606
606
|
|
|
607
607
|
// eslint-disable-next-line camelcase
|
|
608
|
-
async
|
|
608
|
+
async aztec_utl_tryAes128Decrypt(
|
|
609
609
|
ciphertextBVecStorage: ACVMField[],
|
|
610
610
|
[ciphertextLength]: ACVMField[],
|
|
611
611
|
iv: ACVMField[],
|
|
@@ -615,8 +615,15 @@ export class Oracle {
|
|
|
615
615
|
const ivBuffer = fromUintArray(iv, 8);
|
|
616
616
|
const symKeyBuffer = fromUintArray(symKey, 8);
|
|
617
617
|
|
|
618
|
-
|
|
619
|
-
|
|
618
|
+
// Noir Option<BoundedVec> is encoded as [is_some: Field, storage: Field[], length: Field].
|
|
619
|
+
try {
|
|
620
|
+
const plaintext = await this.handlerAsUtility().aes128Decrypt(ciphertext, ivBuffer, symKeyBuffer);
|
|
621
|
+
const [storage, length] = bufferToBoundedVec(plaintext, ciphertextBVecStorage.length);
|
|
622
|
+
return [toACVMField(1), storage, length];
|
|
623
|
+
} catch {
|
|
624
|
+
const zeroStorage = Array(ciphertextBVecStorage.length).fill(toACVMField(0));
|
|
625
|
+
return [toACVMField(0), zeroStorage, toACVMField(0)];
|
|
626
|
+
}
|
|
620
627
|
}
|
|
621
628
|
|
|
622
629
|
// eslint-disable-next-line camelcase
|
|
@@ -633,9 +640,23 @@ export class Oracle {
|
|
|
633
640
|
return secret.toFields().map(toACVMField);
|
|
634
641
|
}
|
|
635
642
|
|
|
643
|
+
// eslint-disable-next-line camelcase
|
|
644
|
+
aztec_utl_invalidateContractSyncCache(
|
|
645
|
+
[contractAddress]: ACVMField[],
|
|
646
|
+
scopes: ACVMField[],
|
|
647
|
+
[scopeCount]: ACVMField[],
|
|
648
|
+
): Promise<ACVMField[]> {
|
|
649
|
+
const scopeAddresses = scopes.slice(0, +scopeCount).map(s => AztecAddress.fromField(Fr.fromString(s)));
|
|
650
|
+
this.handlerAsUtility().invalidateContractSyncCache(
|
|
651
|
+
AztecAddress.fromField(Fr.fromString(contractAddress)),
|
|
652
|
+
scopeAddresses,
|
|
653
|
+
);
|
|
654
|
+
return Promise.resolve([]);
|
|
655
|
+
}
|
|
656
|
+
|
|
636
657
|
// eslint-disable-next-line camelcase
|
|
637
658
|
async aztec_utl_emitOffchainEffect(data: ACVMField[]) {
|
|
638
|
-
await this.
|
|
659
|
+
await this.handlerAsUtility().emitOffchainEffect(data.map(Fr.fromString));
|
|
639
660
|
return [];
|
|
640
661
|
}
|
|
641
662
|
|
|
@@ -103,7 +103,7 @@ export async function executePrivateFunction(
|
|
|
103
103
|
newNotes,
|
|
104
104
|
noteHashNullifierCounterMap,
|
|
105
105
|
rawReturnValues,
|
|
106
|
-
offchainEffects,
|
|
106
|
+
offchainEffects.map(e => ({ data: e.data })),
|
|
107
107
|
taggingIndexRanges,
|
|
108
108
|
nestedExecutionResults,
|
|
109
109
|
contractClassLogs,
|
|
@@ -26,7 +26,6 @@ import {
|
|
|
26
26
|
} from '@aztec/stdlib/tx';
|
|
27
27
|
|
|
28
28
|
import type { AccessScopes } from '../../access_scopes.js';
|
|
29
|
-
import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
|
|
30
29
|
import { NoteService } from '../../notes/note_service.js';
|
|
31
30
|
import type { SenderTaggingStore } from '../../storage/tagging_store/sender_tagging_store.js';
|
|
32
31
|
import { syncSenderTaggingIndexes } from '../../tagging/index.js';
|
|
@@ -49,7 +48,6 @@ export type PrivateExecutionOracleArgs = Omit<UtilityExecutionOracleArgs, 'contr
|
|
|
49
48
|
noteCache: ExecutionNoteCache;
|
|
50
49
|
taggingIndexCache: ExecutionTaggingIndexCache;
|
|
51
50
|
senderTaggingStore: SenderTaggingStore;
|
|
52
|
-
contractSyncService: ContractSyncService;
|
|
53
51
|
totalPublicCalldataCount?: number;
|
|
54
52
|
sideEffectCounter?: number;
|
|
55
53
|
senderForTags?: AztecAddress;
|
|
@@ -73,7 +71,6 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
73
71
|
private newNotes: NoteAndSlot[] = [];
|
|
74
72
|
private noteHashNullifierCounterMap: Map<number, number> = new Map();
|
|
75
73
|
private contractClassLogs: CountedContractClassLog[] = [];
|
|
76
|
-
private offchainEffects: { data: Fr[] }[] = [];
|
|
77
74
|
private nestedExecutionResults: PrivateCallExecutionResult[] = [];
|
|
78
75
|
|
|
79
76
|
private readonly argsHash: Fr;
|
|
@@ -84,7 +81,6 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
84
81
|
private readonly noteCache: ExecutionNoteCache;
|
|
85
82
|
private readonly taggingIndexCache: ExecutionTaggingIndexCache;
|
|
86
83
|
private readonly senderTaggingStore: SenderTaggingStore;
|
|
87
|
-
private readonly contractSyncService: ContractSyncService;
|
|
88
84
|
private totalPublicCalldataCount: number;
|
|
89
85
|
protected sideEffectCounter: number;
|
|
90
86
|
private senderForTags?: AztecAddress;
|
|
@@ -104,7 +100,6 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
104
100
|
this.noteCache = args.noteCache;
|
|
105
101
|
this.taggingIndexCache = args.taggingIndexCache;
|
|
106
102
|
this.senderTaggingStore = args.senderTaggingStore;
|
|
107
|
-
this.contractSyncService = args.contractSyncService;
|
|
108
103
|
this.totalPublicCalldataCount = args.totalPublicCalldataCount ?? 0;
|
|
109
104
|
this.sideEffectCounter = args.sideEffectCounter ?? 0;
|
|
110
105
|
this.senderForTags = args.senderForTags;
|
|
@@ -158,13 +153,6 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
158
153
|
return this.contractClassLogs;
|
|
159
154
|
}
|
|
160
155
|
|
|
161
|
-
/**
|
|
162
|
-
* Return the offchain effects emitted during this execution.
|
|
163
|
-
*/
|
|
164
|
-
public getOffchainEffects() {
|
|
165
|
-
return this.offchainEffects;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
156
|
/**
|
|
169
157
|
* Returns the tagging index ranges that were used in this execution (and that need to be stored in the db).
|
|
170
158
|
*/
|
|
@@ -654,9 +642,4 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
654
642
|
public getDebugFunctionName() {
|
|
655
643
|
return this.contractStore.getDebugFunctionName(this.contractAddress, this.callContext.functionSelector);
|
|
656
644
|
}
|
|
657
|
-
|
|
658
|
-
public emitOffchainEffect(data: Fr[]): Promise<void> {
|
|
659
|
-
this.offchainEffects.push({ data });
|
|
660
|
-
return Promise.resolve();
|
|
661
|
-
}
|
|
662
645
|
}
|
|
@@ -19,10 +19,11 @@ import { deriveEcdhSharedSecret } from '@aztec/stdlib/logs';
|
|
|
19
19
|
import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
|
|
20
20
|
import type { NoteStatus } from '@aztec/stdlib/note';
|
|
21
21
|
import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
22
|
-
import type { BlockHeader, Capsule } from '@aztec/stdlib/tx';
|
|
22
|
+
import type { BlockHeader, Capsule, OffchainEffect } from '@aztec/stdlib/tx';
|
|
23
23
|
|
|
24
24
|
import type { AccessScopes } from '../../access_scopes.js';
|
|
25
25
|
import { createContractLogger, logContractMessage } from '../../contract_logging.js';
|
|
26
|
+
import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
|
|
26
27
|
import { EventService } from '../../events/event_service.js';
|
|
27
28
|
import { LogService } from '../../logs/log_service.js';
|
|
28
29
|
import { MessageContextService } from '../../messages/message_context_service.js';
|
|
@@ -62,6 +63,7 @@ export type UtilityExecutionOracleArgs = {
|
|
|
62
63
|
capsuleStore: CapsuleStore;
|
|
63
64
|
privateEventStore: PrivateEventStore;
|
|
64
65
|
messageContextService: MessageContextService;
|
|
66
|
+
contractSyncService: ContractSyncService;
|
|
65
67
|
jobId: string;
|
|
66
68
|
log?: ReturnType<typeof createLogger>;
|
|
67
69
|
scopes: AccessScopes;
|
|
@@ -75,6 +77,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
75
77
|
isUtility = true as const;
|
|
76
78
|
|
|
77
79
|
private contractLogger: Logger | undefined;
|
|
80
|
+
private offchainEffects: OffchainEffect[] = [];
|
|
78
81
|
|
|
79
82
|
protected readonly contractAddress: AztecAddress;
|
|
80
83
|
protected readonly authWitnesses: AuthWitness[];
|
|
@@ -90,6 +93,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
90
93
|
protected readonly capsuleStore: CapsuleStore;
|
|
91
94
|
protected readonly privateEventStore: PrivateEventStore;
|
|
92
95
|
protected readonly messageContextService: MessageContextService;
|
|
96
|
+
protected readonly contractSyncService: ContractSyncService;
|
|
93
97
|
protected readonly jobId: string;
|
|
94
98
|
protected logger: ReturnType<typeof createLogger>;
|
|
95
99
|
protected readonly scopes: AccessScopes;
|
|
@@ -109,6 +113,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
109
113
|
this.capsuleStore = args.capsuleStore;
|
|
110
114
|
this.privateEventStore = args.privateEventStore;
|
|
111
115
|
this.messageContextService = args.messageContextService;
|
|
116
|
+
this.contractSyncService = args.contractSyncService;
|
|
112
117
|
this.jobId = args.jobId;
|
|
113
118
|
this.logger = args.log ?? createLogger('simulator:client_view_context');
|
|
114
119
|
this.scopes = args.scopes;
|
|
@@ -650,6 +655,17 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
650
655
|
return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries, this.jobId);
|
|
651
656
|
}
|
|
652
657
|
|
|
658
|
+
/**
|
|
659
|
+
* Clears cached sync state for a contract for a set of scopes, forcing re-sync on the next query so that newly
|
|
660
|
+
* stored notes or events are discovered.
|
|
661
|
+
*/
|
|
662
|
+
public invalidateContractSyncCache(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
|
|
663
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
664
|
+
throw new Error(`Contract ${this.contractAddress} cannot invalidate sync cache of ${contractAddress}`);
|
|
665
|
+
}
|
|
666
|
+
this.contractSyncService.invalidateContractForScopes(contractAddress, scopes);
|
|
667
|
+
}
|
|
668
|
+
|
|
653
669
|
// TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
|
|
654
670
|
public aes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
|
|
655
671
|
const aes128 = new Aes128();
|
|
@@ -671,4 +687,14 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
671
687
|
const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
|
|
672
688
|
return deriveEcdhSharedSecret(addressSecret, ephPk);
|
|
673
689
|
}
|
|
690
|
+
|
|
691
|
+
public emitOffchainEffect(data: Fr[]): Promise<void> {
|
|
692
|
+
this.offchainEffects.push({ data, contractAddress: this.contractAddress });
|
|
693
|
+
return Promise.resolve();
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/** Returns offchain effects collected during execution. */
|
|
697
|
+
public getOffchainEffects(): OffchainEffect[] {
|
|
698
|
+
return this.offchainEffects;
|
|
699
|
+
}
|
|
674
700
|
}
|
|
@@ -20,12 +20,12 @@ export class ContractSyncService implements StagedStore {
|
|
|
20
20
|
readonly storeName = 'contract_sync';
|
|
21
21
|
|
|
22
22
|
// Tracks contracts synced since last wipe. The cache is keyed per individual scope address
|
|
23
|
-
// (`contractAddress:scopeAddress`), or `contractAddress:*` for
|
|
23
|
+
// (`contractAddress:scopeAddress`), or `contractAddress:*` for all scopes (all accounts).
|
|
24
24
|
// The value is a promise that resolves when the contract is synced.
|
|
25
25
|
private syncedContracts: Map<string, Promise<void>> = new Map();
|
|
26
26
|
|
|
27
|
-
// Per-job
|
|
28
|
-
private
|
|
27
|
+
// Per-job excluded contract addresses - these contracts should not be synced.
|
|
28
|
+
private excludedFromSync: Map<string, Set<string>> = new Map();
|
|
29
29
|
|
|
30
30
|
constructor(
|
|
31
31
|
private aztecNode: AztecNode,
|
|
@@ -35,8 +35,8 @@ export class ContractSyncService implements StagedStore {
|
|
|
35
35
|
) {}
|
|
36
36
|
|
|
37
37
|
/** Sets contracts that should be skipped during sync for a specific job. */
|
|
38
|
-
|
|
39
|
-
this.
|
|
38
|
+
setExcludedFromSync(jobId: string, addresses: Set<string>): void {
|
|
39
|
+
this.excludedFromSync.set(jobId, addresses);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -56,47 +56,34 @@ export class ContractSyncService implements StagedStore {
|
|
|
56
56
|
jobId: string,
|
|
57
57
|
scopes: AccessScopes,
|
|
58
58
|
): Promise<void> {
|
|
59
|
-
|
|
60
|
-
const overrides = this.overriddenContracts.get(jobId);
|
|
61
|
-
if (overrides?.has(contractAddress.toString())) {
|
|
59
|
+
if (this.#shouldSkipSync(jobId, contractAddress)) {
|
|
62
60
|
return;
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const allScopesExisting = this.syncedContracts.get(allScopesKey);
|
|
68
|
-
if (allScopesExisting || (scopes !== 'ALL_SCOPES' && scopes.length == 0)) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const unsyncedScopes =
|
|
73
|
-
scopes === 'ALL_SCOPES'
|
|
74
|
-
? scopes
|
|
75
|
-
: scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope)));
|
|
76
|
-
const unsyncedScopesKeys = toKeys(contractAddress, unsyncedScopes);
|
|
77
|
-
|
|
78
|
-
if (unsyncedScopesKeys.length > 0) {
|
|
79
|
-
// Start sync and store the promise for all unsynced scopes
|
|
80
|
-
const promise = this.#doSync(
|
|
63
|
+
this.#startSyncIfNeeded(contractAddress, scopes, scopesToSync =>
|
|
64
|
+
this.#syncContract(
|
|
81
65
|
contractAddress,
|
|
82
66
|
functionToInvokeAfterSync,
|
|
83
67
|
utilityExecutor,
|
|
84
68
|
anchorBlockHeader,
|
|
85
69
|
jobId,
|
|
86
|
-
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
unsyncedScopesKeys.forEach(key => this.syncedContracts.delete(key));
|
|
90
|
-
throw err;
|
|
91
|
-
});
|
|
92
|
-
unsyncedScopesKeys.forEach(key => this.syncedContracts.set(key, promise));
|
|
93
|
-
}
|
|
70
|
+
scopesToSync,
|
|
71
|
+
),
|
|
72
|
+
);
|
|
94
73
|
|
|
95
|
-
|
|
96
|
-
await Promise.all(promises);
|
|
74
|
+
await this.#awaitSync(contractAddress, scopes);
|
|
97
75
|
}
|
|
98
76
|
|
|
99
|
-
|
|
77
|
+
/** Clears sync cache entries for the given scopes of a contract. Also clears the ALL_SCOPES entry. */
|
|
78
|
+
invalidateContractForScopes(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
|
|
79
|
+
if (scopes.length === 0) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
scopes.forEach(scope => this.syncedContracts.delete(toKey(contractAddress, scope)));
|
|
83
|
+
this.syncedContracts.delete(toKey(contractAddress, 'ALL_SCOPES'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async #syncContract(
|
|
100
87
|
contractAddress: AztecAddress,
|
|
101
88
|
functionToInvokeAfterSync: FunctionSelector | null,
|
|
102
89
|
utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<any>,
|
|
@@ -129,8 +116,8 @@ export class ContractSyncService implements StagedStore {
|
|
|
129
116
|
}
|
|
130
117
|
|
|
131
118
|
commit(jobId: string): Promise<void> {
|
|
132
|
-
// Clear
|
|
133
|
-
this.
|
|
119
|
+
// Clear excluded contracts for this job
|
|
120
|
+
this.excludedFromSync.delete(jobId);
|
|
134
121
|
return Promise.resolve();
|
|
135
122
|
}
|
|
136
123
|
|
|
@@ -138,9 +125,51 @@ export class ContractSyncService implements StagedStore {
|
|
|
138
125
|
// We clear the synced contracts cache here because, when the job is discarded, any associated database writes from
|
|
139
126
|
// the sync are also undone.
|
|
140
127
|
this.syncedContracts.clear();
|
|
141
|
-
this.
|
|
128
|
+
this.excludedFromSync.delete(jobId);
|
|
142
129
|
return Promise.resolve();
|
|
143
130
|
}
|
|
131
|
+
/** Returns true if sync should be skipped for this contract */
|
|
132
|
+
#shouldSkipSync(jobId: string, contractAddress: AztecAddress): boolean {
|
|
133
|
+
return !!this.excludedFromSync.get(jobId)?.has(contractAddress.toString());
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** If there are unsynced scopes, starts sync and stores the promise in cache with error cleanup. */
|
|
137
|
+
#startSyncIfNeeded(
|
|
138
|
+
contractAddress: AztecAddress,
|
|
139
|
+
scopes: AccessScopes,
|
|
140
|
+
syncFn: (scopesToSync: AccessScopes) => Promise<void>,
|
|
141
|
+
): void {
|
|
142
|
+
const scopesToSync = this.#getScopesToSync(contractAddress, scopes);
|
|
143
|
+
const keys = toKeys(contractAddress, scopesToSync);
|
|
144
|
+
if (keys.length === 0) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const promise = syncFn(scopesToSync).catch(err => {
|
|
148
|
+
keys.forEach(key => this.syncedContracts.delete(key));
|
|
149
|
+
throw err;
|
|
150
|
+
});
|
|
151
|
+
keys.forEach(key => this.syncedContracts.set(key, promise));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Filters out scopes that are already cached, returning only those that still need syncing. */
|
|
155
|
+
#getScopesToSync(contractAddress: AztecAddress, scopes: AccessScopes): AccessScopes {
|
|
156
|
+
if (this.syncedContracts.has(toKey(contractAddress, 'ALL_SCOPES'))) {
|
|
157
|
+
// If we are already syncing all scopes, then return an empty list
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
if (scopes === 'ALL_SCOPES') {
|
|
161
|
+
return 'ALL_SCOPES';
|
|
162
|
+
}
|
|
163
|
+
return scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope)));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Collects all relevant scope promises (including in-flight ones from concurrent calls) and awaits them. */
|
|
167
|
+
async #awaitSync(contractAddress: AztecAddress, scopes: AccessScopes): Promise<void> {
|
|
168
|
+
const promises = toKeys(contractAddress, scopes)
|
|
169
|
+
.map(key => this.syncedContracts.get(key))
|
|
170
|
+
.filter(p => p !== undefined);
|
|
171
|
+
await Promise.all(promises);
|
|
172
|
+
}
|
|
144
173
|
}
|
|
145
174
|
|
|
146
175
|
function toKeys(contract: AztecAddress, scopes: AccessScopes) {
|
package/src/oracle_version.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
///
|
|
5
5
|
/// @dev Whenever a contract function or Noir test is run, the `aztec_utl_assertCompatibleOracleVersion` oracle is called
|
|
6
6
|
/// and if the oracle version is incompatible an error is thrown.
|
|
7
|
-
export const ORACLE_VERSION =
|
|
7
|
+
export const ORACLE_VERSION = 18;
|
|
8
8
|
|
|
9
9
|
/// This hash is computed as by hashing the Oracle interface and it is used to detect when the Oracle interface changes,
|
|
10
10
|
/// which in turn implies that you need to update the ORACLE_VERSION constant in this file and in
|
|
11
11
|
/// `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
|
|
12
|
-
export const ORACLE_INTERFACE_HASH = '
|
|
12
|
+
export const ORACLE_INTERFACE_HASH = '57e5b07c6d55fb167ef90f8d0f410f9bdb5b154a31159c624a061be40b02a2c2';
|