@aztec/pxe 0.0.1-commit.ec5f612 → 0.0.1-commit.ec7ac5448
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_synchronizer.d.ts +1 -1
- package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
- package/dest/block_synchronizer/block_synchronizer.js +6 -0
- package/dest/config/index.d.ts +2 -2
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.d.ts +10 -5
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +31 -8
- 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/execution_tagging_index_cache.d.ts +5 -5
- package/dest/contract_function_simulator/execution_tagging_index_cache.d.ts.map +1 -1
- package/dest/contract_function_simulator/execution_tagging_index_cache.js +17 -9
- package/dest/contract_function_simulator/index.d.ts +2 -1
- package/dest/contract_function_simulator/index.d.ts.map +1 -1
- package/dest/contract_function_simulator/index.js +1 -0
- package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts +4 -6
- package/dest/contract_function_simulator/noir-structs/event_validation_request.d.ts.map +1 -1
- package/dest/contract_function_simulator/noir-structs/event_validation_request.js +8 -10
- 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 +2 -2
- package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts.map +1 -1
- package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +2 -4
- package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +4 -7
- 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 +6 -11
- package/dest/contract_function_simulator/oracle/interfaces.d.ts +61 -45
- package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts +9 -0
- package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.d.ts.map +1 -0
- package/dest/contract_function_simulator/oracle/legacy_oracle_mappings.js +47 -0
- package/dest/contract_function_simulator/oracle/oracle.d.ts +75 -44
- package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/oracle.js +281 -96
- package/dest/contract_function_simulator/oracle/private_execution.js +5 -3
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +23 -49
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.js +40 -63
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +89 -56
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +272 -107
- 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 +9 -2
- 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_logging.d.ts +9 -4
- package/dest/contract_logging.d.ts.map +1 -1
- package/dest/contract_logging.js +21 -6
- package/dest/contract_sync/contract_sync_service.d.ts +6 -5
- package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
- package/dest/contract_sync/contract_sync_service.js +44 -37
- package/dest/contract_sync/helpers.d.ts +2 -3
- package/dest/contract_sync/helpers.d.ts.map +1 -1
- package/dest/contract_sync/helpers.js +7 -2
- package/dest/debug/pxe_debug_utils.d.ts +3 -3
- package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
- package/dest/entrypoints/client/bundle/index.d.ts +1 -2
- package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
- package/dest/entrypoints/client/bundle/index.js +0 -1
- 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/index.d.ts +1 -2
- package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
- package/dest/entrypoints/client/lazy/index.js +0 -1
- 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 -3
- package/dest/entrypoints/server/index.d.ts.map +1 -1
- package/dest/entrypoints/server/index.js +1 -2
- 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 +3 -2
- package/dest/events/event_service.d.ts.map +1 -1
- package/dest/events/event_service.js +16 -4
- package/dest/logs/log_service.d.ts +5 -8
- package/dest/logs/log_service.d.ts.map +1 -1
- package/dest/logs/log_service.js +24 -37
- package/dest/messages/message_context_service.d.ts +17 -0
- package/dest/messages/message_context_service.d.ts.map +1 -0
- package/dest/messages/message_context_service.js +36 -0
- package/dest/notes/note_service.d.ts +4 -5
- package/dest/notes/note_service.d.ts.map +1 -1
- package/dest/notes/note_service.js +14 -5
- package/dest/notes_filter.d.ts +2 -3
- package/dest/notes_filter.d.ts.map +1 -1
- 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/pxe.d.ts +11 -8
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +45 -26
- package/dest/storage/capsule_store/capsule_service.d.ts +21 -0
- package/dest/storage/capsule_store/capsule_service.d.ts.map +1 -0
- package/dest/storage/capsule_store/capsule_service.js +50 -0
- package/dest/storage/capsule_store/capsule_store.d.ts +9 -9
- package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
- package/dest/storage/capsule_store/capsule_store.js +33 -28
- package/dest/storage/capsule_store/index.d.ts +2 -1
- package/dest/storage/capsule_store/index.d.ts.map +1 -1
- package/dest/storage/capsule_store/index.js +1 -0
- package/dest/storage/metadata.d.ts +1 -1
- package/dest/storage/metadata.js +1 -1
- package/dest/storage/note_store/note_store.d.ts +1 -1
- package/dest/storage/note_store/note_store.d.ts.map +1 -1
- package/dest/storage/note_store/note_store.js +2 -2
- package/dest/storage/tagging_store/sender_tagging_store.d.ts +26 -25
- package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
- package/dest/storage/tagging_store/sender_tagging_store.js +141 -115
- package/dest/tagging/index.d.ts +2 -2
- package/dest/tagging/index.d.ts.map +1 -1
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts +1 -1
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts.map +1 -1
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +10 -1
- package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts +4 -3
- package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts.map +1 -1
- package/dest/tagging/sender_sync/utils/get_status_change_of_pending.js +20 -10
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +2 -1
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +24 -11
- package/package.json +16 -16
- package/src/bin/check_oracle_version.ts +4 -4
- package/src/block_synchronizer/block_synchronizer.ts +6 -0
- package/src/config/index.ts +1 -1
- package/src/contract_function_simulator/contract_function_simulator.ts +44 -12
- package/src/contract_function_simulator/ephemeral_array_service.ts +110 -0
- package/src/contract_function_simulator/execution_tagging_index_cache.ts +16 -11
- package/src/contract_function_simulator/index.ts +1 -0
- package/src/contract_function_simulator/noir-structs/event_validation_request.ts +9 -9
- package/src/contract_function_simulator/noir-structs/log_retrieval_request.ts +1 -1
- package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +2 -5
- package/src/contract_function_simulator/noir-structs/note_validation_request.ts +4 -10
- package/src/contract_function_simulator/oracle/interfaces.ts +82 -54
- package/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +104 -0
- package/src/contract_function_simulator/oracle/oracle.ts +363 -139
- package/src/contract_function_simulator/oracle/private_execution.ts +4 -4
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +45 -84
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +444 -143
- package/src/contract_function_simulator/pick_notes.ts +9 -2
- package/src/contract_function_simulator/proxied_contract_data_source.ts +8 -1
- package/src/contract_logging.ts +18 -5
- package/src/contract_sync/contract_sync_service.ts +77 -59
- package/src/contract_sync/helpers.ts +4 -4
- package/src/debug/pxe_debug_utils.ts +3 -3
- package/src/entrypoints/client/bundle/index.ts +0 -1
- package/src/entrypoints/client/bundle/utils.ts +2 -3
- package/src/entrypoints/client/lazy/index.ts +0 -1
- 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 -2
- package/src/entrypoints/server/utils.ts +2 -3
- package/src/events/event_service.ts +17 -4
- package/src/logs/log_service.ts +52 -78
- package/src/messages/message_context_service.ts +44 -0
- package/src/notes/note_service.ts +18 -8
- package/src/notes_filter.ts +1 -3
- package/src/oracle_version.ts +20 -10
- package/src/pxe.ts +68 -31
- package/src/storage/capsule_store/capsule_service.ts +90 -0
- package/src/storage/capsule_store/capsule_store.ts +34 -26
- package/src/storage/capsule_store/index.ts +1 -0
- package/src/storage/metadata.ts +1 -1
- package/src/storage/note_store/note_store.ts +2 -5
- package/src/storage/tagging_store/sender_tagging_store.ts +182 -135
- package/src/tagging/index.ts +1 -1
- package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +19 -1
- package/src/tagging/sender_sync/utils/get_status_change_of_pending.ts +26 -11
- package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +19 -9
- package/dest/access_scopes.d.ts +0 -9
- package/dest/access_scopes.d.ts.map +0 -1
- package/dest/access_scopes.js +0 -6
- package/src/access_scopes.ts +0 -9
|
@@ -6,33 +6,36 @@ import { Point } from '@aztec/foundation/curves/grumpkin';
|
|
|
6
6
|
import { LogLevels, type Logger, createLogger } from '@aztec/foundation/log';
|
|
7
7
|
import type { MembershipWitness } from '@aztec/foundation/trees';
|
|
8
8
|
import type { KeyStore } from '@aztec/key-store';
|
|
9
|
+
import { isProtocolContract } from '@aztec/protocol-contracts';
|
|
9
10
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
10
11
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
11
12
|
import { BlockHash } from '@aztec/stdlib/block';
|
|
12
|
-
import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract';
|
|
13
|
+
import type { CompleteAddress, ContractInstance, PartialAddress } from '@aztec/stdlib/contract';
|
|
13
14
|
import { siloNullifier } from '@aztec/stdlib/hash';
|
|
14
15
|
import type { AztecNode } from '@aztec/stdlib/interfaces/server';
|
|
15
16
|
import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
|
|
16
|
-
import { computeAddressSecret } from '@aztec/stdlib/keys';
|
|
17
|
-
import {
|
|
17
|
+
import { type PublicKeys, computeAddressSecret } from '@aztec/stdlib/keys';
|
|
18
|
+
import { MessageContext, deriveAppSiloedSharedSecret } from '@aztec/stdlib/logs';
|
|
18
19
|
import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
|
|
19
20
|
import type { NoteStatus } from '@aztec/stdlib/note';
|
|
20
21
|
import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
21
|
-
import type { BlockHeader, Capsule } from '@aztec/stdlib/tx';
|
|
22
|
+
import type { BlockHeader, Capsule, OffchainEffect } from '@aztec/stdlib/tx';
|
|
22
23
|
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
24
|
+
import { createContractLogger, logContractMessage, stripAztecnrLogPrefix } from '../../contract_logging.js';
|
|
25
|
+
import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
|
|
25
26
|
import { EventService } from '../../events/event_service.js';
|
|
26
27
|
import { LogService } from '../../logs/log_service.js';
|
|
28
|
+
import { MessageContextService } from '../../messages/message_context_service.js';
|
|
27
29
|
import { NoteService } from '../../notes/note_service.js';
|
|
28
|
-
import {
|
|
30
|
+
import { ORACLE_VERSION_MAJOR } from '../../oracle_version.js';
|
|
29
31
|
import type { AddressStore } from '../../storage/address_store/address_store.js';
|
|
30
|
-
import type {
|
|
32
|
+
import type { CapsuleService } from '../../storage/capsule_store/capsule_service.js';
|
|
31
33
|
import type { ContractStore } from '../../storage/contract_store/contract_store.js';
|
|
32
34
|
import type { NoteStore } from '../../storage/note_store/note_store.js';
|
|
33
35
|
import type { PrivateEventStore } from '../../storage/private_event_store/private_event_store.js';
|
|
34
36
|
import type { RecipientTaggingStore } from '../../storage/tagging_store/recipient_tagging_store.js';
|
|
35
37
|
import type { SenderAddressBookStore } from '../../storage/tagging_store/sender_address_book_store.js';
|
|
38
|
+
import { EphemeralArrayService } from '../ephemeral_array_service.js';
|
|
36
39
|
import { EventValidationRequest } from '../noir-structs/event_validation_request.js';
|
|
37
40
|
import { LogRetrievalRequest } from '../noir-structs/log_retrieval_request.js';
|
|
38
41
|
import { LogRetrievalResponse } from '../noir-structs/log_retrieval_response.js';
|
|
@@ -56,11 +59,13 @@ export type UtilityExecutionOracleArgs = {
|
|
|
56
59
|
aztecNode: AztecNode;
|
|
57
60
|
recipientTaggingStore: RecipientTaggingStore;
|
|
58
61
|
senderAddressBookStore: SenderAddressBookStore;
|
|
59
|
-
|
|
62
|
+
capsuleService: CapsuleService;
|
|
60
63
|
privateEventStore: PrivateEventStore;
|
|
64
|
+
messageContextService: MessageContextService;
|
|
65
|
+
contractSyncService: ContractSyncService;
|
|
61
66
|
jobId: string;
|
|
62
67
|
log?: ReturnType<typeof createLogger>;
|
|
63
|
-
scopes:
|
|
68
|
+
scopes: AztecAddress[];
|
|
64
69
|
};
|
|
65
70
|
|
|
66
71
|
/**
|
|
@@ -71,6 +76,12 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
71
76
|
isUtility = true as const;
|
|
72
77
|
|
|
73
78
|
private contractLogger: Logger | undefined;
|
|
79
|
+
private aztecnrLogger: Logger | undefined;
|
|
80
|
+
private offchainEffects: OffchainEffect[] = [];
|
|
81
|
+
private readonly ephemeralArrayService = new EphemeralArrayService();
|
|
82
|
+
|
|
83
|
+
// We store oracle version to be able to show a nice error message when an oracle handler is missing.
|
|
84
|
+
private contractOracleVersion: { major: number; minor: number } | undefined;
|
|
74
85
|
|
|
75
86
|
protected readonly contractAddress: AztecAddress;
|
|
76
87
|
protected readonly authWitnesses: AuthWitness[];
|
|
@@ -83,11 +94,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
83
94
|
protected readonly aztecNode: AztecNode;
|
|
84
95
|
protected readonly recipientTaggingStore: RecipientTaggingStore;
|
|
85
96
|
protected readonly senderAddressBookStore: SenderAddressBookStore;
|
|
86
|
-
protected readonly
|
|
97
|
+
protected readonly capsuleService: CapsuleService;
|
|
87
98
|
protected readonly privateEventStore: PrivateEventStore;
|
|
99
|
+
protected readonly messageContextService: MessageContextService;
|
|
100
|
+
protected readonly contractSyncService: ContractSyncService;
|
|
88
101
|
protected readonly jobId: string;
|
|
89
|
-
protected
|
|
90
|
-
protected readonly scopes:
|
|
102
|
+
protected logger: ReturnType<typeof createLogger>;
|
|
103
|
+
protected readonly scopes: AztecAddress[];
|
|
91
104
|
|
|
92
105
|
constructor(args: UtilityExecutionOracleArgs) {
|
|
93
106
|
this.contractAddress = args.contractAddress;
|
|
@@ -101,24 +114,60 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
101
114
|
this.aztecNode = args.aztecNode;
|
|
102
115
|
this.recipientTaggingStore = args.recipientTaggingStore;
|
|
103
116
|
this.senderAddressBookStore = args.senderAddressBookStore;
|
|
104
|
-
this.
|
|
117
|
+
this.capsuleService = args.capsuleService;
|
|
105
118
|
this.privateEventStore = args.privateEventStore;
|
|
119
|
+
this.messageContextService = args.messageContextService;
|
|
120
|
+
this.contractSyncService = args.contractSyncService;
|
|
106
121
|
this.jobId = args.jobId;
|
|
107
|
-
this.
|
|
122
|
+
this.logger = args.log ?? createLogger('simulator:client_view_context');
|
|
108
123
|
this.scopes = args.scopes;
|
|
109
124
|
}
|
|
110
125
|
|
|
111
|
-
public
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
public assertCompatibleOracleVersion(major: number, minor: number): void {
|
|
127
|
+
// TODO(F-416): Remove this hack on v5 when protocol contracts are redeployed.
|
|
128
|
+
// Protocol contracts/canonical contracts shipped with committed bytecode that cannot be changed. Assert they use
|
|
129
|
+
// the expected pinned version or the current one. We want to allow for both the pinned and the current versions
|
|
130
|
+
// because we want this code to work with both the pinned and unpinned version since some branches do not have the
|
|
131
|
+
// pinned contracts (like e.g. next)
|
|
132
|
+
const LEGACY_ORACLE_VERSION = 12;
|
|
133
|
+
if (isProtocolContract(this.contractAddress)) {
|
|
134
|
+
if (major !== LEGACY_ORACLE_VERSION && major !== ORACLE_VERSION_MAJOR) {
|
|
135
|
+
const hint =
|
|
136
|
+
major > ORACLE_VERSION_MAJOR
|
|
137
|
+
? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
|
|
138
|
+
: 'The contract was compiled with an older version of Aztec.nr than your private environment supports. Recompile the contract with a compatible version of Aztec.nr.';
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${LEGACY_ORACLE_VERSION} or ${ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
this.contractOracleVersion = { major, minor };
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (major !== ORACLE_VERSION_MAJOR) {
|
|
148
|
+
const hint =
|
|
149
|
+
major > ORACLE_VERSION_MAJOR
|
|
150
|
+
? 'The contract was compiled with a newer version of Aztec.nr than your private environment supports. Upgrade your private environment to a compatible version.'
|
|
151
|
+
: 'The contract was compiled with an older version of Aztec.nr than your private environment supports. Recompile the contract with a compatible version of Aztec.nr.';
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Incompatible private environment version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
154
|
+
);
|
|
114
155
|
}
|
|
156
|
+
|
|
157
|
+
// Major matches - store both major and minor for later diagnostics (e.g. when an oracle is not found)
|
|
158
|
+
this.contractOracleVersion = { major, minor };
|
|
115
159
|
}
|
|
116
160
|
|
|
117
|
-
|
|
161
|
+
// Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
|
|
162
|
+
public nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
|
|
163
|
+
return this.contractOracleVersion;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public getRandomField(): Fr {
|
|
118
167
|
return Fr.random();
|
|
119
168
|
}
|
|
120
169
|
|
|
121
|
-
public
|
|
170
|
+
public getUtilityContext(): UtilityContext {
|
|
122
171
|
return new UtilityContext(this.anchorBlockHeader, this.contractAddress);
|
|
123
172
|
}
|
|
124
173
|
|
|
@@ -129,34 +178,33 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
129
178
|
* @throws If the keys are not registered in the key store.
|
|
130
179
|
* @throws If scopes are defined and the account is not in the scopes.
|
|
131
180
|
*/
|
|
132
|
-
public async
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
|
|
138
|
-
hasAccess = true;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
if (!hasAccess) {
|
|
142
|
-
throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
|
|
181
|
+
public async getKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
|
|
182
|
+
let hasAccess = false;
|
|
183
|
+
for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
|
|
184
|
+
if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
|
|
185
|
+
hasAccess = true;
|
|
143
186
|
}
|
|
144
187
|
}
|
|
188
|
+
if (!hasAccess) {
|
|
189
|
+
throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
|
|
190
|
+
}
|
|
145
191
|
return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
|
|
146
192
|
}
|
|
147
193
|
|
|
148
194
|
/**
|
|
149
195
|
* Fetches the index and sibling path of a leaf at a given block from the note hash tree.
|
|
150
|
-
* @param
|
|
151
|
-
* witness.
|
|
196
|
+
* @param blockHash - The hash of a block that contains the note hash tree root in which to find the
|
|
197
|
+
* membership witness.
|
|
152
198
|
* @param noteHash - The note hash to find in the note hash tree.
|
|
153
199
|
* @returns The membership witness containing the leaf index and sibling path
|
|
154
200
|
*/
|
|
155
|
-
public
|
|
156
|
-
|
|
201
|
+
public getNoteHashMembershipWitness(
|
|
202
|
+
blockHash: BlockHash,
|
|
157
203
|
noteHash: Fr,
|
|
158
204
|
): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
|
|
159
|
-
return this
|
|
205
|
+
return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
|
|
206
|
+
this.aztecNode.getNoteHashMembershipWitness(blockHash, noteHash),
|
|
207
|
+
);
|
|
160
208
|
}
|
|
161
209
|
|
|
162
210
|
/**
|
|
@@ -165,16 +213,21 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
165
213
|
* Block hashes are the leaves of the archive tree. Each time a new block is added to the chain,
|
|
166
214
|
* its block hash is appended as a new leaf to the archive tree.
|
|
167
215
|
*
|
|
168
|
-
* @param
|
|
216
|
+
* @param referenceBlockHash - The hash of a block that contains the archive tree root in which to find the membership
|
|
169
217
|
* witness.
|
|
170
218
|
* @param blockHash - The block hash to find in the archive tree.
|
|
171
219
|
* @returns The membership witness containing the leaf index and sibling path
|
|
172
220
|
*/
|
|
173
|
-
public
|
|
174
|
-
|
|
221
|
+
public getBlockHashMembershipWitness(
|
|
222
|
+
referenceBlockHash: BlockHash,
|
|
175
223
|
blockHash: BlockHash,
|
|
176
224
|
): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
|
|
177
|
-
|
|
225
|
+
// Note that we validate that the reference block hash is at or before the anchor block - we don't test the block
|
|
226
|
+
// hash at all. If the block hash did not exist by the reference block hash, then the node will not return the
|
|
227
|
+
// membership witness as there is none.
|
|
228
|
+
return this.#queryWithBlockHashNotAfterAnchor(referenceBlockHash, () =>
|
|
229
|
+
this.aztecNode.getBlockHashMembershipWitness(referenceBlockHash, blockHash),
|
|
230
|
+
);
|
|
178
231
|
}
|
|
179
232
|
|
|
180
233
|
/**
|
|
@@ -183,11 +236,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
183
236
|
* @param nullifier - Nullifier we try to find witness for.
|
|
184
237
|
* @returns The nullifier membership witness (if found).
|
|
185
238
|
*/
|
|
186
|
-
public
|
|
239
|
+
public getNullifierMembershipWitness(
|
|
187
240
|
blockHash: BlockHash,
|
|
188
241
|
nullifier: Fr,
|
|
189
242
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
190
|
-
return this
|
|
243
|
+
return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
|
|
244
|
+
this.aztecNode.getNullifierMembershipWitness(blockHash, nullifier),
|
|
245
|
+
);
|
|
191
246
|
}
|
|
192
247
|
|
|
193
248
|
/**
|
|
@@ -199,11 +254,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
199
254
|
* list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
|
|
200
255
|
* we are trying to prove non-inclusion for.
|
|
201
256
|
*/
|
|
202
|
-
public
|
|
257
|
+
public getLowNullifierMembershipWitness(
|
|
203
258
|
blockHash: BlockHash,
|
|
204
259
|
nullifier: Fr,
|
|
205
260
|
): Promise<NullifierMembershipWitness | undefined> {
|
|
206
|
-
return this
|
|
261
|
+
return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
|
|
262
|
+
this.aztecNode.getLowNullifierMembershipWitness(blockHash, nullifier),
|
|
263
|
+
);
|
|
207
264
|
}
|
|
208
265
|
|
|
209
266
|
/**
|
|
@@ -212,8 +269,10 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
212
269
|
* @param leafSlot - The slot of the public data tree to get the witness for.
|
|
213
270
|
* @returns - The witness
|
|
214
271
|
*/
|
|
215
|
-
public
|
|
216
|
-
return this
|
|
272
|
+
public getPublicDataWitness(blockHash: BlockHash, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
|
|
273
|
+
return this.#queryWithBlockHashNotAfterAnchor(blockHash, () =>
|
|
274
|
+
this.aztecNode.getPublicDataWitness(blockHash, leafSlot),
|
|
275
|
+
);
|
|
217
276
|
}
|
|
218
277
|
|
|
219
278
|
/**
|
|
@@ -221,7 +280,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
221
280
|
* @param blockNumber - The number of a block of which to get the block header.
|
|
222
281
|
* @returns Block extracted from a block with block number `blockNumber`.
|
|
223
282
|
*/
|
|
224
|
-
public async
|
|
283
|
+
public async getBlockHeader(blockNumber: BlockNumber): Promise<BlockHeader | undefined> {
|
|
225
284
|
const anchorBlockNumber = this.anchorBlockHeader.getBlockNumber();
|
|
226
285
|
if (blockNumber > anchorBlockNumber) {
|
|
227
286
|
throw new Error(`Block number ${blockNumber} is higher than current block ${anchorBlockNumber}`);
|
|
@@ -232,12 +291,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
232
291
|
}
|
|
233
292
|
|
|
234
293
|
/**
|
|
235
|
-
* Retrieve the
|
|
294
|
+
* Retrieve the public keys and partial address associated to a given address.
|
|
236
295
|
* @param account - The account address.
|
|
237
|
-
* @returns
|
|
296
|
+
* @returns The public keys and partial address, or `undefined` if the account is not registered.
|
|
238
297
|
*/
|
|
239
|
-
public
|
|
240
|
-
|
|
298
|
+
public async getPublicKeysAndPartialAddress(
|
|
299
|
+
account: AztecAddress,
|
|
300
|
+
): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined> {
|
|
301
|
+
const completeAddress = await this.addressStore.getCompleteAddress(account);
|
|
302
|
+
if (!completeAddress) {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
return { publicKeys: completeAddress.publicKeys, partialAddress: completeAddress.partialAddress };
|
|
241
306
|
}
|
|
242
307
|
|
|
243
308
|
protected async getCompleteAddressOrFail(account: AztecAddress): Promise<CompleteAddress> {
|
|
@@ -256,11 +321,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
256
321
|
* @param address - Address.
|
|
257
322
|
* @returns A contract instance.
|
|
258
323
|
*/
|
|
259
|
-
public
|
|
260
|
-
return this.getContractInstance(address);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
protected async getContractInstance(address: AztecAddress): Promise<ContractInstance> {
|
|
324
|
+
public async getContractInstance(address: AztecAddress): Promise<ContractInstance> {
|
|
264
325
|
const instance = await this.contractStore.getContractInstance(address);
|
|
265
326
|
if (!instance) {
|
|
266
327
|
throw new Error(`No contract instance found for address ${address.toString()}`);
|
|
@@ -274,7 +335,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
274
335
|
* @param messageHash - Hash of the message to authenticate.
|
|
275
336
|
* @returns Authentication witness for the requested message hash.
|
|
276
337
|
*/
|
|
277
|
-
public
|
|
338
|
+
public getAuthWitness(messageHash: Fr): Promise<Fr[] | undefined> {
|
|
278
339
|
return Promise.resolve(this.authWitnesses.find(w => w.requestHash.equals(messageHash))?.witness);
|
|
279
340
|
}
|
|
280
341
|
|
|
@@ -300,7 +361,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
300
361
|
* @param status - The status of notes to fetch.
|
|
301
362
|
* @returns Array of note data.
|
|
302
363
|
*/
|
|
303
|
-
public async
|
|
364
|
+
public async getNotes(
|
|
304
365
|
owner: AztecAddress | undefined,
|
|
305
366
|
storageSlot: Fr,
|
|
306
367
|
numSelects: number,
|
|
@@ -340,7 +401,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
340
401
|
* @param innerNullifier - The inner nullifier.
|
|
341
402
|
* @returns A boolean indicating whether the nullifier exists in the tree or not.
|
|
342
403
|
*/
|
|
343
|
-
public async
|
|
404
|
+
public async doesNullifierExist(innerNullifier: Fr) {
|
|
344
405
|
const [nullifier, anchorBlockHash] = await Promise.all([
|
|
345
406
|
siloNullifier(this.contractAddress, innerNullifier!),
|
|
346
407
|
this.anchorBlockHeader.hash(),
|
|
@@ -352,19 +413,20 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
352
413
|
}
|
|
353
414
|
|
|
354
415
|
/**
|
|
355
|
-
*
|
|
416
|
+
* Returns the membership witness of an un-nullified L1 to L2 message.
|
|
356
417
|
* @param contractAddress - Address of a contract by which the message was emitted.
|
|
357
418
|
* @param messageHash - Hash of the message.
|
|
358
419
|
* @param secret - Secret used to compute a nullifier.
|
|
359
420
|
* @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
|
|
360
421
|
* @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
|
|
361
422
|
*/
|
|
362
|
-
public async
|
|
423
|
+
public async getL1ToL2MembershipWitness(contractAddress: AztecAddress, messageHash: Fr, secret: Fr) {
|
|
363
424
|
const [messageIndex, siblingPath] = await getNonNullifiedL1ToL2MessageWitness(
|
|
364
425
|
this.aztecNode,
|
|
365
426
|
contractAddress,
|
|
366
427
|
messageHash,
|
|
367
428
|
secret,
|
|
429
|
+
await this.anchorBlockHeader.hash(),
|
|
368
430
|
);
|
|
369
431
|
|
|
370
432
|
return new MessageLoadOracleInputs(messageIndex, siblingPath);
|
|
@@ -377,29 +439,31 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
377
439
|
* @param startStorageSlot - The starting storage slot.
|
|
378
440
|
* @param numberOfElements - Number of elements to read from the starting storage slot.
|
|
379
441
|
*/
|
|
380
|
-
public
|
|
442
|
+
public getFromPublicStorage(
|
|
381
443
|
blockHash: BlockHash,
|
|
382
444
|
contractAddress: AztecAddress,
|
|
383
445
|
startStorageSlot: Fr,
|
|
384
446
|
numberOfElements: number,
|
|
385
447
|
) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
448
|
+
return this.#queryWithBlockHashNotAfterAnchor(blockHash, async () => {
|
|
449
|
+
const slots = Array(numberOfElements)
|
|
450
|
+
.fill(0)
|
|
451
|
+
.map((_, i) => new Fr(startStorageSlot.value + BigInt(i)));
|
|
389
452
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
453
|
+
const values = await Promise.all(
|
|
454
|
+
slots.map(storageSlot => this.aztecNode.getPublicStorageAt(blockHash, contractAddress, storageSlot)),
|
|
455
|
+
);
|
|
393
456
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
457
|
+
this.logger.debug(
|
|
458
|
+
`Oracle storage read: slots=[${slots.map(slot => slot.toString()).join(', ')}] address=${contractAddress.toString()} values=[${values.join(', ')}]`,
|
|
459
|
+
);
|
|
397
460
|
|
|
398
|
-
|
|
461
|
+
return values;
|
|
462
|
+
});
|
|
399
463
|
}
|
|
400
464
|
|
|
401
465
|
/**
|
|
402
|
-
* Returns a per-contract logger whose output is prefixed with `
|
|
466
|
+
* Returns a per-contract logger whose output is prefixed with `contract:<name>(<addrAbbrev>)`.
|
|
403
467
|
*/
|
|
404
468
|
async #getContractLogger(): Promise<Logger> {
|
|
405
469
|
if (!this.contractLogger) {
|
|
@@ -408,66 +472,157 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
408
472
|
this.contractLogger = await createContractLogger(
|
|
409
473
|
this.contractAddress,
|
|
410
474
|
addr => this.contractStore.getDebugContractName(addr),
|
|
475
|
+
'user',
|
|
411
476
|
{ instanceId: this.jobId },
|
|
412
477
|
);
|
|
413
478
|
}
|
|
414
479
|
return this.contractLogger;
|
|
415
480
|
}
|
|
416
481
|
|
|
417
|
-
|
|
482
|
+
/**
|
|
483
|
+
* Returns a per-contract logger whose output is prefixed with `aztecnr:<name>(<addrAbbrev>)`.
|
|
484
|
+
*/
|
|
485
|
+
async #getAztecnrLogger(): Promise<Logger> {
|
|
486
|
+
if (!this.aztecnrLogger) {
|
|
487
|
+
// Purpose of instanceId is to distinguish logs from different instances of the same component. It makes sense
|
|
488
|
+
// to re-use jobId as instanceId here as executions of different PXE jobs are isolated.
|
|
489
|
+
this.aztecnrLogger = await createContractLogger(
|
|
490
|
+
this.contractAddress,
|
|
491
|
+
addr => this.contractStore.getDebugContractName(addr),
|
|
492
|
+
'aztecnr',
|
|
493
|
+
{ instanceId: this.jobId },
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
return this.aztecnrLogger;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
public async log(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
418
500
|
if (!LogLevels[level]) {
|
|
419
501
|
throw new Error(`Invalid log level: ${level}`);
|
|
420
502
|
}
|
|
421
|
-
|
|
422
|
-
|
|
503
|
+
|
|
504
|
+
const { kind, message: strippedMessage } = stripAztecnrLogPrefix(message);
|
|
505
|
+
|
|
506
|
+
const logger = kind == 'aztecnr' ? await this.#getAztecnrLogger() : await this.#getContractLogger();
|
|
507
|
+
logContractMessage(logger, LogLevels[level], strippedMessage, fields);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
|
|
511
|
+
public async getPendingTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr, scope: AztecAddress) {
|
|
512
|
+
const logService = this.#createLogService();
|
|
513
|
+
const logs = await logService.fetchTaggedLogs(this.contractAddress, scope);
|
|
514
|
+
await this.capsuleService.appendToCapsuleArray(
|
|
515
|
+
this.contractAddress,
|
|
516
|
+
pendingTaggedLogArrayBaseSlot,
|
|
517
|
+
logs.map(log => log.toFields()),
|
|
518
|
+
this.jobId,
|
|
519
|
+
scope,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** Fetches pending tagged logs into a freshly allocated ephemeral array and returns its base slot. */
|
|
524
|
+
public async getPendingTaggedLogsV2(scope: AztecAddress): Promise<Fr> {
|
|
525
|
+
const logService = this.#createLogService();
|
|
526
|
+
const logs = await logService.fetchTaggedLogs(this.contractAddress, scope);
|
|
527
|
+
return this.ephemeralArrayService.newArray(logs.map(log => log.toFields()));
|
|
423
528
|
}
|
|
424
529
|
|
|
425
|
-
|
|
426
|
-
|
|
530
|
+
#createLogService(): LogService {
|
|
531
|
+
return new LogService(
|
|
427
532
|
this.aztecNode,
|
|
428
533
|
this.anchorBlockHeader,
|
|
429
534
|
this.keyStore,
|
|
430
|
-
this.capsuleStore,
|
|
431
535
|
this.recipientTaggingStore,
|
|
432
536
|
this.senderAddressBookStore,
|
|
433
537
|
this.addressStore,
|
|
434
538
|
this.jobId,
|
|
435
|
-
this.
|
|
539
|
+
this.logger.getBindings(),
|
|
436
540
|
);
|
|
437
|
-
|
|
438
|
-
await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
|
|
439
541
|
}
|
|
440
542
|
|
|
441
543
|
/**
|
|
442
|
-
*
|
|
443
|
-
* `enqueue_event_for_validation`, inserting them into the note database and event store respectively, making them
|
|
444
|
-
* queryable via `get_notes` and `getPrivateEvents`.
|
|
544
|
+
* Legacy: validates note/event requests stored in capsule arrays.
|
|
445
545
|
*
|
|
446
|
-
*
|
|
447
|
-
* @param contractAddress - The address of the contract that the logs are tagged for.
|
|
448
|
-
* @param noteValidationRequestsArrayBaseSlot - The base slot of capsule array containing note validation requests.
|
|
449
|
-
* @param eventValidationRequestsArrayBaseSlot - The base slot of capsule array containing event validation requests.
|
|
546
|
+
* Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
|
|
450
547
|
*/
|
|
451
|
-
public async
|
|
548
|
+
public async validateAndStoreEnqueuedNotesAndEvents(
|
|
452
549
|
contractAddress: AztecAddress,
|
|
453
550
|
noteValidationRequestsArrayBaseSlot: Fr,
|
|
454
551
|
eventValidationRequestsArrayBaseSlot: Fr,
|
|
552
|
+
maxNotePackedLen: number,
|
|
553
|
+
maxEventSerializedLen: number,
|
|
554
|
+
scope: AztecAddress,
|
|
455
555
|
) {
|
|
456
556
|
// TODO(#10727): allow other contracts to store notes
|
|
457
557
|
if (!this.contractAddress.equals(contractAddress)) {
|
|
458
558
|
throw new Error(`Got a note validation request from ${contractAddress}, expected ${this.contractAddress}`);
|
|
459
559
|
}
|
|
460
560
|
|
|
461
|
-
// We read all note and event validation requests and process them all concurrently. This makes the process much
|
|
462
|
-
// faster as we don't need to wait for the network round-trip.
|
|
463
561
|
const noteValidationRequests = (
|
|
464
|
-
await this.
|
|
465
|
-
|
|
562
|
+
await this.capsuleService.readCapsuleArray(
|
|
563
|
+
contractAddress,
|
|
564
|
+
noteValidationRequestsArrayBaseSlot,
|
|
565
|
+
this.jobId,
|
|
566
|
+
scope,
|
|
567
|
+
)
|
|
568
|
+
).map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
|
|
466
569
|
|
|
467
570
|
const eventValidationRequests = (
|
|
468
|
-
await this.
|
|
469
|
-
|
|
571
|
+
await this.capsuleService.readCapsuleArray(
|
|
572
|
+
contractAddress,
|
|
573
|
+
eventValidationRequestsArrayBaseSlot,
|
|
574
|
+
this.jobId,
|
|
575
|
+
scope,
|
|
576
|
+
)
|
|
577
|
+
).map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
|
|
578
|
+
|
|
579
|
+
await this.#processValidationRequests(noteValidationRequests, eventValidationRequests, scope);
|
|
470
580
|
|
|
581
|
+
await this.capsuleService.setCapsuleArray(
|
|
582
|
+
contractAddress,
|
|
583
|
+
noteValidationRequestsArrayBaseSlot,
|
|
584
|
+
[],
|
|
585
|
+
this.jobId,
|
|
586
|
+
scope,
|
|
587
|
+
);
|
|
588
|
+
await this.capsuleService.setCapsuleArray(
|
|
589
|
+
contractAddress,
|
|
590
|
+
eventValidationRequestsArrayBaseSlot,
|
|
591
|
+
[],
|
|
592
|
+
this.jobId,
|
|
593
|
+
scope,
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
public async validateAndStoreEnqueuedNotesAndEventsV2(
|
|
598
|
+
noteValidationRequestsArrayBaseSlot: Fr,
|
|
599
|
+
eventValidationRequestsArrayBaseSlot: Fr,
|
|
600
|
+
maxNotePackedLen: number,
|
|
601
|
+
maxEventSerializedLen: number,
|
|
602
|
+
scope: AztecAddress,
|
|
603
|
+
) {
|
|
604
|
+
const noteValidationRequests = this.ephemeralArrayService
|
|
605
|
+
.readArrayAt(noteValidationRequestsArrayBaseSlot)
|
|
606
|
+
.map(fields => NoteValidationRequest.fromFields(fields, maxNotePackedLen));
|
|
607
|
+
|
|
608
|
+
const eventValidationRequests = this.ephemeralArrayService
|
|
609
|
+
.readArrayAt(eventValidationRequestsArrayBaseSlot)
|
|
610
|
+
.map(fields => EventValidationRequest.fromFields(fields, maxEventSerializedLen));
|
|
611
|
+
|
|
612
|
+
await this.#processValidationRequests(noteValidationRequests, eventValidationRequests, scope);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Dispatches note and event validation requests to the service layer.
|
|
617
|
+
*
|
|
618
|
+
* This function is an auxiliary to support legacy (capsule backed) and new (ephemeral array backed) versions of the
|
|
619
|
+
* `validateAndStoreEnqueuedNotesAndEvents` oracle.
|
|
620
|
+
*/
|
|
621
|
+
async #processValidationRequests(
|
|
622
|
+
noteValidationRequests: NoteValidationRequest[],
|
|
623
|
+
eventValidationRequests: EventValidationRequest[],
|
|
624
|
+
scope: AztecAddress,
|
|
625
|
+
) {
|
|
471
626
|
const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
|
|
472
627
|
const noteStorePromises = noteValidationRequests.map(request =>
|
|
473
628
|
noteService.validateAndStoreNote(
|
|
@@ -480,7 +635,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
480
635
|
request.noteHash,
|
|
481
636
|
request.nullifier,
|
|
482
637
|
request.txHash,
|
|
483
|
-
|
|
638
|
+
scope,
|
|
484
639
|
),
|
|
485
640
|
);
|
|
486
641
|
|
|
@@ -493,21 +648,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
493
648
|
request.serializedEvent,
|
|
494
649
|
request.eventCommitment,
|
|
495
650
|
request.txHash,
|
|
496
|
-
|
|
651
|
+
scope,
|
|
497
652
|
),
|
|
498
653
|
);
|
|
499
654
|
|
|
500
655
|
await Promise.all([...noteStorePromises, ...eventStorePromises]);
|
|
501
|
-
|
|
502
|
-
// Requests are cleared once we're done.
|
|
503
|
-
await this.capsuleStore.setCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, [], this.jobId);
|
|
504
|
-
await this.capsuleStore.setCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, [], this.jobId);
|
|
505
656
|
}
|
|
506
657
|
|
|
507
|
-
public async
|
|
658
|
+
public async getLogsByTag(
|
|
508
659
|
contractAddress: AztecAddress,
|
|
509
660
|
logRetrievalRequestsArrayBaseSlot: Fr,
|
|
510
661
|
logRetrievalResponsesArrayBaseSlot: Fr,
|
|
662
|
+
scope: AztecAddress,
|
|
511
663
|
) {
|
|
512
664
|
// TODO(#10727): allow other contracts to process partial notes
|
|
513
665
|
if (!this.contractAddress.equals(contractAddress)) {
|
|
@@ -517,101 +669,250 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
517
669
|
// We read all log retrieval requests and process them all concurrently. This makes the process much faster as we
|
|
518
670
|
// don't need to wait for the network round-trip.
|
|
519
671
|
const logRetrievalRequests = (
|
|
520
|
-
await this.
|
|
672
|
+
await this.capsuleService.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId, scope)
|
|
521
673
|
).map(LogRetrievalRequest.fromFields);
|
|
522
674
|
|
|
523
|
-
const logService =
|
|
524
|
-
|
|
525
|
-
this.anchorBlockHeader,
|
|
526
|
-
this.keyStore,
|
|
527
|
-
this.capsuleStore,
|
|
528
|
-
this.recipientTaggingStore,
|
|
529
|
-
this.senderAddressBookStore,
|
|
530
|
-
this.addressStore,
|
|
531
|
-
this.jobId,
|
|
532
|
-
this.log.getBindings(),
|
|
533
|
-
);
|
|
534
|
-
|
|
535
|
-
const maybeLogRetrievalResponses = await logService.bulkRetrieveLogs(logRetrievalRequests);
|
|
675
|
+
const logService = this.#createLogService();
|
|
676
|
+
const maybeLogRetrievalResponses = await logService.fetchLogsByTag(contractAddress, logRetrievalRequests);
|
|
536
677
|
|
|
537
678
|
// Requests are cleared once we're done.
|
|
538
|
-
await this.
|
|
679
|
+
await this.capsuleService.setCapsuleArray(
|
|
680
|
+
contractAddress,
|
|
681
|
+
logRetrievalRequestsArrayBaseSlot,
|
|
682
|
+
[],
|
|
683
|
+
this.jobId,
|
|
684
|
+
scope,
|
|
685
|
+
);
|
|
539
686
|
|
|
540
687
|
// The responses are stored as Option<LogRetrievalResponse> in a second CapsuleArray.
|
|
541
|
-
await this.
|
|
688
|
+
await this.capsuleService.setCapsuleArray(
|
|
542
689
|
contractAddress,
|
|
543
690
|
logRetrievalResponsesArrayBaseSlot,
|
|
544
691
|
maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption),
|
|
545
692
|
this.jobId,
|
|
693
|
+
scope,
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
public async getLogsByTagV2(requestArrayBaseSlot: Fr): Promise<Fr> {
|
|
698
|
+
const logRetrievalRequests = this.ephemeralArrayService
|
|
699
|
+
.readArrayAt(requestArrayBaseSlot)
|
|
700
|
+
.map(LogRetrievalRequest.fromFields);
|
|
701
|
+
const logService = this.#createLogService();
|
|
702
|
+
|
|
703
|
+
const maybeLogRetrievalResponses = await logService.fetchLogsByTag(this.contractAddress, logRetrievalRequests);
|
|
704
|
+
|
|
705
|
+
return this.ephemeralArrayService.newArray(maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Deprecated, only kept for backwards compatibility until Alpha v5 rolls out.
|
|
709
|
+
public async getMessageContextsByTxHash(
|
|
710
|
+
contractAddress: AztecAddress,
|
|
711
|
+
messageContextRequestsArrayBaseSlot: Fr,
|
|
712
|
+
messageContextResponsesArrayBaseSlot: Fr,
|
|
713
|
+
scope: AztecAddress,
|
|
714
|
+
) {
|
|
715
|
+
try {
|
|
716
|
+
if (!this.contractAddress.equals(contractAddress)) {
|
|
717
|
+
throw new Error(`Got a message context request from ${contractAddress}, expected ${this.contractAddress}`);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// TODO(@mverzilli): this is a prime example of where using an ephemeral array would make much more sense, we don't
|
|
721
|
+
// need scopes here, we just need a bit of shared memory to cross boundaries between Noir and TS.
|
|
722
|
+
// At the same time, we don't want to allow any global scope access other than where backwards compatibility
|
|
723
|
+
// forces us to. Hence we need the scope here to be artificial.
|
|
724
|
+
const requestCapsules = await this.capsuleService.readCapsuleArray(
|
|
725
|
+
contractAddress,
|
|
726
|
+
messageContextRequestsArrayBaseSlot,
|
|
727
|
+
this.jobId,
|
|
728
|
+
scope,
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
const txHashes = requestCapsules.map((fields, i) => {
|
|
732
|
+
if (fields.length !== 1) {
|
|
733
|
+
throw new Error(
|
|
734
|
+
`Malformed message context request at index ${i}: expected 1 field (tx hash), got ${fields.length}`,
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
return fields[0];
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
|
|
741
|
+
txHashes,
|
|
742
|
+
this.anchorBlockHeader.getBlockNumber(),
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
// Leave response in response capsule array.
|
|
746
|
+
await this.capsuleService.setCapsuleArray(
|
|
747
|
+
contractAddress,
|
|
748
|
+
messageContextResponsesArrayBaseSlot,
|
|
749
|
+
maybeMessageContexts.map(MessageContext.toSerializedOption),
|
|
750
|
+
this.jobId,
|
|
751
|
+
scope,
|
|
752
|
+
);
|
|
753
|
+
} finally {
|
|
754
|
+
await this.capsuleService.setCapsuleArray(
|
|
755
|
+
contractAddress,
|
|
756
|
+
messageContextRequestsArrayBaseSlot,
|
|
757
|
+
[],
|
|
758
|
+
this.jobId,
|
|
759
|
+
scope,
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/** Reads tx hash requests from an ephemeral array, resolves their contexts, and returns the response slot. */
|
|
765
|
+
public async getMessageContextsByTxHashV2(requestArrayBaseSlot: Fr): Promise<Fr> {
|
|
766
|
+
const requestFields = this.ephemeralArrayService.readArrayAt(requestArrayBaseSlot);
|
|
767
|
+
|
|
768
|
+
const txHashes = requestFields.map((fields, i) => {
|
|
769
|
+
if (fields.length !== 1) {
|
|
770
|
+
throw new Error(
|
|
771
|
+
`Malformed message context request at index ${i}: expected 1 field (tx hash), got ${fields.length}`,
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
return fields[0];
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
const maybeMessageContexts = await this.messageContextService.getMessageContextsByTxHash(
|
|
778
|
+
txHashes,
|
|
779
|
+
this.anchorBlockHeader.getBlockNumber(),
|
|
546
780
|
);
|
|
781
|
+
|
|
782
|
+
return this.ephemeralArrayService.newArray(maybeMessageContexts.map(MessageContext.toSerializedOption));
|
|
547
783
|
}
|
|
548
784
|
|
|
549
|
-
public
|
|
785
|
+
public setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], scope: AztecAddress): void {
|
|
550
786
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
551
787
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
552
788
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
553
789
|
}
|
|
554
|
-
this.
|
|
555
|
-
return Promise.resolve();
|
|
790
|
+
this.capsuleService.setCapsule(contractAddress, slot, capsule, this.jobId, scope);
|
|
556
791
|
}
|
|
557
792
|
|
|
558
|
-
public
|
|
793
|
+
public getCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): Promise<Fr[] | null> {
|
|
559
794
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
560
795
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
561
796
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
562
797
|
}
|
|
563
|
-
return (
|
|
564
|
-
// TODO(#12425): On the following line, the pertinent capsule gets overshadowed by the transient one. Tackle this.
|
|
565
|
-
this.capsules.find(c => c.contractAddress.equals(contractAddress) && c.storageSlot.equals(slot))?.data ??
|
|
566
|
-
(await this.capsuleStore.loadCapsule(this.contractAddress, slot, this.jobId))
|
|
567
|
-
);
|
|
798
|
+
return this.capsuleService.getCapsule(contractAddress, slot, this.jobId, scope, this.capsules);
|
|
568
799
|
}
|
|
569
800
|
|
|
570
|
-
public
|
|
801
|
+
public deleteCapsule(contractAddress: AztecAddress, slot: Fr, scope: AztecAddress): void {
|
|
571
802
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
572
803
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
573
804
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
574
805
|
}
|
|
575
|
-
this.
|
|
576
|
-
return Promise.resolve();
|
|
806
|
+
this.capsuleService.deleteCapsule(contractAddress, slot, this.jobId, scope);
|
|
577
807
|
}
|
|
578
808
|
|
|
579
|
-
public
|
|
809
|
+
public copyCapsule(
|
|
580
810
|
contractAddress: AztecAddress,
|
|
581
811
|
srcSlot: Fr,
|
|
582
812
|
dstSlot: Fr,
|
|
583
813
|
numEntries: number,
|
|
814
|
+
scope: AztecAddress,
|
|
584
815
|
): Promise<void> {
|
|
585
816
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
586
817
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
587
818
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
588
819
|
}
|
|
589
|
-
return this.
|
|
820
|
+
return this.capsuleService.copyCapsule(contractAddress, srcSlot, dstSlot, numEntries, this.jobId, scope);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Clears cached sync state for a contract for a set of scopes, forcing re-sync on the next query so that newly
|
|
825
|
+
* stored notes or events are discovered.
|
|
826
|
+
*/
|
|
827
|
+
public setContractSyncCacheInvalid(contractAddress: AztecAddress, scopes: AztecAddress[]): void {
|
|
828
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
829
|
+
throw new Error(`Contract ${this.contractAddress} cannot invalidate sync cache of ${contractAddress}`);
|
|
830
|
+
}
|
|
831
|
+
this.contractSyncService.invalidateContractForScopes(contractAddress, scopes);
|
|
590
832
|
}
|
|
591
833
|
|
|
592
834
|
// TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
|
|
593
|
-
public
|
|
835
|
+
public decryptAes128(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
|
|
594
836
|
const aes128 = new Aes128();
|
|
595
837
|
return aes128.decryptBufferCBC(ciphertext, iv, symKey);
|
|
596
838
|
}
|
|
597
839
|
|
|
598
840
|
/**
|
|
599
|
-
* Retrieves the shared secret for a given address and ephemeral public key.
|
|
841
|
+
* Retrieves the app-siloed shared secret for a given address and ephemeral public key.
|
|
600
842
|
* @param address - The address to get the secret for.
|
|
601
843
|
* @param ephPk - The ephemeral public key to get the secret for.
|
|
602
|
-
* @
|
|
844
|
+
* @param contractAddress - The contract address for app-siloing (validated against execution context).
|
|
845
|
+
* @returns The app-siloed shared secret as a Field.
|
|
603
846
|
*/
|
|
604
|
-
public
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
847
|
+
public async getSharedSecret(address: AztecAddress, ephPk: Point, contractAddress: AztecAddress): Promise<Fr> {
|
|
848
|
+
if (!contractAddress.equals(this.contractAddress)) {
|
|
849
|
+
throw new Error(
|
|
850
|
+
`getSharedSecret called with contract address ${contractAddress}, expected ${this.contractAddress}`,
|
|
851
|
+
);
|
|
852
|
+
}
|
|
610
853
|
const recipientCompleteAddress = await this.getCompleteAddressOrFail(address);
|
|
611
854
|
const ivskM = await this.keyStore.getMasterSecretKey(
|
|
612
855
|
recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
|
|
613
856
|
);
|
|
614
857
|
const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
|
|
615
|
-
return
|
|
858
|
+
return deriveAppSiloedSharedSecret(addressSecret, ephPk, this.contractAddress);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
public pushEphemeral(slot: Fr, elements: Fr[]): number {
|
|
862
|
+
return this.ephemeralArrayService.push(slot, elements);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
public popEphemeral(slot: Fr): Fr[] {
|
|
866
|
+
return this.ephemeralArrayService.pop(slot);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
public getEphemeral(slot: Fr, index: number): Fr[] {
|
|
870
|
+
return this.ephemeralArrayService.get(slot, index);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
public setEphemeral(slot: Fr, index: number, elements: Fr[]): void {
|
|
874
|
+
this.ephemeralArrayService.set(slot, index, elements);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
public getEphemeralLen(slot: Fr): number {
|
|
878
|
+
return this.ephemeralArrayService.len(slot);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
public removeEphemeral(slot: Fr, index: number): void {
|
|
882
|
+
this.ephemeralArrayService.remove(slot, index);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
public clearEphemeral(slot: Fr): void {
|
|
886
|
+
this.ephemeralArrayService.clear(slot);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
public emitOffchainEffect(data: Fr[]): Promise<void> {
|
|
890
|
+
this.offchainEffects.push({ data, contractAddress: this.contractAddress });
|
|
891
|
+
return Promise.resolve();
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/** Returns offchain effects collected during execution. */
|
|
895
|
+
public getOffchainEffects(): OffchainEffect[] {
|
|
896
|
+
return this.offchainEffects;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/** Runs a query concurrently with a validation that the block hash is not ahead of the anchor block. */
|
|
900
|
+
async #queryWithBlockHashNotAfterAnchor<T>(blockHash: BlockHash, query: () => Promise<T>): Promise<T> {
|
|
901
|
+
const [response] = await Promise.all([
|
|
902
|
+
query(),
|
|
903
|
+
(async () => {
|
|
904
|
+
const header = await this.aztecNode.getBlockHeader(blockHash);
|
|
905
|
+
if (!header) {
|
|
906
|
+
throw new Error(`Could not find block header for block hash ${blockHash}`);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
if (header.getBlockNumber() > this.anchorBlockHeader.getBlockNumber()) {
|
|
910
|
+
throw new Error(
|
|
911
|
+
`Made a node query with a reference block hash ${blockHash} with block number ${header.getBlockNumber()}, which is ahead of the anchor block number ${this.anchorBlockHeader.getBlockNumber()} (from anchor block hash ${await this.anchorBlockHeader.hash()}).`,
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
})(),
|
|
915
|
+
]);
|
|
916
|
+
return response;
|
|
616
917
|
}
|
|
617
918
|
}
|