@aztec/pxe 0.0.1-commit.e588bc7e5 → 0.0.1-commit.e5a3663dd
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/bin/check_oracle_version.js +4 -4
- package/dest/block_synchronizer/block_stream_source.d.ts +10 -0
- package/dest/block_synchronizer/block_stream_source.d.ts.map +1 -0
- package/dest/block_synchronizer/block_stream_source.js +37 -0
- package/dest/block_synchronizer/block_synchronizer.d.ts +6 -2
- package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
- package/dest/block_synchronizer/block_synchronizer.js +24 -10
- package/dest/config/index.d.ts +1 -1
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +7 -14
- package/dest/contract_function_simulator/contract_function_simulator.d.ts +4 -1
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +8 -5
- package/dest/contract_function_simulator/ephemeral_array_service.d.ts +28 -0
- package/dest/contract_function_simulator/ephemeral_array_service.d.ts.map +1 -0
- package/dest/contract_function_simulator/ephemeral_array_service.js +78 -0
- package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +1 -1
- package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
- package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts +1 -1
- package/dest/contract_function_simulator/noir-structs/log_retrieval_request.js +1 -1
- package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts +1 -1
- package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +1 -1
- package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +1 -1
- package/dest/contract_function_simulator/noir-structs/note_validation_request.js +1 -1
- package/dest/contract_function_simulator/oracle/interfaces.d.ts +15 -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 +10 -1
- package/dest/contract_function_simulator/oracle/oracle.d.ts +14 -2
- package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/oracle.js +105 -3
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +10 -11
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.js +21 -17
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +34 -13
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +149 -28
- package/dest/contract_function_simulator/pick_notes.d.ts +1 -1
- package/dest/contract_function_simulator/pick_notes.d.ts.map +1 -1
- package/dest/contract_function_simulator/pick_notes.js +20 -3
- package/dest/contract_function_simulator/proxied_contract_data_source.d.ts +1 -1
- package/dest/contract_function_simulator/proxied_contract_data_source.d.ts.map +1 -1
- package/dest/contract_function_simulator/proxied_contract_data_source.js +3 -0
- package/dest/contract_sync/contract_sync_service.d.ts +1 -1
- package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
- package/dest/contract_sync/contract_sync_service.js +35 -23
- package/dest/entrypoints/client/bundle/utils.d.ts +2 -2
- package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
- package/dest/entrypoints/client/bundle/utils.js +2 -2
- package/dest/entrypoints/client/lazy/utils.d.ts +2 -2
- package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
- package/dest/entrypoints/client/lazy/utils.js +2 -2
- package/dest/entrypoints/pxe_creation_options.d.ts +3 -1
- package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
- package/dest/entrypoints/pxe_creation_options.js +3 -1
- package/dest/entrypoints/server/index.d.ts +2 -2
- package/dest/entrypoints/server/index.d.ts.map +1 -1
- package/dest/entrypoints/server/index.js +1 -1
- package/dest/entrypoints/server/utils.d.ts +2 -2
- package/dest/entrypoints/server/utils.d.ts.map +1 -1
- package/dest/entrypoints/server/utils.js +2 -2
- package/dest/events/event_service.d.ts +1 -1
- package/dest/events/event_service.d.ts.map +1 -1
- package/dest/events/event_service.js +10 -1
- package/dest/events/private_event_filter_validator.d.ts +3 -2
- package/dest/events/private_event_filter_validator.d.ts.map +1 -1
- package/dest/events/private_event_filter_validator.js +15 -0
- package/dest/logs/log_service.d.ts +6 -6
- package/dest/logs/log_service.d.ts.map +1 -1
- package/dest/logs/log_service.js +8 -20
- package/dest/oracle_version.d.ts +4 -3
- package/dest/oracle_version.d.ts.map +1 -1
- package/dest/oracle_version.js +20 -10
- package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.js +4 -7
- package/dest/private_kernel/private_kernel_oracle.d.ts +5 -5
- package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
- package/dest/private_kernel/private_kernel_oracle.js +12 -15
- package/dest/pxe.d.ts +16 -4
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +49 -20
- package/dest/storage/anchor_block_store/anchor_block_store.js +1 -1
- package/dest/storage/capsule_store/capsule_store.d.ts +1 -1
- package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
- package/dest/storage/capsule_store/capsule_store.js +8 -5
- package/dest/storage/contract_store/contract_store.d.ts +1 -1
- package/dest/storage/contract_store/contract_store.d.ts.map +1 -1
- package/dest/storage/contract_store/contract_store.js +4 -2
- package/dest/storage/private_event_store/private_event_store.d.ts +1 -1
- package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
- package/dest/storage/private_event_store/private_event_store.js +3 -0
- package/dest/storage/private_event_store/stored_private_event.js +1 -1
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +2 -2
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +2 -16
- package/package.json +16 -16
- package/src/bin/check_oracle_version.ts +4 -4
- package/src/block_synchronizer/block_stream_source.ts +52 -0
- package/src/block_synchronizer/block_synchronizer.ts +27 -11
- package/src/config/index.ts +2 -8
- package/src/contract_function_simulator/contract_function_simulator.ts +8 -4
- package/src/contract_function_simulator/ephemeral_array_service.ts +110 -0
- package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
- package/src/contract_function_simulator/noir-structs/log_retrieval_request.ts +1 -1
- package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +1 -1
- package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -1
- package/src/contract_function_simulator/oracle/interfaces.ts +30 -1
- package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +7 -1
- package/src/contract_function_simulator/oracle/oracle.ts +157 -3
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +34 -20
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +241 -55
- package/src/contract_function_simulator/pick_notes.ts +22 -3
- package/src/contract_function_simulator/proxied_contract_data_source.ts +8 -1
- package/src/contract_sync/contract_sync_service.ts +57 -51
- package/src/entrypoints/client/bundle/utils.ts +2 -3
- package/src/entrypoints/client/lazy/utils.ts +2 -3
- package/src/entrypoints/pxe_creation_options.ts +7 -0
- package/src/entrypoints/server/index.ts +1 -1
- package/src/entrypoints/server/utils.ts +2 -3
- package/src/events/event_service.ts +13 -1
- package/src/events/private_event_filter_validator.ts +21 -1
- package/src/logs/log_service.ts +14 -50
- package/src/oracle_version.ts +20 -10
- package/src/private_kernel/private_kernel_execution_prover.ts +4 -9
- package/src/private_kernel/private_kernel_oracle.ts +14 -14
- package/src/pxe.ts +86 -24
- package/src/storage/anchor_block_store/anchor_block_store.ts +1 -1
- package/src/storage/capsule_store/capsule_store.ts +15 -5
- package/src/storage/contract_store/contract_store.ts +8 -6
- package/src/storage/private_event_store/private_event_store.ts +4 -0
- package/src/storage/private_event_store/stored_private_event.ts +1 -1
- package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +5 -15
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Logger } from '@aztec/foundation/log';
|
|
2
|
+
import { Semaphore } from '@aztec/foundation/queue';
|
|
2
3
|
import type { FunctionCall, FunctionSelector } from '@aztec/stdlib/abi';
|
|
3
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
5
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
@@ -9,6 +10,9 @@ import type { ContractStore } from '../storage/contract_store/contract_store.js'
|
|
|
9
10
|
import type { NoteStore } from '../storage/note_store/note_store.js';
|
|
10
11
|
import { syncState, verifyCurrentClassId } from './helpers.js';
|
|
11
12
|
|
|
13
|
+
/** Maximum number of scope syncs running concurrently across the PXE. */
|
|
14
|
+
const MAX_CONCURRENT_SCOPE_SYNCS = 5;
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
* Service for syncing the private state of contracts and verifying that the PXE holds the current class artifact.
|
|
14
18
|
* It uses a cache to avoid redundant sync operations - the cache is wiped when the anchor block changes.
|
|
@@ -26,6 +30,11 @@ export class ContractSyncService implements StagedStore {
|
|
|
26
30
|
// Per-job excluded contract addresses - these contracts should not be synced.
|
|
27
31
|
private excludedFromSync: Map<string, Set<string>> = new Map();
|
|
28
32
|
|
|
33
|
+
// Bounds the number of scope syncs running concurrently. Scopes beyond this limit queue here. Sized to trade off
|
|
34
|
+
// parallelism on non-ACIR work (node RPC, note store reads) against memory pressure from concurrent circuit
|
|
35
|
+
// execution.
|
|
36
|
+
#syncSlot = new Semaphore(MAX_CONCURRENT_SCOPE_SYNCS);
|
|
37
|
+
|
|
29
38
|
constructor(
|
|
30
39
|
private aztecNode: AztecNode,
|
|
31
40
|
private contractStore: ContractStore,
|
|
@@ -59,15 +68,22 @@ export class ContractSyncService implements StagedStore {
|
|
|
59
68
|
return;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
this.#startSyncIfNeeded(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
this.#startSyncIfNeeded(
|
|
72
|
+
contractAddress,
|
|
73
|
+
scopes,
|
|
74
|
+
() => verifyCurrentClassId(contractAddress, this.aztecNode, this.contractStore, anchorBlockHeader),
|
|
75
|
+
scope =>
|
|
76
|
+
syncState(
|
|
77
|
+
contractAddress,
|
|
78
|
+
this.contractStore,
|
|
79
|
+
functionToInvokeAfterSync,
|
|
80
|
+
utilityExecutor,
|
|
81
|
+
this.noteStore,
|
|
82
|
+
this.aztecNode,
|
|
83
|
+
anchorBlockHeader,
|
|
84
|
+
jobId,
|
|
85
|
+
scope,
|
|
86
|
+
),
|
|
71
87
|
);
|
|
72
88
|
|
|
73
89
|
await this.#awaitSync(contractAddress, scopes);
|
|
@@ -81,39 +97,6 @@ export class ContractSyncService implements StagedStore {
|
|
|
81
97
|
scopes.forEach(scope => this.syncedContracts.delete(toKey(contractAddress, scope)));
|
|
82
98
|
}
|
|
83
99
|
|
|
84
|
-
async #syncContract(
|
|
85
|
-
contractAddress: AztecAddress,
|
|
86
|
-
functionToInvokeAfterSync: FunctionSelector | null,
|
|
87
|
-
utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise<any>,
|
|
88
|
-
anchorBlockHeader: BlockHeader,
|
|
89
|
-
jobId: string,
|
|
90
|
-
scopes: AztecAddress[],
|
|
91
|
-
): Promise<void> {
|
|
92
|
-
this.log.debug(`Syncing contract ${contractAddress}`);
|
|
93
|
-
|
|
94
|
-
await Promise.all([
|
|
95
|
-
// Call sync_state sequentially for each scope address — each invocation synchronizes one account's private
|
|
96
|
-
// state using scoped capsule arrays.
|
|
97
|
-
(async () => {
|
|
98
|
-
for (const scope of scopes) {
|
|
99
|
-
await syncState(
|
|
100
|
-
contractAddress,
|
|
101
|
-
this.contractStore,
|
|
102
|
-
functionToInvokeAfterSync,
|
|
103
|
-
utilityExecutor,
|
|
104
|
-
this.noteStore,
|
|
105
|
-
this.aztecNode,
|
|
106
|
-
anchorBlockHeader,
|
|
107
|
-
jobId,
|
|
108
|
-
scope,
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
})(),
|
|
112
|
-
verifyCurrentClassId(contractAddress, this.aztecNode, this.contractStore, anchorBlockHeader),
|
|
113
|
-
]);
|
|
114
|
-
this.log.debug(`Contract ${contractAddress} synced`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
100
|
/** Clears sync cache. Called by BlockSynchronizer when anchor block changes. */
|
|
118
101
|
wipe(): void {
|
|
119
102
|
this.log.debug(`Wiping contract sync cache (${this.syncedContracts.size} entries)`);
|
|
@@ -138,22 +121,45 @@ export class ContractSyncService implements StagedStore {
|
|
|
138
121
|
return !!this.excludedFromSync.get(jobId)?.has(contractAddress.toString());
|
|
139
122
|
}
|
|
140
123
|
|
|
141
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* If there are unsynced scopes, starts one sync per scope (bounded by #syncSlot) and stores each promise in the
|
|
126
|
+
* cache with per-scope error cleanup. The verifyFn runs once for the whole fan-out and is awaited by every new
|
|
127
|
+
* scope's promise, matching the pre-parallelization invariant that a cache-miss batch re-verifies the class id.
|
|
128
|
+
*/
|
|
142
129
|
#startSyncIfNeeded(
|
|
143
130
|
contractAddress: AztecAddress,
|
|
144
131
|
scopes: AztecAddress[],
|
|
145
|
-
|
|
132
|
+
verifyFn: () => Promise<void>,
|
|
133
|
+
syncScopeFn: (scope: AztecAddress) => Promise<void>,
|
|
146
134
|
): void {
|
|
147
135
|
const scopesToSync = scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope)));
|
|
148
|
-
|
|
149
|
-
if (keys.length === 0) {
|
|
136
|
+
if (scopesToSync.length === 0) {
|
|
150
137
|
return;
|
|
151
138
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
139
|
+
|
|
140
|
+
this.log.debug(`Syncing contract ${contractAddress} for ${scopesToSync.length} scope(s)`);
|
|
141
|
+
const verifyPromise = verifyFn();
|
|
142
|
+
|
|
143
|
+
for (const scope of scopesToSync) {
|
|
144
|
+
const key = toKey(contractAddress, scope);
|
|
145
|
+
const promise = Promise.all([verifyPromise, this.#runBounded(() => syncScopeFn(scope))])
|
|
146
|
+
.then(() => {})
|
|
147
|
+
.catch(err => {
|
|
148
|
+
this.syncedContracts.delete(key);
|
|
149
|
+
throw err;
|
|
150
|
+
});
|
|
151
|
+
this.syncedContracts.set(key, promise);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Runs fn while holding a slot in #syncSlot, bounding total concurrent scope syncs. */
|
|
156
|
+
async #runBounded<T>(fn: () => Promise<T>): Promise<T> {
|
|
157
|
+
await this.#syncSlot.acquire();
|
|
158
|
+
try {
|
|
159
|
+
return await fn();
|
|
160
|
+
} finally {
|
|
161
|
+
this.#syncSlot.release();
|
|
162
|
+
}
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
/** Collects all relevant scope promises (including in-flight ones from concurrent calls) and awaits them. */
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BBPrivateKernelProver } from '@aztec/bb-prover/client';
|
|
2
1
|
import { BBBundlePrivateKernelProver } from '@aztec/bb-prover/client/bundle';
|
|
3
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
3
|
import { createStore } from '@aztec/kv-store/indexeddb';
|
|
@@ -9,7 +8,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
|
9
8
|
import type { PXEConfig } from '../../../config/index.js';
|
|
10
9
|
import { PXE } from '../../../pxe.js';
|
|
11
10
|
import { PXE_DATA_SCHEMA_VERSION } from '../../../storage/metadata.js';
|
|
12
|
-
import type
|
|
11
|
+
import { type PXECreationOptions, isPrivateKernelProver } from '../../pxe_creation_options.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Create and start an PXE instance with the given AztecNode.
|
|
@@ -44,7 +43,7 @@ export async function createPXE(
|
|
|
44
43
|
const proverLogger = loggers.prover ?? createLogger('pxe:bb:wasm:bundle', { actor });
|
|
45
44
|
|
|
46
45
|
let prover;
|
|
47
|
-
if (options.proverOrOptions
|
|
46
|
+
if (isPrivateKernelProver(options.proverOrOptions)) {
|
|
48
47
|
prover = options.proverOrOptions;
|
|
49
48
|
} else {
|
|
50
49
|
prover = new BBBundlePrivateKernelProver(simulator, { ...options.proverOrOptions, logger: proverLogger });
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BBPrivateKernelProver } from '@aztec/bb-prover/client';
|
|
2
1
|
import { BBLazyPrivateKernelProver } from '@aztec/bb-prover/client/lazy';
|
|
3
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
3
|
import { createStore } from '@aztec/kv-store/indexeddb';
|
|
@@ -9,7 +8,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
|
9
8
|
import type { PXEConfig } from '../../../config/index.js';
|
|
10
9
|
import { PXE } from '../../../pxe.js';
|
|
11
10
|
import { PXE_DATA_SCHEMA_VERSION } from '../../../storage/metadata.js';
|
|
12
|
-
import type
|
|
11
|
+
import { type PXECreationOptions, isPrivateKernelProver } from '../../pxe_creation_options.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Create and start an PXE instance with the given AztecNode.
|
|
@@ -44,7 +43,7 @@ export async function createPXE(
|
|
|
44
43
|
const proverLogger = loggers.prover ?? createLogger('pxe:bb:wasm:bundle', { actor });
|
|
45
44
|
|
|
46
45
|
let prover;
|
|
47
|
-
if (options.proverOrOptions
|
|
46
|
+
if (isPrivateKernelProver(options.proverOrOptions)) {
|
|
48
47
|
prover = options.proverOrOptions;
|
|
49
48
|
} else {
|
|
50
49
|
prover = new BBLazyPrivateKernelProver(simulator, { ...options.proverOrOptions, logger: proverLogger });
|
|
@@ -12,3 +12,10 @@ export type PXECreationOptions = {
|
|
|
12
12
|
store?: AztecAsyncKVStore;
|
|
13
13
|
simulator?: CircuitSimulator;
|
|
14
14
|
};
|
|
15
|
+
|
|
16
|
+
/** Checks if the given value implements the PrivateKernelProver interface via duck-typing. */
|
|
17
|
+
export function isPrivateKernelProver(value: unknown): value is PrivateKernelProver {
|
|
18
|
+
return (
|
|
19
|
+
typeof value === 'object' && value !== null && typeof (value as PrivateKernelProver).createChonkProof === 'function'
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -5,7 +5,7 @@ export * from '../../error_enriching.js';
|
|
|
5
5
|
export * from '../../storage/index.js';
|
|
6
6
|
export * from './utils.js';
|
|
7
7
|
export { NoteService } from '../../notes/note_service.js';
|
|
8
|
-
export {
|
|
8
|
+
export { ORACLE_VERSION_MAJOR, ORACLE_VERSION_MINOR } from '../../oracle_version.js';
|
|
9
9
|
export { type PXECreationOptions } from '../pxe_creation_options.js';
|
|
10
10
|
export { JobCoordinator } from '../../job_coordinator/job_coordinator.js';
|
|
11
11
|
export { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BBPrivateKernelProver } from '@aztec/bb-prover/client';
|
|
2
1
|
import { BBBundlePrivateKernelProver } from '@aztec/bb-prover/client/bundle';
|
|
3
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
3
|
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
@@ -10,7 +9,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
|
10
9
|
import type { PXEConfig } from '../../config/index.js';
|
|
11
10
|
import { PXE } from '../../pxe.js';
|
|
12
11
|
import { PXE_DATA_SCHEMA_VERSION } from '../../storage/index.js';
|
|
13
|
-
import type
|
|
12
|
+
import { type PXECreationOptions, isPrivateKernelProver } from '../pxe_creation_options.js';
|
|
14
13
|
|
|
15
14
|
type PXEConfigWithoutDefaults = Omit<PXEConfig, 'l1Contracts' | 'l1ChainId' | 'l2BlockBatchSize' | 'rollupVersion'>;
|
|
16
15
|
|
|
@@ -49,7 +48,7 @@ export async function createPXE(
|
|
|
49
48
|
const proverLogger = loggers.prover ?? createLogger('pxe:bb:native', { actor });
|
|
50
49
|
|
|
51
50
|
let prover;
|
|
52
|
-
if (options.proverOrOptions
|
|
51
|
+
if (isPrivateKernelProver(options.proverOrOptions)) {
|
|
53
52
|
prover = options.proverOrOptions;
|
|
54
53
|
} else {
|
|
55
54
|
prover = new BBBundlePrivateKernelProver(simulator, { ...options.proverOrOptions, logger: proverLogger });
|
|
@@ -2,7 +2,7 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import type { EventSelector } from '@aztec/stdlib/abi';
|
|
4
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
|
-
import { siloNullifier } from '@aztec/stdlib/hash';
|
|
5
|
+
import { computePrivateEventCommitment, siloNullifier } from '@aztec/stdlib/hash';
|
|
6
6
|
import type { AztecNode } from '@aztec/stdlib/interfaces/server';
|
|
7
7
|
import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
8
8
|
|
|
@@ -26,6 +26,18 @@ export class EventService {
|
|
|
26
26
|
txHash: TxHash,
|
|
27
27
|
scope: AztecAddress,
|
|
28
28
|
): Promise<void> {
|
|
29
|
+
// Defense-in-depth: the built-in private-event path derives this commitment from content before enqueueing, but
|
|
30
|
+
// unconstrained PXE-side code (e.g. a custom message handler) can reach this oracle with arbitrary
|
|
31
|
+
// (content, commitment) pairs. Without this check it could bind arbitrary content to a legitimate tx nullifier,
|
|
32
|
+
// causing PXE to surface fabricated event data.
|
|
33
|
+
const recomputedCommitment = await computePrivateEventCommitment(randomness, selector.toField(), content);
|
|
34
|
+
if (!recomputedCommitment.equals(eventCommitment)) {
|
|
35
|
+
this.log.warn(
|
|
36
|
+
`Skipping event whose content does not hash to the provided commitment. contract=${contractAddress}, selector=${selector}, eventCommitment=${eventCommitment}, txHash=${txHash}, recomputedCommitment=${recomputedCommitment}`,
|
|
37
|
+
);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
// While using 'latest' block number would be fine for private events since they cannot be accessed from Aztec.nr
|
|
30
42
|
// (and thus we're less concerned about being ahead of the synced block), we use the synced block number to
|
|
31
43
|
// maintain consistent behavior in the PXE. Additionally, events should never be ahead of the synced block here
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { PrivateEventFilter } from '@aztec/aztec.js/wallet';
|
|
2
2
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
3
3
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
5
|
|
|
5
6
|
import type { PrivateEventStoreFilter } from '../storage/private_event_store/private_event_store.js';
|
|
6
7
|
|
|
7
8
|
export class PrivateEventFilterValidator {
|
|
8
|
-
|
|
9
|
+
private readonly log = createLogger('pxe:private_event_filter_validator');
|
|
10
|
+
|
|
11
|
+
constructor(private readonly lastBlock: BlockNumber) {}
|
|
9
12
|
|
|
10
13
|
validate(filter: PrivateEventFilter): PrivateEventStoreFilter {
|
|
11
14
|
let { fromBlock, toBlock } = filter;
|
|
@@ -35,6 +38,23 @@ export class PrivateEventFilterValidator {
|
|
|
35
38
|
throw new Error('toBlock must be strictly greater than fromBlock');
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
// Cap the requested range to the synced block range. Without this, callers that pass a large
|
|
42
|
+
// toBlock (e.g. Number.MAX_SAFE_INTEGER as a "give me everything" idiom) would silently receive
|
|
43
|
+
// only the events that happen to be synced and believe they have complete coverage.
|
|
44
|
+
// We warn + cap rather than throw so callers don't need to query the last synced block before
|
|
45
|
+
// every request (which would also be unreliable, as the block can advance between the two calls).
|
|
46
|
+
const syncedUpperBound = BlockNumber(this.lastBlock + 1);
|
|
47
|
+
if (fromBlock >= syncedUpperBound) {
|
|
48
|
+
this.log.warn(
|
|
49
|
+
`Requested fromBlock ${fromBlock} is past last synced block ${this.lastBlock}; no events will be returned until PXE syncs further.`,
|
|
50
|
+
);
|
|
51
|
+
} else if (toBlock > syncedUpperBound) {
|
|
52
|
+
this.log.warn(
|
|
53
|
+
`Requested toBlock ${toBlock} exceeds last synced block ${this.lastBlock}; capping to ${syncedUpperBound}. Retry once PXE is further synced for complete coverage.`,
|
|
54
|
+
);
|
|
55
|
+
toBlock = syncedUpperBound;
|
|
56
|
+
}
|
|
57
|
+
|
|
38
58
|
return {
|
|
39
59
|
contractAddress: filter.contractAddress,
|
|
40
60
|
scopes: filter.scopes,
|
package/src/logs/log_service.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
1
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
2
|
import type { KeyStore } from '@aztec/key-store';
|
|
4
3
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
|
+
import type { L2TipsProvider } from '@aztec/stdlib/block';
|
|
5
5
|
import type { AztecNode } from '@aztec/stdlib/interfaces/server';
|
|
6
|
-
import {
|
|
7
|
-
ExtendedDirectionalAppTaggingSecret,
|
|
8
|
-
PendingTaggedLog,
|
|
9
|
-
SiloedTag,
|
|
10
|
-
Tag,
|
|
11
|
-
TxScopedL2Log,
|
|
12
|
-
} from '@aztec/stdlib/logs';
|
|
6
|
+
import { ExtendedDirectionalAppTaggingSecret, PendingTaggedLog, SiloedTag, Tag } from '@aztec/stdlib/logs';
|
|
13
7
|
import type { BlockHeader } from '@aztec/stdlib/tx';
|
|
14
8
|
|
|
15
9
|
import type { LogRetrievalRequest } from '../contract_function_simulator/noir-structs/log_retrieval_request.js';
|
|
16
10
|
import { LogRetrievalResponse } from '../contract_function_simulator/noir-structs/log_retrieval_response.js';
|
|
17
11
|
import { AddressStore } from '../storage/address_store/address_store.js';
|
|
18
|
-
import type { CapsuleService } from '../storage/capsule_store/capsule_service.js';
|
|
19
12
|
import type { RecipientTaggingStore } from '../storage/tagging_store/recipient_tagging_store.js';
|
|
20
13
|
import type { SenderAddressBookStore } from '../storage/tagging_store/sender_address_book_store.js';
|
|
21
14
|
import {
|
|
@@ -30,8 +23,8 @@ export class LogService {
|
|
|
30
23
|
constructor(
|
|
31
24
|
private readonly aztecNode: AztecNode,
|
|
32
25
|
private readonly anchorBlockHeader: BlockHeader,
|
|
26
|
+
private readonly l2TipsStore: L2TipsProvider,
|
|
33
27
|
private readonly keyStore: KeyStore,
|
|
34
|
-
private readonly capsuleService: CapsuleService,
|
|
35
28
|
private readonly recipientTaggingStore: RecipientTaggingStore,
|
|
36
29
|
private readonly senderAddressBookStore: SenderAddressBookStore,
|
|
37
30
|
private readonly addressStore: AddressStore,
|
|
@@ -120,17 +113,15 @@ export class LogService {
|
|
|
120
113
|
);
|
|
121
114
|
}
|
|
122
115
|
|
|
123
|
-
public async fetchTaggedLogs(
|
|
124
|
-
contractAddress: AztecAddress,
|
|
125
|
-
pendingTaggedLogArrayBaseSlot: Fr,
|
|
126
|
-
recipient: AztecAddress,
|
|
127
|
-
) {
|
|
116
|
+
public async fetchTaggedLogs(contractAddress: AztecAddress, recipient: AztecAddress): Promise<PendingTaggedLog[]> {
|
|
128
117
|
this.log.verbose(`Fetching tagged logs for ${contractAddress.toString()}`);
|
|
129
118
|
|
|
130
119
|
// We only load logs from block up to and including the anchor block number
|
|
131
120
|
const anchorBlockNumber = this.anchorBlockHeader.getBlockNumber();
|
|
132
121
|
const anchorBlockHash = await this.anchorBlockHeader.hash();
|
|
133
122
|
|
|
123
|
+
const l2Tips = await this.l2TipsStore.getL2Tips();
|
|
124
|
+
const currentTimestamp = this.anchorBlockHeader.globalVariables.timestamp;
|
|
134
125
|
// Get all secrets for this recipient (one per sender)
|
|
135
126
|
const secrets = await this.#getSecretsForSenders(contractAddress, recipient);
|
|
136
127
|
|
|
@@ -143,17 +134,19 @@ export class LogService {
|
|
|
143
134
|
this.recipientTaggingStore,
|
|
144
135
|
anchorBlockNumber,
|
|
145
136
|
anchorBlockHash,
|
|
137
|
+
currentTimestamp,
|
|
138
|
+
l2Tips.finalized.block.number,
|
|
146
139
|
this.jobId,
|
|
147
140
|
),
|
|
148
141
|
),
|
|
149
142
|
);
|
|
150
143
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
144
|
+
return logArrays
|
|
145
|
+
.flat()
|
|
146
|
+
.map(
|
|
147
|
+
scopedLog =>
|
|
148
|
+
new PendingTaggedLog(scopedLog.logData, scopedLog.txHash, scopedLog.noteHashes, scopedLog.firstNullifier),
|
|
149
|
+
);
|
|
157
150
|
}
|
|
158
151
|
|
|
159
152
|
async #getSecretsForSenders(
|
|
@@ -187,7 +180,6 @@ export class LogService {
|
|
|
187
180
|
|
|
188
181
|
if (!secret) {
|
|
189
182
|
// Note that all senders originate from either the SenderAddressBookStore or the KeyStore.
|
|
190
|
-
// TODO(F-512): make sure we actually prevent registering invalid senders.
|
|
191
183
|
throw new Error(
|
|
192
184
|
`Failed to compute a tagging secret for sender ${sender} - this implies this is an invalid address, which should not happen as they have been previously registered in PXE.`,
|
|
193
185
|
);
|
|
@@ -197,32 +189,4 @@ export class LogService {
|
|
|
197
189
|
}),
|
|
198
190
|
);
|
|
199
191
|
}
|
|
200
|
-
|
|
201
|
-
#storePendingTaggedLogs(
|
|
202
|
-
contractAddress: AztecAddress,
|
|
203
|
-
capsuleArrayBaseSlot: Fr,
|
|
204
|
-
recipient: AztecAddress,
|
|
205
|
-
privateLogs: TxScopedL2Log[],
|
|
206
|
-
) {
|
|
207
|
-
// Build all pending tagged logs from the scoped logs
|
|
208
|
-
const pendingTaggedLogs = privateLogs.map(scopedLog => {
|
|
209
|
-
const pendingTaggedLog = new PendingTaggedLog(
|
|
210
|
-
scopedLog.logData,
|
|
211
|
-
scopedLog.txHash,
|
|
212
|
-
scopedLog.noteHashes,
|
|
213
|
-
scopedLog.firstNullifier,
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
return pendingTaggedLog.toFields();
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// TODO: This looks like it could belong more at the oracle interface level
|
|
220
|
-
return this.capsuleService.appendToCapsuleArray(
|
|
221
|
-
contractAddress,
|
|
222
|
-
capsuleArrayBaseSlot,
|
|
223
|
-
pendingTaggedLogs,
|
|
224
|
-
this.jobId,
|
|
225
|
-
recipient,
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
192
|
}
|
package/src/oracle_version.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
/// The
|
|
2
|
-
///
|
|
3
|
-
///
|
|
1
|
+
/// The oracle version constants are used to check that the oracle interface is in sync between PXE and Aztec.nr.
|
|
2
|
+
/// We version the oracle interface as `major.minor` where:
|
|
3
|
+
/// - `major` = backward-breaking changes (must match exactly between PXE and Aztec.nr)
|
|
4
|
+
/// - `minor` = oracle additions (non-breaking; PXE minor >= contract minor)
|
|
4
5
|
///
|
|
5
|
-
///
|
|
6
|
-
///
|
|
7
|
-
|
|
6
|
+
/// The Noir counterparts are in `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
|
|
7
|
+
///
|
|
8
|
+
/// @dev Whenever a contract function or Noir test is run, the `aztec_utl_assertCompatibleOracleVersion` oracle is called.
|
|
9
|
+
/// If the major version is incompatible, an error is thrown immediately. The minor version is recorded by the PXE and
|
|
10
|
+
/// used to provide helpful error messages if a contract calls an oracle that doesn't exist. We don't throw immediately
|
|
11
|
+
/// if AZTEC_NR_MINOR > PXE_MINOR because if a contract is updated to use a newer Aztec.nr dependency without actually
|
|
12
|
+
/// using any of the new oracles then there is no reason to throw.
|
|
13
|
+
export const ORACLE_VERSION_MAJOR = 22;
|
|
14
|
+
export const ORACLE_VERSION_MINOR = 2;
|
|
8
15
|
|
|
9
|
-
/// This hash is computed
|
|
10
|
-
///
|
|
11
|
-
/// `
|
|
12
|
-
|
|
16
|
+
/// This hash is computed from the Oracle interface and is used to detect when that interface changes. When it does,
|
|
17
|
+
/// you need to either:
|
|
18
|
+
/// - increment `ORACLE_VERSION_MAJOR` and reset `ORACLE_VERSION_MINOR` to zero if the change is breaking, or
|
|
19
|
+
/// - increment only `ORACLE_VERSION_MINOR` if the change is additive (a new oracle was added).
|
|
20
|
+
///
|
|
21
|
+
/// These constants must be kept in sync between this file and `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
|
|
22
|
+
export const ORACLE_INTERFACE_HASH = '193fe3f9fee6a84d26803e636c9746dd805a4f389d44a0618de75c2c5eb4912e';
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from '@aztec/stdlib/tx';
|
|
34
34
|
import { VerificationKeyAsFields, VerificationKeyData, VkData } from '@aztec/stdlib/vks';
|
|
35
35
|
|
|
36
|
+
import { computeTxExpirationTimestamp } from './hints/compute_tx_expiration_timestamp.js';
|
|
36
37
|
import { PrivateKernelResetPrivateInputsBuilder } from './hints/private_kernel_reset_private_inputs_builder.js';
|
|
37
38
|
import type { PrivateKernelOracle } from './private_kernel_oracle.js';
|
|
38
39
|
|
|
@@ -267,15 +268,9 @@ export class PrivateKernelExecutionProver {
|
|
|
267
268
|
// TODO: Enable padding once we better understand the final amounts to pad to.
|
|
268
269
|
const paddedSideEffectAmounts = PaddedSideEffectAmounts.empty();
|
|
269
270
|
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
const expirationTimestampUpperBound = previousKernelData.publicInputs
|
|
273
|
-
const anchorBlockTimestamp = previousKernelData.publicInputs.constants.anchorBlockHeader.globalVariables.timestamp;
|
|
274
|
-
if (expirationTimestampUpperBound <= anchorBlockTimestamp) {
|
|
275
|
-
throw new Error(
|
|
276
|
-
`Include-by timestamp must be greater than the anchor block timestamp. Anchor block timestamp: ${anchorBlockTimestamp}. Include-by timestamp: ${expirationTimestampUpperBound}.`,
|
|
277
|
-
);
|
|
278
|
-
}
|
|
271
|
+
// Round the aggregated expirationTimestamp down to reduce precision and avoid leaking which private
|
|
272
|
+
// functions were called via their exact expiration offsets.
|
|
273
|
+
const expirationTimestampUpperBound = computeTxExpirationTimestamp(previousKernelData.publicInputs);
|
|
279
274
|
|
|
280
275
|
const privateInputs = new PrivateKernelTailCircuitPrivateInputs(
|
|
281
276
|
previousKernelData,
|
|
@@ -7,13 +7,13 @@ import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-type
|
|
|
7
7
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
8
8
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
9
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
10
|
-
import { BlockHash } from '@aztec/stdlib/block';
|
|
11
10
|
import { type ContractInstanceWithAddress, computeSaltedInitializationHash } from '@aztec/stdlib/contract';
|
|
12
11
|
import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '@aztec/stdlib/delayed-public-mutable';
|
|
13
12
|
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
14
13
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
15
14
|
import { UpdatedClassIdHints } from '@aztec/stdlib/kernel';
|
|
16
15
|
import type { NullifierMembershipWitness } from '@aztec/stdlib/trees';
|
|
16
|
+
import type { BlockHeader } from '@aztec/stdlib/tx';
|
|
17
17
|
import type { VerificationKeyAsFields } from '@aztec/stdlib/vks';
|
|
18
18
|
|
|
19
19
|
import type { ContractStore } from '../storage/contract_store/contract_store.js';
|
|
@@ -26,7 +26,7 @@ export class PrivateKernelOracle {
|
|
|
26
26
|
private contractStore: ContractStore,
|
|
27
27
|
private keyStore: KeyStore,
|
|
28
28
|
private node: AztecNode,
|
|
29
|
-
private
|
|
29
|
+
private blockHeader: BlockHeader,
|
|
30
30
|
) {}
|
|
31
31
|
|
|
32
32
|
/** Retrieves the preimage of a contract address from the registered contract instances db. */
|
|
@@ -80,22 +80,20 @@ export class PrivateKernelOracle {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/** Returns a membership witness with the sibling path and leaf index in our note hash tree. */
|
|
83
|
-
getNoteHashMembershipWitness(
|
|
84
|
-
|
|
83
|
+
async getNoteHashMembershipWitness(
|
|
84
|
+
noteHash: Fr,
|
|
85
|
+
): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
|
|
86
|
+
return this.node.getNoteHashMembershipWitness(await this.blockHeader.hash(), noteHash);
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
/** Returns a membership witness with the sibling path and leaf index in our nullifier indexed merkle tree. */
|
|
88
|
-
getNullifierMembershipWitness(nullifier: Fr): Promise<NullifierMembershipWitness | undefined> {
|
|
89
|
-
return this.node.getNullifierMembershipWitness(this.
|
|
90
|
+
async getNullifierMembershipWitness(nullifier: Fr): Promise<NullifierMembershipWitness | undefined> {
|
|
91
|
+
return this.node.getNullifierMembershipWitness(await this.blockHeader.hash(), nullifier);
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
/** Returns the root of our note hash merkle tree. */
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (!header) {
|
|
96
|
-
throw new Error(`No block header found for block hash ${this.blockHash}`);
|
|
97
|
-
}
|
|
98
|
-
return header.state.partial.noteHashTree.root;
|
|
95
|
+
getNoteHashTreeRoot(): Fr {
|
|
96
|
+
return this.blockHeader.state.partial.noteHashTree.root;
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
/**
|
|
@@ -126,14 +124,16 @@ export class PrivateKernelOracle {
|
|
|
126
124
|
ProtocolContractAddress.ContractInstanceRegistry,
|
|
127
125
|
delayedPublicMutableHashSlot,
|
|
128
126
|
);
|
|
129
|
-
const
|
|
127
|
+
const blockHash = await this.blockHeader.hash();
|
|
128
|
+
|
|
129
|
+
const updatedClassIdWitness = await this.node.getPublicDataWitness(blockHash, hashLeafSlot);
|
|
130
130
|
|
|
131
131
|
if (!updatedClassIdWitness) {
|
|
132
132
|
throw new Error(`No public data tree witness found for ${hashLeafSlot}`);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
const readStorage = (storageSlot: Fr) =>
|
|
136
|
-
this.node.getPublicStorageAt(
|
|
136
|
+
this.node.getPublicStorageAt(blockHash, ProtocolContractAddress.ContractInstanceRegistry, storageSlot);
|
|
137
137
|
const delayedPublicMutableValues = await DelayedPublicMutableValues.readFromTree(
|
|
138
138
|
delayedPublicMutableSlot,
|
|
139
139
|
readStorage,
|