@aztec/pxe 0.0.1-commit.88c5703d4 → 0.0.1-commit.88e6f9396
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 +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +17 -2
- package/dest/contract_function_simulator/oracle/interfaces.d.ts +2 -1
- 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 +24 -4
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -4
- 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 -2
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +9 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +11 -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 +11 -8
- package/package.json +16 -16
- package/src/contract_function_simulator/contract_function_simulator.ts +24 -2
- package/src/contract_function_simulator/oracle/interfaces.ts +1 -0
- package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +103 -45
- package/src/contract_function_simulator/oracle/oracle.ts +24 -4
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +0 -4
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +15 -0
- package/src/contract_sync/contract_sync_service.ts +67 -38
- package/src/oracle_version.ts +2 -2
- package/src/pxe.ts +24 -9
|
@@ -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
|
}
|
|
@@ -604,9 +604,8 @@ export class Oracle {
|
|
|
604
604
|
return [];
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
-
// TODO(F-452): Return Option and wrap in try/catch so BB exceptions don't crash PXE.
|
|
608
607
|
// eslint-disable-next-line camelcase
|
|
609
|
-
async
|
|
608
|
+
async aztec_utl_tryAes128Decrypt(
|
|
610
609
|
ciphertextBVecStorage: ACVMField[],
|
|
611
610
|
[ciphertextLength]: ACVMField[],
|
|
612
611
|
iv: ACVMField[],
|
|
@@ -616,8 +615,15 @@ export class Oracle {
|
|
|
616
615
|
const ivBuffer = fromUintArray(iv, 8);
|
|
617
616
|
const symKeyBuffer = fromUintArray(symKey, 8);
|
|
618
617
|
|
|
619
|
-
|
|
620
|
-
|
|
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
|
+
}
|
|
621
627
|
}
|
|
622
628
|
|
|
623
629
|
// eslint-disable-next-line camelcase
|
|
@@ -634,6 +640,20 @@ export class Oracle {
|
|
|
634
640
|
return secret.toFields().map(toACVMField);
|
|
635
641
|
}
|
|
636
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
|
+
|
|
637
657
|
// eslint-disable-next-line camelcase
|
|
638
658
|
async aztec_utl_emitOffchainEffect(data: ACVMField[]) {
|
|
639
659
|
await this.handlerAsUtility().emitOffchainEffect(data.map(Fr.fromString));
|
|
@@ -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;
|
|
@@ -83,7 +81,6 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
83
81
|
private readonly noteCache: ExecutionNoteCache;
|
|
84
82
|
private readonly taggingIndexCache: ExecutionTaggingIndexCache;
|
|
85
83
|
private readonly senderTaggingStore: SenderTaggingStore;
|
|
86
|
-
private readonly contractSyncService: ContractSyncService;
|
|
87
84
|
private totalPublicCalldataCount: number;
|
|
88
85
|
protected sideEffectCounter: number;
|
|
89
86
|
private senderForTags?: AztecAddress;
|
|
@@ -103,7 +100,6 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
|
|
|
103
100
|
this.noteCache = args.noteCache;
|
|
104
101
|
this.taggingIndexCache = args.taggingIndexCache;
|
|
105
102
|
this.senderTaggingStore = args.senderTaggingStore;
|
|
106
|
-
this.contractSyncService = args.contractSyncService;
|
|
107
103
|
this.totalPublicCalldataCount = args.totalPublicCalldataCount ?? 0;
|
|
108
104
|
this.sideEffectCounter = args.sideEffectCounter ?? 0;
|
|
109
105
|
this.senderForTags = args.senderForTags;
|
|
@@ -23,6 +23,7 @@ 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;
|
|
@@ -91,6 +93,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
91
93
|
protected readonly capsuleStore: CapsuleStore;
|
|
92
94
|
protected readonly privateEventStore: PrivateEventStore;
|
|
93
95
|
protected readonly messageContextService: MessageContextService;
|
|
96
|
+
protected readonly contractSyncService: ContractSyncService;
|
|
94
97
|
protected readonly jobId: string;
|
|
95
98
|
protected logger: ReturnType<typeof createLogger>;
|
|
96
99
|
protected readonly scopes: AccessScopes;
|
|
@@ -110,6 +113,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
110
113
|
this.capsuleStore = args.capsuleStore;
|
|
111
114
|
this.privateEventStore = args.privateEventStore;
|
|
112
115
|
this.messageContextService = args.messageContextService;
|
|
116
|
+
this.contractSyncService = args.contractSyncService;
|
|
113
117
|
this.jobId = args.jobId;
|
|
114
118
|
this.logger = args.log ?? createLogger('simulator:client_view_context');
|
|
115
119
|
this.scopes = args.scopes;
|
|
@@ -651,6 +655,17 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
651
655
|
return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries, this.jobId);
|
|
652
656
|
}
|
|
653
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
|
+
|
|
654
669
|
// TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
|
|
655
670
|
public aes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
|
|
656
671
|
const aes128 = new Aes128();
|
|
@@ -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';
|
package/src/pxe.ts
CHANGED
|
@@ -107,7 +107,9 @@ export type SimulateTxOpts = {
|
|
|
107
107
|
skipTxValidation?: boolean;
|
|
108
108
|
/** If false, fees are enforced. */
|
|
109
109
|
skipFeeEnforcement?: boolean;
|
|
110
|
-
/**
|
|
110
|
+
/** If true, kernel logic is emulated in TS for simulation */
|
|
111
|
+
skipKernels?: boolean;
|
|
112
|
+
/** State overrides for the simulation, such as contract instances and artifacts. Requires skipKernels: true */
|
|
111
113
|
overrides?: SimulationOverrides;
|
|
112
114
|
/** Addresses whose private state and keys are accessible during private execution */
|
|
113
115
|
scopes: AccessScopes;
|
|
@@ -567,6 +569,9 @@ export class PXE {
|
|
|
567
569
|
|
|
568
570
|
if (wasAdded) {
|
|
569
571
|
this.log.info(`Added sender:\n ${sender.toString()}`);
|
|
572
|
+
// Wipe the entire sync cache: the new sender's tagged logs could contain notes/events for any contract, so
|
|
573
|
+
// all contracts must re-sync to discover them.
|
|
574
|
+
this.contractSyncService.wipe();
|
|
570
575
|
} else {
|
|
571
576
|
this.log.info(`Sender:\n "${sender.toString()}"\n already registered.`);
|
|
572
577
|
}
|
|
@@ -896,7 +901,14 @@ export class PXE {
|
|
|
896
901
|
*/
|
|
897
902
|
public simulateTx(
|
|
898
903
|
txRequest: TxExecutionRequest,
|
|
899
|
-
{
|
|
904
|
+
{
|
|
905
|
+
simulatePublic,
|
|
906
|
+
skipTxValidation = false,
|
|
907
|
+
skipFeeEnforcement = false,
|
|
908
|
+
skipKernels = true,
|
|
909
|
+
overrides,
|
|
910
|
+
scopes,
|
|
911
|
+
}: SimulateTxOpts,
|
|
900
912
|
): Promise<TxSimulationResult> {
|
|
901
913
|
// We disable concurrent simulations since those might execute oracles which read and write to the PXE stores (e.g.
|
|
902
914
|
// to the capsules), and we need to prevent concurrent runs from interfering with one another (e.g. attempting to
|
|
@@ -920,17 +932,20 @@ export class PXE {
|
|
|
920
932
|
await this.blockStateSynchronizer.sync();
|
|
921
933
|
const syncTime = syncTimer.ms();
|
|
922
934
|
|
|
923
|
-
const contractFunctionSimulator = this.#getSimulatorForTx(overrides);
|
|
924
|
-
// Temporary: in case there are overrides, we have to skip the kernels or validations
|
|
925
|
-
// will fail. Consider handing control to the user/wallet on whether they want to run them
|
|
926
|
-
// or not.
|
|
927
935
|
const overriddenContracts = overrides?.contracts ? new Set(Object.keys(overrides.contracts)) : undefined;
|
|
928
936
|
const hasOverriddenContracts = overriddenContracts !== undefined && overriddenContracts.size > 0;
|
|
929
|
-
const skipKernels = hasOverriddenContracts;
|
|
930
937
|
|
|
931
|
-
|
|
938
|
+
if (hasOverriddenContracts && !skipKernels) {
|
|
939
|
+
throw new Error(
|
|
940
|
+
'Simulating with overridden contracts is not compatible with kernel execution. Please set skipKernels to true when simulating with overridden contracts.',
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
const contractFunctionSimulator = this.#getSimulatorForTx(overrides);
|
|
944
|
+
|
|
932
945
|
if (hasOverriddenContracts) {
|
|
933
|
-
|
|
946
|
+
// Overridden contracts don't have a sync function, so calling sync on them would fail.
|
|
947
|
+
// We exclude them so the sync service skips them entirely.
|
|
948
|
+
this.contractSyncService.setExcludedFromSync(jobId, overriddenContracts);
|
|
934
949
|
}
|
|
935
950
|
|
|
936
951
|
// Execution of private functions only; no proving, and no kernel logic.
|