@aztec/pxe 0.0.1-commit.4d79d1f2d → 0.0.1-commit.4eabbdb
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/access_scopes.d.ts +9 -0
- package/dest/access_scopes.d.ts.map +1 -0
- package/dest/access_scopes.js +6 -0
- package/dest/config/package_info.js +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.d.ts +8 -6
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +107 -37
- package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
- package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +2 -2
- package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
- package/dest/contract_function_simulator/noir-structs/note_validation_request.js +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +3 -2
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.js +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +4 -3
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +1 -1
- package/dest/contract_sync/contract_sync_service.d.ts +4 -3
- package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
- package/dest/contract_sync/contract_sync_service.js +10 -10
- package/dest/contract_sync/helpers.d.ts +3 -2
- package/dest/contract_sync/helpers.d.ts.map +1 -1
- package/dest/contract_sync/helpers.js +3 -3
- package/dest/debug/pxe_debug_utils.d.ts +5 -4
- package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
- package/dest/debug/pxe_debug_utils.js +4 -4
- package/dest/entrypoints/client/bundle/index.d.ts +3 -1
- package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
- package/dest/entrypoints/client/bundle/index.js +2 -0
- package/dest/entrypoints/client/lazy/index.d.ts +3 -1
- package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
- package/dest/entrypoints/client/lazy/index.js +2 -0
- package/dest/entrypoints/server/index.d.ts +3 -1
- package/dest/entrypoints/server/index.d.ts.map +1 -1
- package/dest/entrypoints/server/index.js +2 -0
- package/dest/logs/log_service.d.ts +3 -2
- package/dest/logs/log_service.d.ts.map +1 -1
- package/dest/logs/log_service.js +1 -1
- package/dest/notes/note_service.d.ts +4 -3
- package/dest/notes/note_service.d.ts.map +1 -1
- package/dest/notes/note_service.js +3 -2
- package/dest/notes_filter.d.ts +25 -0
- package/dest/notes_filter.d.ts.map +1 -0
- package/dest/notes_filter.js +4 -0
- package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts +4 -0
- package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts.map +1 -0
- package/dest/private_kernel/hints/{compute_tx_include_by_timestamp.js → compute_tx_expiration_timestamp.js} +12 -12
- package/dest/private_kernel/hints/index.d.ts +1 -1
- package/dest/private_kernel/hints/index.js +1 -1
- package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.js +4 -4
- package/dest/private_kernel/private_kernel_execution_prover.js +6 -6
- package/dest/pxe.d.ts +12 -11
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +17 -15
- package/dest/storage/note_store/note_store.d.ts +3 -2
- package/dest/storage/note_store/note_store.d.ts.map +1 -1
- package/dest/storage/note_store/note_store.js +2 -2
- package/dest/tagging/get_all_logs_by_tags.d.ts +1 -1
- package/dest/tagging/get_all_logs_by_tags.d.ts.map +1 -1
- package/dest/tagging/get_all_logs_by_tags.js +17 -3
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +4 -4
- package/dest/tagging/recipient_sync/utils/find_highest_indexes.js +2 -2
- package/package.json +16 -16
- package/src/access_scopes.ts +9 -0
- package/src/config/package_info.ts +1 -1
- package/src/contract_function_simulator/contract_function_simulator.ts +213 -55
- package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
- package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -1
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +4 -3
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +4 -3
- package/src/contract_sync/contract_sync_service.ts +19 -12
- package/src/contract_sync/helpers.ts +7 -2
- package/src/debug/pxe_debug_utils.ts +9 -8
- package/src/entrypoints/client/bundle/index.ts +2 -0
- package/src/entrypoints/client/lazy/index.ts +2 -0
- package/src/entrypoints/server/index.ts +2 -0
- package/src/logs/log_service.ts +3 -6
- package/src/notes/note_service.ts +4 -3
- package/src/notes_filter.ts +26 -0
- package/src/private_kernel/hints/{compute_tx_include_by_timestamp.ts → compute_tx_expiration_timestamp.ts} +13 -13
- package/src/private_kernel/hints/index.ts +1 -1
- package/src/private_kernel/hints/private_kernel_reset_private_inputs_builder.ts +7 -7
- package/src/private_kernel/private_kernel_execution_prover.ts +6 -6
- package/src/pxe.ts +29 -27
- package/src/storage/note_store/note_store.ts +7 -3
- package/src/tagging/get_all_logs_by_tags.ts +28 -4
- package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +4 -4
- package/src/tagging/recipient_sync/utils/find_highest_indexes.ts +2 -2
- package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts +0 -4
- package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts.map +0 -1
|
@@ -6,6 +6,7 @@ import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '
|
|
|
6
6
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
7
7
|
import type { BlockHeader } from '@aztec/stdlib/tx';
|
|
8
8
|
|
|
9
|
+
import type { AccessScopes } from '../access_scopes.js';
|
|
9
10
|
import { NoteService } from '../notes/note_service.js';
|
|
10
11
|
import type { ContractStore } from '../storage/contract_store/contract_store.js';
|
|
11
12
|
import type { NoteStore } from '../storage/note_store/note_store.js';
|
|
@@ -42,11 +43,12 @@ export async function syncState(
|
|
|
42
43
|
contractAddress: AztecAddress,
|
|
43
44
|
contractStore: ContractStore,
|
|
44
45
|
functionToInvokeAfterSync: FunctionSelector | null,
|
|
45
|
-
utilityExecutor: (privateSyncCall: FunctionCall) => Promise<any>,
|
|
46
|
+
utilityExecutor: (privateSyncCall: FunctionCall, scopes: AccessScopes) => Promise<any>,
|
|
46
47
|
noteStore: NoteStore,
|
|
47
48
|
aztecNode: AztecNode,
|
|
48
49
|
anchorBlockHeader: BlockHeader,
|
|
49
50
|
jobId: string,
|
|
51
|
+
scopes: AccessScopes,
|
|
50
52
|
) {
|
|
51
53
|
// Protocol contracts don't have private state to sync
|
|
52
54
|
if (!isProtocolContract(contractAddress)) {
|
|
@@ -61,7 +63,10 @@ export async function syncState(
|
|
|
61
63
|
|
|
62
64
|
// Both sync_state and syncNoteNullifiers interact with the note store, but running them in parallel is safe
|
|
63
65
|
// because note store is designed to handle concurrent operations.
|
|
64
|
-
await Promise.all([
|
|
66
|
+
await Promise.all([
|
|
67
|
+
utilityExecutor(syncStateFunctionCall, scopes),
|
|
68
|
+
noteService.syncNoteNullifiers(contractAddress, scopes),
|
|
69
|
+
]);
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { FunctionCall } from '@aztec/stdlib/abi';
|
|
2
2
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
3
|
-
import type {
|
|
4
|
-
import type { NoteDao, NotesFilter } from '@aztec/stdlib/note';
|
|
3
|
+
import type { NoteDao } from '@aztec/stdlib/note';
|
|
5
4
|
import type { ContractOverrides } from '@aztec/stdlib/tx';
|
|
6
5
|
|
|
6
|
+
import type { AccessScopes } from '../access_scopes.js';
|
|
7
7
|
import type { BlockSynchronizer } from '../block_synchronizer/block_synchronizer.js';
|
|
8
8
|
import type { ContractFunctionSimulator } from '../contract_function_simulator/contract_function_simulator.js';
|
|
9
9
|
import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
|
|
10
|
+
import type { NotesFilter } from '../notes_filter.js';
|
|
10
11
|
import type { AnchorBlockStore } from '../storage/index.js';
|
|
11
12
|
import type { NoteStore } from '../storage/note_store/note_store.js';
|
|
12
13
|
|
|
@@ -17,11 +18,11 @@ import type { NoteStore } from '../storage/note_store/note_store.js';
|
|
|
17
18
|
export class PXEDebugUtils {
|
|
18
19
|
#putJobInQueue!: <T>(job: (jobId: string) => Promise<T>) => Promise<T>;
|
|
19
20
|
#getSimulatorForTx!: (overrides?: { contracts?: ContractOverrides }) => ContractFunctionSimulator;
|
|
20
|
-
#
|
|
21
|
+
#executeUtility!: (
|
|
21
22
|
contractFunctionSimulator: ContractFunctionSimulator,
|
|
22
23
|
call: FunctionCall,
|
|
23
24
|
authWitnesses: AuthWitness[] | undefined,
|
|
24
|
-
scopes:
|
|
25
|
+
scopes: AccessScopes,
|
|
25
26
|
jobId: string,
|
|
26
27
|
) => Promise<any>;
|
|
27
28
|
|
|
@@ -36,17 +37,17 @@ export class PXEDebugUtils {
|
|
|
36
37
|
public setPXEHelpers(
|
|
37
38
|
putJobInQueue: <T>(job: (jobId: string) => Promise<T>) => Promise<T>,
|
|
38
39
|
getSimulatorForTx: (overrides?: { contracts?: ContractOverrides }) => ContractFunctionSimulator,
|
|
39
|
-
|
|
40
|
+
executeUtility: (
|
|
40
41
|
contractFunctionSimulator: ContractFunctionSimulator,
|
|
41
42
|
call: FunctionCall,
|
|
42
43
|
authWitnesses: AuthWitness[] | undefined,
|
|
43
|
-
scopes:
|
|
44
|
+
scopes: AccessScopes,
|
|
44
45
|
jobId: string,
|
|
45
46
|
) => Promise<any>,
|
|
46
47
|
) {
|
|
47
48
|
this.#putJobInQueue = putJobInQueue;
|
|
48
49
|
this.#getSimulatorForTx = getSimulatorForTx;
|
|
49
|
-
this.#
|
|
50
|
+
this.#executeUtility = executeUtility;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
@@ -72,7 +73,7 @@ export class PXEDebugUtils {
|
|
|
72
73
|
filter.contractAddress,
|
|
73
74
|
null,
|
|
74
75
|
async (privateSyncCall, execScopes) =>
|
|
75
|
-
await this.#
|
|
76
|
+
await this.#executeUtility(contractFunctionSimulator, privateSyncCall, [], execScopes, jobId),
|
|
76
77
|
anchorBlockHeader,
|
|
77
78
|
jobId,
|
|
78
79
|
filter.scopes,
|
package/src/logs/log_service.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/server';
|
|
|
6
6
|
import { DirectionalAppTaggingSecret, PendingTaggedLog, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
7
7
|
import type { BlockHeader } from '@aztec/stdlib/tx';
|
|
8
8
|
|
|
9
|
+
import type { AccessScopes } from '../access_scopes.js';
|
|
9
10
|
import type { LogRetrievalRequest } from '../contract_function_simulator/noir-structs/log_retrieval_request.js';
|
|
10
11
|
import { LogRetrievalResponse } from '../contract_function_simulator/noir-structs/log_retrieval_response.js';
|
|
11
12
|
import { AddressStore } from '../storage/address_store/address_store.js';
|
|
@@ -107,11 +108,7 @@ export class LogService {
|
|
|
107
108
|
);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
public async fetchTaggedLogs(
|
|
111
|
-
contractAddress: AztecAddress,
|
|
112
|
-
pendingTaggedLogArrayBaseSlot: Fr,
|
|
113
|
-
scopes?: AztecAddress[],
|
|
114
|
-
) {
|
|
111
|
+
public async fetchTaggedLogs(contractAddress: AztecAddress, pendingTaggedLogArrayBaseSlot: Fr, scopes: AccessScopes) {
|
|
115
112
|
this.log.verbose(`Fetching tagged logs for ${contractAddress.toString()}`);
|
|
116
113
|
|
|
117
114
|
// We only load logs from block up to and including the anchor block number
|
|
@@ -119,7 +116,7 @@ export class LogService {
|
|
|
119
116
|
const anchorBlockHash = await this.anchorBlockHeader.hash();
|
|
120
117
|
|
|
121
118
|
// Determine recipients: use scopes if provided, otherwise get all accounts
|
|
122
|
-
const recipients = scopes && scopes.length > 0 ? scopes : await this.keyStore.getAccounts();
|
|
119
|
+
const recipients = scopes !== 'ALL_SCOPES' && scopes.length > 0 ? scopes : await this.keyStore.getAccounts();
|
|
123
120
|
|
|
124
121
|
// For each recipient, fetch secrets, load logs, and store them.
|
|
125
122
|
// We run these per-recipient tasks in parallel so that logs are loaded for all recipients concurrently.
|
|
@@ -7,6 +7,7 @@ import { Note, NoteDao, NoteStatus } from '@aztec/stdlib/note';
|
|
|
7
7
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
8
8
|
import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
9
9
|
|
|
10
|
+
import type { AccessScopes } from '../access_scopes.js';
|
|
10
11
|
import type { NoteStore } from '../storage/note_store/note_store.js';
|
|
11
12
|
|
|
12
13
|
export class NoteService {
|
|
@@ -31,7 +32,7 @@ export class NoteService {
|
|
|
31
32
|
owner: AztecAddress | undefined,
|
|
32
33
|
storageSlot: Fr,
|
|
33
34
|
status: NoteStatus,
|
|
34
|
-
scopes
|
|
35
|
+
scopes: AccessScopes,
|
|
35
36
|
) {
|
|
36
37
|
const noteDaos = await this.noteStore.getNotes(
|
|
37
38
|
{
|
|
@@ -70,10 +71,10 @@ export class NoteService {
|
|
|
70
71
|
*
|
|
71
72
|
* @param contractAddress - The contract whose notes should be checked and nullified.
|
|
72
73
|
*/
|
|
73
|
-
public async syncNoteNullifiers(contractAddress: AztecAddress): Promise<void> {
|
|
74
|
+
public async syncNoteNullifiers(contractAddress: AztecAddress, scopes: AccessScopes): Promise<void> {
|
|
74
75
|
const anchorBlockHash = await this.anchorBlockHeader.hash();
|
|
75
76
|
|
|
76
|
-
const contractNotes = await this.noteStore.getNotes({ contractAddress }, this.jobId);
|
|
77
|
+
const contractNotes = await this.noteStore.getNotes({ contractAddress, scopes }, this.jobId);
|
|
77
78
|
|
|
78
79
|
if (contractNotes.length === 0) {
|
|
79
80
|
return;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
|
+
import type { NoteStatus } from '@aztec/stdlib/note';
|
|
4
|
+
|
|
5
|
+
import type { AccessScopes } from './access_scopes.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A filter used to fetch notes.
|
|
9
|
+
* @remarks This filter is applied as an intersection of all its params.
|
|
10
|
+
*/
|
|
11
|
+
export type NotesFilter = {
|
|
12
|
+
/**
|
|
13
|
+
* The contract address the note belongs to.
|
|
14
|
+
* @remarks Providing a contract address is required as we need that information to trigger private state sync.
|
|
15
|
+
*/
|
|
16
|
+
contractAddress: AztecAddress;
|
|
17
|
+
/** The owner of the note. */
|
|
18
|
+
owner?: AztecAddress;
|
|
19
|
+
/** The specific storage location of the note on the contract. */
|
|
20
|
+
storageSlot?: Fr;
|
|
21
|
+
/** The status of the note. Defaults to 'ACTIVE'. */
|
|
22
|
+
status?: NoteStatus;
|
|
23
|
+
/** The siloed nullifier for the note. */
|
|
24
|
+
siloedNullifier?: Fr;
|
|
25
|
+
scopes: AccessScopes;
|
|
26
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MAX_TX_LIFETIME } from '@aztec/constants';
|
|
2
2
|
import type { PrivateKernelCircuitPublicInputs } from '@aztec/stdlib/kernel';
|
|
3
3
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
4
4
|
|
|
@@ -8,12 +8,12 @@ const ROUNDED_DURATIONS = [
|
|
|
8
8
|
1, // 1 second
|
|
9
9
|
];
|
|
10
10
|
|
|
11
|
-
function roundTimestamp(blockTimestamp: bigint,
|
|
11
|
+
function roundTimestamp(blockTimestamp: bigint, expirationTimestamp: bigint): UInt64 {
|
|
12
12
|
return ROUNDED_DURATIONS.reduce((timestamp, duration) => {
|
|
13
13
|
if (timestamp <= blockTimestamp) {
|
|
14
14
|
// The timestamp must be greater than the block timestamp.
|
|
15
15
|
// If it is too small, round it down again using a smaller duration.
|
|
16
|
-
const totalDuration =
|
|
16
|
+
const totalDuration = expirationTimestamp - blockTimestamp;
|
|
17
17
|
const roundedDuration = totalDuration - (totalDuration % BigInt(duration));
|
|
18
18
|
return blockTimestamp + roundedDuration;
|
|
19
19
|
}
|
|
@@ -21,36 +21,36 @@ function roundTimestamp(blockTimestamp: bigint, includeByTimestamp: bigint): UIn
|
|
|
21
21
|
}, 0n);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function
|
|
24
|
+
export function computeTxExpirationTimestamp(
|
|
25
25
|
previousKernel: PrivateKernelCircuitPublicInputs,
|
|
26
|
-
|
|
26
|
+
txLifetime = MAX_TX_LIFETIME,
|
|
27
27
|
): UInt64 {
|
|
28
|
-
if (
|
|
28
|
+
if (txLifetime > MAX_TX_LIFETIME) {
|
|
29
29
|
throw new Error(
|
|
30
|
-
`Custom
|
|
30
|
+
`Custom tx lifetime cannot be greater than the max allowed. Max allowed: ${MAX_TX_LIFETIME}. Custom value: ${txLifetime}.`,
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const anchorBlockTimestamp = previousKernel.constants.anchorBlockHeader.globalVariables.timestamp;
|
|
35
|
-
const maxTimestamp = anchorBlockTimestamp + BigInt(
|
|
36
|
-
const
|
|
35
|
+
const maxTimestamp = anchorBlockTimestamp + BigInt(txLifetime);
|
|
36
|
+
const expirationTimestamp = previousKernel.expirationTimestamp;
|
|
37
37
|
|
|
38
|
-
// If the
|
|
38
|
+
// If the expirationTimestamp set during the tx execution is greater than or equal to the max allowed duration,
|
|
39
39
|
// use the maximum allowed timestamp.
|
|
40
40
|
// Note: It shouldn't be larger than the max allowed duration, but we check for it anyway.
|
|
41
|
-
if (
|
|
41
|
+
if (expirationTimestamp >= maxTimestamp) {
|
|
42
42
|
return maxTimestamp;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Round it down to the nearest hour/min/second to reduce precision and avoid revealing the exact value.
|
|
46
46
|
// This makes it harder for others to infer what function calls may have been used to produce a specific timestamp.
|
|
47
|
-
const roundedTimestamp = roundTimestamp(anchorBlockTimestamp,
|
|
47
|
+
const roundedTimestamp = roundTimestamp(anchorBlockTimestamp, expirationTimestamp);
|
|
48
48
|
|
|
49
49
|
// The tx can't be published if the timestamp is the same or less than the anchor block's timestamp.
|
|
50
50
|
// Future blocks will have a greater timestamp, so the tx would never be included.
|
|
51
51
|
if (roundedTimestamp <= anchorBlockTimestamp) {
|
|
52
52
|
throw new Error(
|
|
53
|
-
`Include-by timestamp must be greater than the anchor block timestamp. Anchor block timestamp: ${anchorBlockTimestamp}. Include-by timestamp: ${
|
|
53
|
+
`Include-by timestamp must be greater than the anchor block timestamp. Anchor block timestamp: ${anchorBlockTimestamp}. Include-by timestamp: ${expirationTimestamp}.`,
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './private_kernel_reset_private_inputs_builder.js';
|
|
2
|
-
export * from './
|
|
2
|
+
export * from './compute_tx_expiration_timestamp.js';
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
type PrivateKernelSimulateOutput,
|
|
27
27
|
ReadRequestActionEnum,
|
|
28
28
|
ReadRequestResetActions,
|
|
29
|
-
type
|
|
29
|
+
type ScopedKeyValidationRequestAndSeparator,
|
|
30
30
|
ScopedNoteHash,
|
|
31
31
|
ScopedNullifier,
|
|
32
32
|
ScopedReadRequest,
|
|
@@ -68,9 +68,9 @@ function getNullifierMembershipWitnessResolver(oracle: PrivateKernelOracle) {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
async function
|
|
71
|
+
async function getMasterSecretKeysAndKeyTypeDomainSeparators(
|
|
72
72
|
keyValidationRequests: ClaimedLengthArray<
|
|
73
|
-
|
|
73
|
+
ScopedKeyValidationRequestAndSeparator,
|
|
74
74
|
typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX
|
|
75
75
|
>,
|
|
76
76
|
numRequestsToVerify: number,
|
|
@@ -189,8 +189,8 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
189
189
|
this.previousKernel.validationRequests.nullifierReadRequests,
|
|
190
190
|
this.nullifierResetActions,
|
|
191
191
|
),
|
|
192
|
-
|
|
193
|
-
this.previousKernel.validationRequests.
|
|
192
|
+
getMasterSecretKeysAndKeyTypeDomainSeparators(
|
|
193
|
+
this.previousKernel.validationRequests.scopedKeyValidationRequestsAndSeparators,
|
|
194
194
|
dimensions.KEY_VALIDATION,
|
|
195
195
|
oracle,
|
|
196
196
|
),
|
|
@@ -357,8 +357,8 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
357
357
|
}
|
|
358
358
|
|
|
359
359
|
private needsResetNullifierKeys() {
|
|
360
|
-
const numCurr = this.previousKernel.validationRequests.
|
|
361
|
-
const numNext = this.nextIteration ? this.nextIteration.
|
|
360
|
+
const numCurr = this.previousKernel.validationRequests.scopedKeyValidationRequestsAndSeparators.claimedLength;
|
|
361
|
+
const numNext = this.nextIteration ? this.nextIteration.keyValidationRequestsAndSeparators.claimedLength : 0;
|
|
362
362
|
const maxAmountToKeep = !this.nextIteration ? 0 : MAX_KEY_VALIDATION_REQUESTS_PER_TX;
|
|
363
363
|
if (numCurr + numNext <= maxAmountToKeep) {
|
|
364
364
|
return false;
|
|
@@ -260,20 +260,20 @@ export class PrivateKernelExecutionProver {
|
|
|
260
260
|
// TODO: Enable padding once we better understand the final amounts to pad to.
|
|
261
261
|
const paddedSideEffectAmounts = PaddedSideEffectAmounts.empty();
|
|
262
262
|
|
|
263
|
-
// Use the aggregated
|
|
264
|
-
// TODO: Call `
|
|
265
|
-
const
|
|
263
|
+
// Use the aggregated expirationTimestamp set throughout the tx execution.
|
|
264
|
+
// TODO: Call `computeTxExpirationTimestamp` to round the value down and reduce precision, improving privacy.
|
|
265
|
+
const expirationTimestampUpperBound = previousKernelData.publicInputs.expirationTimestamp;
|
|
266
266
|
const anchorBlockTimestamp = previousKernelData.publicInputs.constants.anchorBlockHeader.globalVariables.timestamp;
|
|
267
|
-
if (
|
|
267
|
+
if (expirationTimestampUpperBound <= anchorBlockTimestamp) {
|
|
268
268
|
throw new Error(
|
|
269
|
-
`Include-by timestamp must be greater than the anchor block timestamp. Anchor block timestamp: ${anchorBlockTimestamp}. Include-by timestamp: ${
|
|
269
|
+
`Include-by timestamp must be greater than the anchor block timestamp. Anchor block timestamp: ${anchorBlockTimestamp}. Include-by timestamp: ${expirationTimestampUpperBound}.`,
|
|
270
270
|
);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
const privateInputs = new PrivateKernelTailCircuitPrivateInputs(
|
|
274
274
|
previousKernelData,
|
|
275
275
|
paddedSideEffectAmounts,
|
|
276
|
-
|
|
276
|
+
expirationTimestampUpperBound,
|
|
277
277
|
);
|
|
278
278
|
|
|
279
279
|
const witgenTimer = new Timer();
|
package/src/pxe.ts
CHANGED
|
@@ -47,11 +47,12 @@ import {
|
|
|
47
47
|
TxProfileResult,
|
|
48
48
|
TxProvingResult,
|
|
49
49
|
TxSimulationResult,
|
|
50
|
-
|
|
50
|
+
UtilityExecutionResult,
|
|
51
51
|
} from '@aztec/stdlib/tx';
|
|
52
52
|
|
|
53
53
|
import { inspect } from 'util';
|
|
54
54
|
|
|
55
|
+
import type { AccessScopes } from './access_scopes.js';
|
|
55
56
|
import { BlockSynchronizer } from './block_synchronizer/index.js';
|
|
56
57
|
import type { PXEConfig } from './config/index.js';
|
|
57
58
|
import { BenchmarkedNodeFactory } from './contract_function_simulator/benchmarked_node.js';
|
|
@@ -93,7 +94,7 @@ export type ProfileTxOpts = {
|
|
|
93
94
|
/** If true, proof generation is skipped during profiling. Defaults to true. */
|
|
94
95
|
skipProofGeneration?: boolean;
|
|
95
96
|
/** Addresses whose private state and keys are accessible during private execution. */
|
|
96
|
-
scopes
|
|
97
|
+
scopes: AccessScopes;
|
|
97
98
|
};
|
|
98
99
|
|
|
99
100
|
/** Options for PXE.simulateTx. */
|
|
@@ -106,16 +107,16 @@ export type SimulateTxOpts = {
|
|
|
106
107
|
skipFeeEnforcement?: boolean;
|
|
107
108
|
/** State overrides for the simulation, such as contract instances and artifacts. */
|
|
108
109
|
overrides?: SimulationOverrides;
|
|
109
|
-
/** Addresses whose private state and keys are accessible during private execution
|
|
110
|
-
scopes
|
|
110
|
+
/** Addresses whose private state and keys are accessible during private execution */
|
|
111
|
+
scopes: AccessScopes;
|
|
111
112
|
};
|
|
112
113
|
|
|
113
|
-
/** Options for PXE.
|
|
114
|
-
export type
|
|
114
|
+
/** Options for PXE.executeUtility. */
|
|
115
|
+
export type ExecuteUtilityOpts = {
|
|
115
116
|
/** The authentication witnesses required for the function call. */
|
|
116
117
|
authwits?: AuthWitness[];
|
|
117
|
-
/** The accounts whose notes we can access in this call
|
|
118
|
-
scopes
|
|
118
|
+
/** The accounts whose notes we can access in this call */
|
|
119
|
+
scopes: AccessScopes;
|
|
119
120
|
};
|
|
120
121
|
|
|
121
122
|
/** Args for PXE.create. */
|
|
@@ -263,7 +264,7 @@ export class PXE {
|
|
|
263
264
|
debugUtils.setPXEHelpers(
|
|
264
265
|
pxe.#putInJobQueue.bind(pxe),
|
|
265
266
|
pxe.#getSimulatorForTx.bind(pxe),
|
|
266
|
-
pxe.#
|
|
267
|
+
pxe.#executeUtility.bind(pxe),
|
|
267
268
|
);
|
|
268
269
|
|
|
269
270
|
pxe.jobQueue.start();
|
|
@@ -357,7 +358,7 @@ export class PXE {
|
|
|
357
358
|
async #executePrivate(
|
|
358
359
|
contractFunctionSimulator: ContractFunctionSimulator,
|
|
359
360
|
txRequest: TxExecutionRequest,
|
|
360
|
-
scopes:
|
|
361
|
+
scopes: AccessScopes,
|
|
361
362
|
jobId: string,
|
|
362
363
|
): Promise<PrivateExecutionResult> {
|
|
363
364
|
const { origin: contractAddress, functionSelector } = txRequest;
|
|
@@ -369,7 +370,7 @@ export class PXE {
|
|
|
369
370
|
contractAddress,
|
|
370
371
|
functionSelector,
|
|
371
372
|
(privateSyncCall, execScopes) =>
|
|
372
|
-
this.#
|
|
373
|
+
this.#executeUtility(contractFunctionSimulator, privateSyncCall, [], execScopes, jobId),
|
|
373
374
|
anchorBlockHeader,
|
|
374
375
|
jobId,
|
|
375
376
|
scopes,
|
|
@@ -393,20 +394,20 @@ export class PXE {
|
|
|
393
394
|
}
|
|
394
395
|
|
|
395
396
|
/**
|
|
396
|
-
*
|
|
397
|
+
* Execute a utility function call on the given contract.
|
|
397
398
|
* @param contractFunctionSimulator - The simulator to use for the function call.
|
|
398
399
|
* @param call - The function call to execute.
|
|
399
400
|
* @param authWitnesses - Authentication witnesses required for the function call.
|
|
400
401
|
* @param scopes - Optional array of account addresses whose notes can be accessed in this call. Defaults to all
|
|
401
402
|
* accounts if not specified.
|
|
402
403
|
* @param jobId - The job ID for staged writes.
|
|
403
|
-
* @returns The
|
|
404
|
+
* @returns The execution result containing the outputs of the utility function.
|
|
404
405
|
*/
|
|
405
|
-
async #
|
|
406
|
+
async #executeUtility(
|
|
406
407
|
contractFunctionSimulator: ContractFunctionSimulator,
|
|
407
408
|
call: FunctionCall,
|
|
408
409
|
authWitnesses: AuthWitness[] | undefined,
|
|
409
|
-
scopes:
|
|
410
|
+
scopes: AccessScopes,
|
|
410
411
|
jobId: string,
|
|
411
412
|
) {
|
|
412
413
|
try {
|
|
@@ -927,6 +928,7 @@ export class PXE {
|
|
|
927
928
|
({ publicInputs, executionSteps } = await generateSimulatedProvingResult(
|
|
928
929
|
privateExecutionResult,
|
|
929
930
|
(addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
|
|
931
|
+
this.node,
|
|
930
932
|
));
|
|
931
933
|
} else {
|
|
932
934
|
// Kernel logic, plus proving of all private functions and kernels.
|
|
@@ -1004,23 +1006,23 @@ export class PXE {
|
|
|
1004
1006
|
inspect(txRequest),
|
|
1005
1007
|
`simulatePublic=${simulatePublic}`,
|
|
1006
1008
|
`skipTxValidation=${skipTxValidation}`,
|
|
1007
|
-
`scopes=${scopes
|
|
1009
|
+
`scopes=${scopes === 'ALL_SCOPES' ? scopes : scopes.map(s => s.toString()).join(', ')}`,
|
|
1008
1010
|
);
|
|
1009
1011
|
}
|
|
1010
1012
|
});
|
|
1011
1013
|
}
|
|
1012
1014
|
|
|
1013
1015
|
/**
|
|
1014
|
-
*
|
|
1016
|
+
* Executes a contract utility function.
|
|
1015
1017
|
* @param call - The function call containing the function details, arguments, and target contract address.
|
|
1016
1018
|
*/
|
|
1017
|
-
public
|
|
1019
|
+
public executeUtility(
|
|
1018
1020
|
call: FunctionCall,
|
|
1019
|
-
{ authwits, scopes }:
|
|
1020
|
-
): Promise<
|
|
1021
|
-
// We disable concurrent
|
|
1021
|
+
{ authwits, scopes }: ExecuteUtilityOpts = { scopes: 'ALL_SCOPES' },
|
|
1022
|
+
): Promise<UtilityExecutionResult> {
|
|
1023
|
+
// We disable concurrent executions since those might execute oracles which read and write to the PXE stores (e.g.
|
|
1022
1024
|
// to the capsules), and we need to prevent concurrent runs from interfering with one another (e.g. attempting to
|
|
1023
|
-
// delete the same read value, or reading values that another
|
|
1025
|
+
// delete the same read value, or reading values that another execution is currently modifying).
|
|
1024
1026
|
return this.#putInJobQueue(async jobId => {
|
|
1025
1027
|
try {
|
|
1026
1028
|
const totalTimer = new Timer();
|
|
@@ -1035,13 +1037,13 @@ export class PXE {
|
|
|
1035
1037
|
call.to,
|
|
1036
1038
|
call.selector,
|
|
1037
1039
|
(privateSyncCall, execScopes) =>
|
|
1038
|
-
this.#
|
|
1040
|
+
this.#executeUtility(contractFunctionSimulator, privateSyncCall, [], execScopes, jobId),
|
|
1039
1041
|
anchorBlockHeader,
|
|
1040
1042
|
jobId,
|
|
1041
1043
|
scopes,
|
|
1042
1044
|
);
|
|
1043
1045
|
|
|
1044
|
-
const executionResult = await this.#
|
|
1046
|
+
const executionResult = await this.#executeUtility(
|
|
1045
1047
|
contractFunctionSimulator,
|
|
1046
1048
|
call,
|
|
1047
1049
|
authwits ?? [],
|
|
@@ -1068,8 +1070,8 @@ export class PXE {
|
|
|
1068
1070
|
const stringifiedArgs = args.map(arg => arg.toString()).join(', ');
|
|
1069
1071
|
throw this.#contextualizeError(
|
|
1070
1072
|
err,
|
|
1071
|
-
`
|
|
1072
|
-
`scopes=${scopes
|
|
1073
|
+
`executeUtility ${to}:${name}(${stringifiedArgs})`,
|
|
1074
|
+
`scopes=${scopes === 'ALL_SCOPES' ? scopes : scopes.map(s => s.toString()).join(', ')}`,
|
|
1073
1075
|
);
|
|
1074
1076
|
}
|
|
1075
1077
|
});
|
|
@@ -1106,7 +1108,7 @@ export class PXE {
|
|
|
1106
1108
|
filter.contractAddress,
|
|
1107
1109
|
null,
|
|
1108
1110
|
async (privateSyncCall, execScopes) =>
|
|
1109
|
-
await this.#
|
|
1111
|
+
await this.#executeUtility(contractFunctionSimulator, privateSyncCall, [], execScopes, jobId),
|
|
1110
1112
|
anchorBlockHeader,
|
|
1111
1113
|
jobId,
|
|
1112
1114
|
filter.scopes,
|
|
@@ -3,9 +3,10 @@ import type { Fr } from '@aztec/foundation/schemas';
|
|
|
3
3
|
import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
|
|
4
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
5
|
import type { DataInBlock } from '@aztec/stdlib/block';
|
|
6
|
-
import { NoteDao, NoteStatus
|
|
6
|
+
import { NoteDao, NoteStatus } from '@aztec/stdlib/note';
|
|
7
7
|
|
|
8
8
|
import type { StagedStore } from '../../job_coordinator/job_coordinator.js';
|
|
9
|
+
import type { NotesFilter } from '../../notes_filter.js';
|
|
9
10
|
import { StoredNote } from './stored_note.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -105,7 +106,7 @@ export class NoteStore implements StagedStore {
|
|
|
105
106
|
* returned once if this is the case)
|
|
106
107
|
*/
|
|
107
108
|
getNotes(filter: NotesFilter, jobId: string): Promise<NoteDao[]> {
|
|
108
|
-
if (filter.scopes !==
|
|
109
|
+
if (filter.scopes !== 'ALL_SCOPES' && filter.scopes.length === 0) {
|
|
109
110
|
return Promise.resolve([]);
|
|
110
111
|
}
|
|
111
112
|
|
|
@@ -179,7 +180,10 @@ export class NoteStore implements StagedStore {
|
|
|
179
180
|
continue;
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
if (
|
|
183
|
+
if (
|
|
184
|
+
filter.scopes !== 'ALL_SCOPES' &&
|
|
185
|
+
note.scopes.intersection(new Set(filter.scopes.map(s => s.toString()))).size === 0
|
|
186
|
+
) {
|
|
183
187
|
continue;
|
|
184
188
|
}
|
|
185
189
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
2
2
|
import type { BlockHash } from '@aztec/stdlib/block';
|
|
3
|
-
import { MAX_LOGS_PER_TAG } from '@aztec/stdlib/interfaces/api-limit';
|
|
3
|
+
import { MAX_LOGS_PER_TAG, MAX_RPC_LEN } from '@aztec/stdlib/interfaces/api-limit';
|
|
4
4
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
5
5
|
import type { SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
6
6
|
|
|
@@ -31,6 +31,26 @@ async function getAllPages<T>(numTags: number, fetchPage: (page: number) => Prom
|
|
|
31
31
|
return allResultsPerTag;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Splits tags into chunks of MAX_RPC_LEN, fetches logs for each chunk using getAllPages, then stitches the results
|
|
36
|
+
* back into a single array preserving the original tag order.
|
|
37
|
+
*/
|
|
38
|
+
async function getAllPagesInBatches<Tag, T>(
|
|
39
|
+
tags: Tag[],
|
|
40
|
+
fetchAllPagesForBatch: (batch: Tag[]) => Promise<T[][]>,
|
|
41
|
+
): Promise<T[][]> {
|
|
42
|
+
if (tags.length <= MAX_RPC_LEN) {
|
|
43
|
+
return fetchAllPagesForBatch(tags);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const batches: Tag[][] = [];
|
|
47
|
+
for (let i = 0; i < tags.length; i += MAX_RPC_LEN) {
|
|
48
|
+
batches.push(tags.slice(i, i + MAX_RPC_LEN));
|
|
49
|
+
}
|
|
50
|
+
const batchResults = await Promise.all(batches.map(fetchAllPagesForBatch));
|
|
51
|
+
return batchResults.flat();
|
|
52
|
+
}
|
|
53
|
+
|
|
34
54
|
/**
|
|
35
55
|
* Fetches all private logs for the given tags, automatically paginating through all pages.
|
|
36
56
|
* @param aztecNode - The Aztec node to query.
|
|
@@ -44,7 +64,9 @@ export function getAllPrivateLogsByTags(
|
|
|
44
64
|
tags: SiloedTag[],
|
|
45
65
|
anchorBlockHash: BlockHash,
|
|
46
66
|
): Promise<TxScopedL2Log[][]> {
|
|
47
|
-
return
|
|
67
|
+
return getAllPagesInBatches(tags, batch =>
|
|
68
|
+
getAllPages(batch.length, page => aztecNode.getPrivateLogsByTags(batch, page, anchorBlockHash)),
|
|
69
|
+
);
|
|
48
70
|
}
|
|
49
71
|
|
|
50
72
|
/**
|
|
@@ -62,7 +84,9 @@ export function getAllPublicLogsByTagsFromContract(
|
|
|
62
84
|
tags: Tag[],
|
|
63
85
|
anchorBlockHash: BlockHash,
|
|
64
86
|
): Promise<TxScopedL2Log[][]> {
|
|
65
|
-
return
|
|
66
|
-
|
|
87
|
+
return getAllPagesInBatches(tags, batch =>
|
|
88
|
+
getAllPages(batch.length, page =>
|
|
89
|
+
aztecNode.getPublicLogsByTagsFromContract(contractAddress, batch, page, anchorBlockHash),
|
|
90
|
+
),
|
|
67
91
|
);
|
|
68
92
|
}
|
|
@@ -30,7 +30,7 @@ export async function loadPrivateLogsForSenderRecipientPair(
|
|
|
30
30
|
// (highestAgedIndex, highestFinalizedIndex + WINDOW_LEN]
|
|
31
31
|
//
|
|
32
32
|
// highestAgedIndex is the highest index that was used in a tx that is included in a block at least
|
|
33
|
-
// `
|
|
33
|
+
// `MAX_TX_LIFETIME` seconds ago.
|
|
34
34
|
// highestFinalizedIndex is the highest index that was used in a tx that is included in a finalized block.
|
|
35
35
|
//
|
|
36
36
|
// "(" denotes an open end of the range - the index is not included in the range.
|
|
@@ -42,19 +42,19 @@ export async function loadPrivateLogsForSenderRecipientPair(
|
|
|
42
42
|
// ever appear.
|
|
43
43
|
//
|
|
44
44
|
// This relies on the "maximum inclusion timestamp" rule enforced by the kernel and rollup circuits:
|
|
45
|
-
// - a transaction's maximum inclusion timestamp is at most `
|
|
45
|
+
// - a transaction's maximum inclusion timestamp is at most `MAX_TX_LIFETIME` seconds after
|
|
46
46
|
// the timestamp of its anchor block; and
|
|
47
47
|
// - a rollup only includes transactions whose inclusion timestamp is >= the L2 block's timestamp.
|
|
48
48
|
//
|
|
49
49
|
// Suppose some device used index `I` in a transaction anchored to block `B_N` at time `N`, and that block is now at
|
|
50
|
-
// least `
|
|
50
|
+
// least `MAX_TX_LIFETIME` seconds in the past. Then there is no possibility of any *other* device
|
|
51
51
|
// trying to use an index <= `I` while anchoring to a *newer* block than `B_N` because if we were anchoring to
|
|
52
52
|
// a newer block than `B_N` then we would already have seen the log with index `I` and hence the device would have
|
|
53
53
|
// chosen a larger index.
|
|
54
54
|
// If that *other* device would anchor to a block older than `B_N` then that tx could never be included in a block
|
|
55
55
|
// because it would already have been expired.
|
|
56
56
|
//
|
|
57
|
-
// Therefore, once we see that index `I` has been used in a block that is at least `
|
|
57
|
+
// Therefore, once we see that index `I` has been used in a block that is at least `MAX_TX_LIFETIME`
|
|
58
58
|
// seconds old, we can safely stop syncing logs for all indexes <= `I` and set highestAgedIndex = `I`.
|
|
59
59
|
//
|
|
60
60
|
// ## Explanation of the upper bound `highestFinalizedIndex + WINDOW_LEN`
|