@aztec/pxe 0.80.0 → 0.81.0
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/pxe_oracle_interface/pxe_oracle_interface.d.ts +7 -6
- package/dest/pxe_oracle_interface/pxe_oracle_interface.d.ts.map +1 -1
- package/dest/pxe_oracle_interface/pxe_oracle_interface.js +41 -76
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +6 -6
- package/dest/storage/note_data_provider/note_dao.d.ts +9 -13
- package/dest/storage/note_data_provider/note_dao.d.ts.map +1 -1
- package/dest/storage/note_data_provider/note_dao.js +11 -15
- package/dest/storage/note_data_provider/note_data_provider.d.ts +2 -2
- package/dest/storage/note_data_provider/note_data_provider.d.ts.map +1 -1
- package/dest/storage/note_data_provider/note_data_provider.js +18 -19
- package/dest/synchronizer/synchronizer.js +1 -1
- package/package.json +15 -15
- package/src/pxe_oracle_interface/pxe_oracle_interface.ts +52 -113
- package/src/pxe_service/pxe_service.ts +10 -17
- package/src/storage/note_data_provider/note_dao.ts +9 -18
- package/src/storage/note_data_provider/note_data_provider.ts +22 -28
- package/src/synchronizer/synchronizer.ts +1 -1
- package/dest/note_decryption_utils/add_public_values_to_payload.d.ts +0 -11
- package/dest/note_decryption_utils/add_public_values_to_payload.d.ts.map +0 -1
- package/dest/note_decryption_utils/add_public_values_to_payload.js +0 -47
- package/src/note_decryption_utils/add_public_values_to_payload.ts +0 -64
|
@@ -13,14 +13,14 @@ export class NoteDataProvider {
|
|
|
13
13
|
#nullifiedNotesByContract;
|
|
14
14
|
#nullifiedNotesByStorageSlot;
|
|
15
15
|
#nullifiedNotesByTxHash;
|
|
16
|
-
#
|
|
16
|
+
#nullifiedNotesByRecipient;
|
|
17
17
|
#nullifiedNotesByNullifier;
|
|
18
18
|
#scopes;
|
|
19
19
|
#notesToScope;
|
|
20
20
|
#notesByContractAndScope;
|
|
21
21
|
#notesByStorageSlotAndScope;
|
|
22
22
|
#notesByTxHashAndScope;
|
|
23
|
-
#
|
|
23
|
+
#notesByRecipientAndScope;
|
|
24
24
|
constructor(store){
|
|
25
25
|
this.#store = store;
|
|
26
26
|
this.#notes = store.openMap('notes');
|
|
@@ -31,14 +31,14 @@ export class NoteDataProvider {
|
|
|
31
31
|
this.#nullifiedNotesByContract = store.openMultiMap('nullified_notes_by_contract');
|
|
32
32
|
this.#nullifiedNotesByStorageSlot = store.openMultiMap('nullified_notes_by_storage_slot');
|
|
33
33
|
this.#nullifiedNotesByTxHash = store.openMultiMap('nullified_notes_by_tx_hash');
|
|
34
|
-
this.#
|
|
34
|
+
this.#nullifiedNotesByRecipient = store.openMultiMap('nullified_notes_by_recipient');
|
|
35
35
|
this.#nullifiedNotesByNullifier = store.openMap('nullified_notes_by_nullifier');
|
|
36
36
|
this.#scopes = store.openMap('scopes');
|
|
37
37
|
this.#notesToScope = store.openMultiMap('notes_to_scope');
|
|
38
38
|
this.#notesByContractAndScope = new Map();
|
|
39
39
|
this.#notesByStorageSlotAndScope = new Map();
|
|
40
40
|
this.#notesByTxHashAndScope = new Map();
|
|
41
|
-
this.#
|
|
41
|
+
this.#notesByRecipientAndScope = new Map();
|
|
42
42
|
}
|
|
43
43
|
static async create(store) {
|
|
44
44
|
const pxeDB = new NoteDataProvider(store);
|
|
@@ -46,7 +46,7 @@ export class NoteDataProvider {
|
|
|
46
46
|
pxeDB.#notesByContractAndScope.set(scope, store.openMultiMap(`${scope}:notes_by_contract`));
|
|
47
47
|
pxeDB.#notesByStorageSlotAndScope.set(scope, store.openMultiMap(`${scope}:notes_by_storage_slot`));
|
|
48
48
|
pxeDB.#notesByTxHashAndScope.set(scope, store.openMultiMap(`${scope}:notes_by_tx_hash`));
|
|
49
|
-
pxeDB.#
|
|
49
|
+
pxeDB.#notesByRecipientAndScope.set(scope, store.openMultiMap(`${scope}:notes_by_recipient`));
|
|
50
50
|
}
|
|
51
51
|
return pxeDB;
|
|
52
52
|
}
|
|
@@ -59,7 +59,7 @@ export class NoteDataProvider {
|
|
|
59
59
|
this.#notesByContractAndScope.set(scopeString, this.#store.openMultiMap(`${scopeString}:notes_by_contract`));
|
|
60
60
|
this.#notesByStorageSlotAndScope.set(scopeString, this.#store.openMultiMap(`${scopeString}:notes_by_storage_slot`));
|
|
61
61
|
this.#notesByTxHashAndScope.set(scopeString, this.#store.openMultiMap(`${scopeString}:notes_by_tx_hash`));
|
|
62
|
-
this.#
|
|
62
|
+
this.#notesByRecipientAndScope.set(scopeString, this.#store.openMultiMap(`${scopeString}:notes_by_recipient`));
|
|
63
63
|
return true;
|
|
64
64
|
}
|
|
65
65
|
async addNotes(notes, scope = AztecAddress.ZERO) {
|
|
@@ -79,7 +79,7 @@ export class NoteDataProvider {
|
|
|
79
79
|
await this.#notesByContractAndScope.get(scope.toString()).set(dao.contractAddress.toString(), noteIndex);
|
|
80
80
|
await this.#notesByStorageSlotAndScope.get(scope.toString()).set(dao.storageSlot.toString(), noteIndex);
|
|
81
81
|
await this.#notesByTxHashAndScope.get(scope.toString()).set(dao.txHash.toString(), noteIndex);
|
|
82
|
-
await this.#
|
|
82
|
+
await this.#notesByRecipientAndScope.get(scope.toString()).set(dao.recipient.toString(), noteIndex);
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
85
|
}
|
|
@@ -95,7 +95,7 @@ export class NoteDataProvider {
|
|
|
95
95
|
await this.#nullifierToNoteId.delete(noteDao.siloedNullifier.toString());
|
|
96
96
|
const scopes = await toArray(this.#scopes.keysAsync());
|
|
97
97
|
for (const scope of scopes){
|
|
98
|
-
await this.#
|
|
98
|
+
await this.#notesByRecipientAndScope.get(scope).deleteValue(noteDao.recipient.toString(), noteIndex);
|
|
99
99
|
await this.#notesByTxHashAndScope.get(scope).deleteValue(noteDao.txHash.toString(), noteIndex);
|
|
100
100
|
await this.#notesByContractAndScope.get(scope).deleteValue(noteDao.contractAddress.toString(), noteIndex);
|
|
101
101
|
await this.#notesByStorageSlotAndScope.get(scope).deleteValue(noteDao.storageSlot.toString(), noteIndex);
|
|
@@ -123,14 +123,14 @@ export class NoteDataProvider {
|
|
|
123
123
|
let scopes = await toArray(this.#nullifiedNotesToScope.getValuesAsync(noteIndex)) ?? [];
|
|
124
124
|
if (scopes.length === 0) {
|
|
125
125
|
scopes = [
|
|
126
|
-
|
|
126
|
+
dao.recipient.toString()
|
|
127
127
|
];
|
|
128
128
|
}
|
|
129
129
|
for (const scope of scopes){
|
|
130
130
|
await this.#notesByContractAndScope.get(scope.toString()).set(dao.contractAddress.toString(), noteIndex);
|
|
131
131
|
await this.#notesByStorageSlotAndScope.get(scope.toString()).set(dao.storageSlot.toString(), noteIndex);
|
|
132
132
|
await this.#notesByTxHashAndScope.get(scope.toString()).set(dao.txHash.toString(), noteIndex);
|
|
133
|
-
await this.#
|
|
133
|
+
await this.#notesByRecipientAndScope.get(scope.toString()).set(dao.recipient.toString(), noteIndex);
|
|
134
134
|
await this.#notesToScope.set(noteIndex, scope);
|
|
135
135
|
}
|
|
136
136
|
await this.#nullifiedNotes.delete(noteIndex);
|
|
@@ -139,13 +139,12 @@ export class NoteDataProvider {
|
|
|
139
139
|
await this.#nullifiedNotesByContract.deleteValue(dao.contractAddress.toString(), noteIndex);
|
|
140
140
|
await this.#nullifiedNotesByStorageSlot.deleteValue(dao.storageSlot.toString(), noteIndex);
|
|
141
141
|
await this.#nullifiedNotesByTxHash.deleteValue(dao.txHash.toString(), noteIndex);
|
|
142
|
-
await this.#
|
|
142
|
+
await this.#nullifiedNotesByRecipient.deleteValue(dao.recipient.toString(), noteIndex);
|
|
143
143
|
await this.#nullifiedNotesByNullifier.delete(dao.siloedNullifier.toString());
|
|
144
144
|
}
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
147
|
async getNotes(filter) {
|
|
148
|
-
const publicKey = filter.owner ? await filter.owner.toAddressPoint() : undefined;
|
|
149
148
|
filter.status = filter.status ?? NoteStatus.ACTIVE;
|
|
150
149
|
const candidateNoteSources = [];
|
|
151
150
|
filter.scopes ??= (await toArray(this.#scopes.keysAsync())).map((addressString)=>AztecAddress.fromString(addressString));
|
|
@@ -155,7 +154,7 @@ export class NoteDataProvider {
|
|
|
155
154
|
if (!await this.#scopes.hasAsync(formattedScopeString)) {
|
|
156
155
|
throw new Error('Trying to get incoming notes of an scope that is not in the PXE database');
|
|
157
156
|
}
|
|
158
|
-
activeNoteIdsPerScope.push(
|
|
157
|
+
activeNoteIdsPerScope.push(filter.recipient ? await toArray(this.#notesByRecipientAndScope.get(formattedScopeString).getValuesAsync(filter.recipient.toString())) : filter.txHash ? await toArray(this.#notesByTxHashAndScope.get(formattedScopeString).getValuesAsync(filter.txHash.toString())) : filter.contractAddress ? await toArray(this.#notesByContractAndScope.get(formattedScopeString).getValuesAsync(filter.contractAddress.toString())) : filter.storageSlot ? await toArray(this.#notesByStorageSlotAndScope.get(formattedScopeString).getValuesAsync(filter.storageSlot.toString())) : await toArray(this.#notesByRecipientAndScope.get(formattedScopeString).valuesAsync()));
|
|
159
158
|
}
|
|
160
159
|
candidateNoteSources.push({
|
|
161
160
|
ids: new Set(activeNoteIdsPerScope.flat()),
|
|
@@ -163,7 +162,7 @@ export class NoteDataProvider {
|
|
|
163
162
|
});
|
|
164
163
|
if (filter.status == NoteStatus.ACTIVE_OR_NULLIFIED) {
|
|
165
164
|
candidateNoteSources.push({
|
|
166
|
-
ids:
|
|
165
|
+
ids: filter.recipient ? await toArray(this.#nullifiedNotesByRecipient.getValuesAsync(filter.recipient.toString())) : filter.txHash ? await toArray(this.#nullifiedNotesByTxHash.getValuesAsync(filter.txHash.toString())) : filter.contractAddress ? await toArray(this.#nullifiedNotesByContract.getValuesAsync(filter.contractAddress.toString())) : filter.storageSlot ? await toArray(this.#nullifiedNotesByStorageSlot.getValuesAsync(filter.storageSlot.toString())) : await toArray(this.#nullifiedNotes.keysAsync()),
|
|
167
166
|
notes: this.#nullifiedNotes
|
|
168
167
|
});
|
|
169
168
|
}
|
|
@@ -184,7 +183,7 @@ export class NoteDataProvider {
|
|
|
184
183
|
if (filter.storageSlot && !note.storageSlot.equals(filter.storageSlot)) {
|
|
185
184
|
continue;
|
|
186
185
|
}
|
|
187
|
-
if (
|
|
186
|
+
if (filter.recipient && !note.recipient.equals(filter.recipient)) {
|
|
188
187
|
continue;
|
|
189
188
|
}
|
|
190
189
|
if (filter.siloedNullifier && !note.siloedNullifier.equals(filter.siloedNullifier)) {
|
|
@@ -195,7 +194,7 @@ export class NoteDataProvider {
|
|
|
195
194
|
}
|
|
196
195
|
return result;
|
|
197
196
|
}
|
|
198
|
-
removeNullifiedNotes(nullifiers,
|
|
197
|
+
removeNullifiedNotes(nullifiers, recipient) {
|
|
199
198
|
if (nullifiers.length === 0) {
|
|
200
199
|
return Promise.resolve([]);
|
|
201
200
|
}
|
|
@@ -213,7 +212,7 @@ export class NoteDataProvider {
|
|
|
213
212
|
}
|
|
214
213
|
const noteScopes = await toArray(this.#notesToScope.getValuesAsync(noteIndex)) ?? [];
|
|
215
214
|
const note = NoteDao.fromBuffer(noteBuffer);
|
|
216
|
-
if (!note.
|
|
215
|
+
if (!note.recipient.equals(recipient)) {
|
|
217
216
|
continue;
|
|
218
217
|
}
|
|
219
218
|
nullifiedNotes.push(note);
|
|
@@ -221,7 +220,7 @@ export class NoteDataProvider {
|
|
|
221
220
|
await this.#notesToScope.delete(noteIndex);
|
|
222
221
|
const scopes = await toArray(this.#scopes.keysAsync());
|
|
223
222
|
for (const scope of scopes){
|
|
224
|
-
await this.#
|
|
223
|
+
await this.#notesByRecipientAndScope.get(scope).deleteValue(note.recipient.toString(), noteIndex);
|
|
225
224
|
await this.#notesByTxHashAndScope.get(scope).deleteValue(note.txHash.toString(), noteIndex);
|
|
226
225
|
await this.#notesByContractAndScope.get(scope).deleteValue(note.contractAddress.toString(), noteIndex);
|
|
227
226
|
await this.#notesByStorageSlotAndScope.get(scope).deleteValue(note.storageSlot.toString(), noteIndex);
|
|
@@ -236,7 +235,7 @@ export class NoteDataProvider {
|
|
|
236
235
|
await this.#nullifiedNotesByContract.set(note.contractAddress.toString(), noteIndex);
|
|
237
236
|
await this.#nullifiedNotesByStorageSlot.set(note.storageSlot.toString(), noteIndex);
|
|
238
237
|
await this.#nullifiedNotesByTxHash.set(note.txHash.toString(), noteIndex);
|
|
239
|
-
await this.#
|
|
238
|
+
await this.#nullifiedNotesByRecipient.set(note.recipient.toString(), noteIndex);
|
|
240
239
|
await this.#nullifiedNotesByNullifier.set(nullifier.toString(), noteIndex);
|
|
241
240
|
await this.#nullifierToNoteId.delete(nullifier.toString());
|
|
242
241
|
}
|
|
@@ -36,7 +36,7 @@ import { L2BlockStream } from '@aztec/stdlib/block';
|
|
|
36
36
|
switch(event.type){
|
|
37
37
|
case 'blocks-added':
|
|
38
38
|
{
|
|
39
|
-
const lastBlock = event.blocks.at(-1);
|
|
39
|
+
const lastBlock = event.blocks.at(-1).block;
|
|
40
40
|
this.log.verbose(`Updated pxe last block to ${lastBlock.number}`, {
|
|
41
41
|
blockHash: lastBlock.hash(),
|
|
42
42
|
archive: lastBlock.archive.root.toString(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/pxe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.81.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./server": "./dest/entrypoints/server/index.js",
|
|
@@ -59,19 +59,19 @@
|
|
|
59
59
|
]
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@aztec/bb-prover": "0.
|
|
63
|
-
"@aztec/bb.js": "0.
|
|
64
|
-
"@aztec/builder": "0.
|
|
65
|
-
"@aztec/constants": "0.
|
|
66
|
-
"@aztec/ethereum": "0.
|
|
67
|
-
"@aztec/foundation": "0.
|
|
68
|
-
"@aztec/key-store": "0.
|
|
69
|
-
"@aztec/kv-store": "0.
|
|
70
|
-
"@aztec/noir-protocol-circuits-types": "0.
|
|
71
|
-
"@aztec/noir-types": "0.
|
|
72
|
-
"@aztec/protocol-contracts": "0.
|
|
73
|
-
"@aztec/simulator": "0.
|
|
74
|
-
"@aztec/stdlib": "0.
|
|
62
|
+
"@aztec/bb-prover": "0.81.0",
|
|
63
|
+
"@aztec/bb.js": "0.81.0",
|
|
64
|
+
"@aztec/builder": "0.81.0",
|
|
65
|
+
"@aztec/constants": "0.81.0",
|
|
66
|
+
"@aztec/ethereum": "0.81.0",
|
|
67
|
+
"@aztec/foundation": "0.81.0",
|
|
68
|
+
"@aztec/key-store": "0.81.0",
|
|
69
|
+
"@aztec/kv-store": "0.81.0",
|
|
70
|
+
"@aztec/noir-protocol-circuits-types": "0.81.0",
|
|
71
|
+
"@aztec/noir-types": "0.81.0",
|
|
72
|
+
"@aztec/protocol-contracts": "0.81.0",
|
|
73
|
+
"@aztec/simulator": "0.81.0",
|
|
74
|
+
"@aztec/stdlib": "0.81.0",
|
|
75
75
|
"@msgpack/msgpack": "^3.0.0-beta2",
|
|
76
76
|
"koa": "^2.14.2",
|
|
77
77
|
"koa-router": "^12.0.0",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"viem": "2.23.7"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@aztec/noir-contracts.js": "0.
|
|
84
|
+
"@aztec/noir-contracts.js": "0.81.0",
|
|
85
85
|
"@jest/globals": "^29.5.0",
|
|
86
86
|
"@types/jest": "^29.5.0",
|
|
87
87
|
"@types/lodash.omit": "^4.5.7",
|
|
@@ -1,48 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
3
|
-
MAX_NOTE_HASHES_PER_TX,
|
|
4
|
-
PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
5
|
-
PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
|
|
6
|
-
} from '@aztec/constants';
|
|
1
|
+
import { type L1_TO_L2_MSG_TREE_HEIGHT, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS } from '@aztec/constants';
|
|
7
2
|
import { timesParallel } from '@aztec/foundation/collection';
|
|
8
3
|
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
9
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
4
|
+
import { Fr, Point } from '@aztec/foundation/fields';
|
|
10
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
11
|
-
import { BufferReader } from '@aztec/foundation/serialize';
|
|
12
6
|
import type { KeyStore } from '@aztec/key-store';
|
|
13
|
-
import {
|
|
14
|
-
|
|
7
|
+
import {
|
|
8
|
+
AcirSimulator,
|
|
9
|
+
type ExecutionDataProvider,
|
|
10
|
+
MessageLoadOracleInputs,
|
|
11
|
+
type SimulationProvider,
|
|
12
|
+
} from '@aztec/simulator/client';
|
|
15
13
|
import {
|
|
16
14
|
type FunctionArtifact,
|
|
17
15
|
FunctionCall,
|
|
18
16
|
FunctionSelector,
|
|
19
17
|
FunctionType,
|
|
20
|
-
NoteSelector,
|
|
21
18
|
encodeArguments,
|
|
22
19
|
getFunctionArtifact,
|
|
23
20
|
} from '@aztec/stdlib/abi';
|
|
24
|
-
import
|
|
21
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
25
22
|
import type { InBlock, L2Block, L2BlockNumber } from '@aztec/stdlib/block';
|
|
26
23
|
import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract';
|
|
27
24
|
import { computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
|
|
28
25
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
29
26
|
import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
|
|
30
27
|
import { computeAddressSecret, computeTaggingSecretPoint } from '@aztec/stdlib/keys';
|
|
31
|
-
import {
|
|
32
|
-
IndexedTaggingSecret,
|
|
33
|
-
L1NotePayload,
|
|
34
|
-
LogWithTxData,
|
|
35
|
-
PrivateLog,
|
|
36
|
-
PublicLog,
|
|
37
|
-
TxScopedL2Log,
|
|
38
|
-
} from '@aztec/stdlib/logs';
|
|
28
|
+
import { IndexedTaggingSecret, LogWithTxData, TxScopedL2Log, deriveEcdhSharedSecret } from '@aztec/stdlib/logs';
|
|
39
29
|
import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging';
|
|
40
30
|
import { Note, type NoteStatus } from '@aztec/stdlib/note';
|
|
41
31
|
import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
42
32
|
import type { BlockHeader } from '@aztec/stdlib/tx';
|
|
43
33
|
import { TxHash } from '@aztec/stdlib/tx';
|
|
44
34
|
|
|
45
|
-
import { getOrderedNoteItems } from '../note_decryption_utils/add_public_values_to_payload.js';
|
|
46
35
|
import type { AddressDataProvider } from '../storage/address_data_provider/address_data_provider.js';
|
|
47
36
|
import type { AuthWitnessDataProvider } from '../storage/auth_witness_data_provider/auth_witness_data_provider.js';
|
|
48
37
|
import type { CapsuleDataProvider } from '../storage/capsule_data_provider/capsule_data_provider.js';
|
|
@@ -470,7 +459,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
470
459
|
const recipients = scopes ? scopes : await this.keyStore.getAccounts();
|
|
471
460
|
// A map of logs going from recipient address to logs. Note that the logs might have been processed before
|
|
472
461
|
// due to us having a sliding window that "looks back" for logs as well. (We look back as there is no guarantee
|
|
473
|
-
// that a logs will be received ordered by a given
|
|
462
|
+
// that a logs will be received ordered by a given tag index and that the tags won't be reused).
|
|
474
463
|
const logsMap = new Map<string, TxScopedL2Log[]>();
|
|
475
464
|
const contractName = await this.contractDataProvider.getDebugContractName(contractAddress);
|
|
476
465
|
for (const recipient of recipients) {
|
|
@@ -516,31 +505,21 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
516
505
|
|
|
517
506
|
logsByTags.forEach((logsByTag, logIndex) => {
|
|
518
507
|
if (logsByTag.length > 0) {
|
|
519
|
-
//
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
if (checkedLogsbyTag.length < logsByTag.length) {
|
|
524
|
-
const discarded = logsByTag.filter(
|
|
525
|
-
log => checkedLogsbyTag.find(filteredLog => filteredLog.equals(log)) === undefined,
|
|
526
|
-
);
|
|
527
|
-
this.log.warn(
|
|
528
|
-
`Discarded ${
|
|
529
|
-
logsByTag.length - checkedLogsbyTag.length
|
|
530
|
-
} public logs with mismatched contract address ${contractAddress}:`,
|
|
531
|
-
discarded.map(l => PublicLog.fromBuffer(l.logData)),
|
|
532
|
-
);
|
|
508
|
+
// Discard public logs
|
|
509
|
+
const filteredLogsByTag = logsByTag.filter(l => !l.isFromPublic);
|
|
510
|
+
if (filteredLogsByTag.length < logsByTag.length) {
|
|
511
|
+
this.log.warn(`Discarded ${logsByTag.filter(l => l.isFromPublic).length} public logs with matching tags`);
|
|
533
512
|
}
|
|
534
513
|
|
|
535
514
|
// The logs for the given tag exist so we store them for later processing
|
|
536
|
-
logsForRecipient.push(...
|
|
515
|
+
logsForRecipient.push(...filteredLogsByTag);
|
|
537
516
|
|
|
538
517
|
// We retrieve the indexed tagging secret corresponding to the log as I need that to evaluate whether
|
|
539
518
|
// a new largest index have been found.
|
|
540
519
|
const secretCorrespondingToLog = secretsForTheWholeWindow[logIndex];
|
|
541
520
|
const initialIndex = initialIndexesMap[secretCorrespondingToLog.appTaggingSecret.toString()];
|
|
542
521
|
|
|
543
|
-
this.log.debug(`Found ${
|
|
522
|
+
this.log.debug(`Found ${filteredLogsByTag.length} logs as recipient ${recipient}`, {
|
|
544
523
|
recipient,
|
|
545
524
|
secret: secretCorrespondingToLog.appTaggingSecret,
|
|
546
525
|
contractName,
|
|
@@ -610,77 +589,36 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
610
589
|
return logsMap;
|
|
611
590
|
}
|
|
612
591
|
|
|
613
|
-
/**
|
|
614
|
-
* Decrypts logs tagged for a recipient and returns them.
|
|
615
|
-
* @param scopedLogs - The logs to decrypt.
|
|
616
|
-
* @param recipient - The recipient of the logs.
|
|
617
|
-
* @returns The decrypted notes.
|
|
618
|
-
*/
|
|
619
|
-
async #decryptTaggedLogs(scopedLogs: TxScopedL2Log[], recipient: AztecAddress) {
|
|
620
|
-
const recipientCompleteAddress = await this.getCompleteAddress(recipient);
|
|
621
|
-
const ivskM = await this.keyStore.getMasterSecretKey(
|
|
622
|
-
recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
|
|
623
|
-
);
|
|
624
|
-
const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
|
|
625
|
-
|
|
626
|
-
// Since we could have notes with the same index for different txs, we need
|
|
627
|
-
// to keep track of them scoping by txHash
|
|
628
|
-
const excludedIndices: Map<string, Set<number>> = new Map();
|
|
629
|
-
const decrypted = [];
|
|
630
|
-
|
|
631
|
-
for (const scopedLog of scopedLogs) {
|
|
632
|
-
const payload = scopedLog.isFromPublic
|
|
633
|
-
? await L1NotePayload.decryptAsIncomingFromPublic(PublicLog.fromBuffer(scopedLog.logData), addressSecret)
|
|
634
|
-
: await L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
|
|
635
|
-
|
|
636
|
-
if (!payload) {
|
|
637
|
-
this.log.verbose('Unable to decrypt log');
|
|
638
|
-
continue;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
if (!excludedIndices.has(scopedLog.txHash.toString())) {
|
|
642
|
-
excludedIndices.set(scopedLog.txHash.toString(), new Set());
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
const note = await getOrderedNoteItems(this.contractDataProvider, payload);
|
|
646
|
-
const plaintext = [payload.storageSlot, payload.noteTypeId.toField(), ...note.items];
|
|
647
|
-
|
|
648
|
-
decrypted.push({ plaintext, txHash: scopedLog.txHash, contractAddress: payload.contractAddress });
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
return decrypted;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
592
|
/**
|
|
655
593
|
* Processes the tagged logs returned by syncTaggedLogs by decrypting them and storing them in the database.
|
|
594
|
+
* @param contractAddress - The address of the contract that the logs are tagged for.
|
|
656
595
|
* @param logs - The logs to process.
|
|
657
596
|
* @param recipient - The recipient of the logs.
|
|
658
597
|
*/
|
|
659
598
|
public async processTaggedLogs(
|
|
599
|
+
contractAddress: AztecAddress,
|
|
660
600
|
logs: TxScopedL2Log[],
|
|
661
601
|
recipient: AztecAddress,
|
|
662
602
|
simulator?: AcirSimulator,
|
|
663
603
|
): Promise<void> {
|
|
664
|
-
const
|
|
604
|
+
for (const scopedLog of logs) {
|
|
605
|
+
if (scopedLog.isFromPublic) {
|
|
606
|
+
throw new Error('Attempted to decrypt public log');
|
|
607
|
+
}
|
|
665
608
|
|
|
666
|
-
// We've produced the full NoteDao, which we'd be able to simply insert into the database. However, this is
|
|
667
|
-
// only a temporary measure as we migrate from the PXE-driven discovery into the new contract-driven approach. We
|
|
668
|
-
// discard most of the work done up to this point and reconstruct the note plaintext to then hand over to the
|
|
669
|
-
// contract for further processing.
|
|
670
|
-
for (const decryptedLog of decryptedLogs) {
|
|
671
609
|
// Log processing requires the note hashes in the tx in which the note was created. We are now assuming that the
|
|
672
610
|
// note was included in the same block in which the log was delivered - note that partial notes will not work this
|
|
673
611
|
// way.
|
|
674
|
-
const txEffect = await this.aztecNode.getTxEffect(
|
|
612
|
+
const txEffect = await this.aztecNode.getTxEffect(scopedLog.txHash);
|
|
675
613
|
if (!txEffect) {
|
|
676
|
-
throw new Error(`Could not find tx effect for tx hash ${
|
|
614
|
+
throw new Error(`Could not find tx effect for tx hash ${scopedLog.txHash}`);
|
|
677
615
|
}
|
|
678
616
|
|
|
679
617
|
// This will trigger calls to the deliverNote oracle
|
|
680
618
|
await this.callProcessLog(
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
619
|
+
contractAddress,
|
|
620
|
+
scopedLog.log.toFields(),
|
|
621
|
+
scopedLog.txHash,
|
|
684
622
|
txEffect.data.noteHashes,
|
|
685
623
|
txEffect.data.nullifiers[0],
|
|
686
624
|
recipient,
|
|
@@ -749,8 +687,6 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
749
687
|
throw new Error(`Failed to fetch tx receipt for tx hash ${txHash} when searching for note hashes`);
|
|
750
688
|
}
|
|
751
689
|
|
|
752
|
-
// TODO(#12549): does it make sense to store the recipient's address point instead of just its address?
|
|
753
|
-
const recipientAddressPoint = await recipient.toAddressPoint();
|
|
754
690
|
const noteDao = new NoteDao(
|
|
755
691
|
new Note(content),
|
|
756
692
|
contractAddress,
|
|
@@ -762,8 +698,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
762
698
|
txReceipt.blockNumber!,
|
|
763
699
|
txReceipt.blockHash!.toString(),
|
|
764
700
|
uniqueNoteHashTreeIndex,
|
|
765
|
-
|
|
766
|
-
NoteSelector.empty(), // TODO(#12013): remove
|
|
701
|
+
recipient,
|
|
767
702
|
);
|
|
768
703
|
|
|
769
704
|
await this.noteDataProvider.addNotes([noteDao], recipient);
|
|
@@ -777,10 +712,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
777
712
|
const [nullifierIndex] = await this.aztecNode.findNullifiersIndexesWithBlock(syncedBlockNumber, [siloedNullifier]);
|
|
778
713
|
if (nullifierIndex !== undefined) {
|
|
779
714
|
const { data: _, ...blockHashAndNum } = nullifierIndex;
|
|
780
|
-
await this.noteDataProvider.removeNullifiedNotes(
|
|
781
|
-
[{ data: siloedNullifier, ...blockHashAndNum }],
|
|
782
|
-
recipientAddressPoint,
|
|
783
|
-
);
|
|
715
|
+
await this.noteDataProvider.removeNullifiedNotes([{ data: siloedNullifier, ...blockHashAndNum }], recipient);
|
|
784
716
|
|
|
785
717
|
this.log.verbose(`Removed just-added note`, {
|
|
786
718
|
contract: contractAddress,
|
|
@@ -806,33 +738,33 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
806
738
|
);
|
|
807
739
|
}
|
|
808
740
|
|
|
809
|
-
const
|
|
741
|
+
const scopedLog = logsForTag[0];
|
|
810
742
|
|
|
811
743
|
// getLogsByTag doesn't have all of the information that we need (notably note hashes and the first nullifier), so
|
|
812
744
|
// we need to make a second call to the node for `getTxEffect`.
|
|
813
745
|
// TODO(#9789): bundle this information in the `getLogsByTag` call.
|
|
814
|
-
const txEffect = await this.aztecNode.getTxEffect(
|
|
746
|
+
const txEffect = await this.aztecNode.getTxEffect(scopedLog.txHash);
|
|
815
747
|
if (txEffect == undefined) {
|
|
816
|
-
throw new Error(`Unexpected: failed to retrieve tx effects for tx ${
|
|
748
|
+
throw new Error(`Unexpected: failed to retrieve tx effects for tx ${scopedLog.txHash} which is known to exist`);
|
|
817
749
|
}
|
|
818
750
|
|
|
819
|
-
const reader = BufferReader.asReader(log.logData);
|
|
820
|
-
const logArray = reader.readArray(PUBLIC_LOG_DATA_SIZE_IN_FIELDS, Fr);
|
|
821
|
-
|
|
822
751
|
// Public logs always take up all available fields by padding with zeroes, and the length of the originally emitted
|
|
823
752
|
// log is lost. Until this is improved, we simply remove all of the zero elements (which are expected to be at the
|
|
824
753
|
// end).
|
|
825
754
|
// TODO(#11636): use the actual log length.
|
|
826
|
-
const trimmedLog =
|
|
755
|
+
const trimmedLog = scopedLog.log.toFields().filter(x => !x.isZero());
|
|
827
756
|
|
|
828
|
-
return new LogWithTxData(trimmedLog,
|
|
757
|
+
return new LogWithTxData(trimmedLog, scopedLog.txHash.hash, txEffect.data.noteHashes, txEffect.data.nullifiers[0]);
|
|
829
758
|
}
|
|
830
759
|
|
|
760
|
+
// TODO(#12553): nuke this as part of tackling that issue. This function is no longer unit tested as I had to remove
|
|
761
|
+
// it from pxe_oracle_interface.test.ts when moving decryption to Noir (at that point we could not get a hold of
|
|
762
|
+
// the decrypted note in the test as TS decryption no longer existed).
|
|
831
763
|
public async removeNullifiedNotes(contractAddress: AztecAddress) {
|
|
832
764
|
this.log.verbose('Searching for nullifiers of known notes', { contract: contractAddress });
|
|
833
765
|
|
|
834
766
|
for (const recipient of await this.keyStore.getAccounts()) {
|
|
835
|
-
const currentNotesForRecipient = await this.noteDataProvider.getNotes({ contractAddress,
|
|
767
|
+
const currentNotesForRecipient = await this.noteDataProvider.getNotes({ contractAddress, recipient });
|
|
836
768
|
const nullifiersToCheck = currentNotesForRecipient.map(note => note.siloedNullifier);
|
|
837
769
|
const nullifierIndexes = await this.aztecNode.findNullifiersIndexesWithBlock('latest', nullifiersToCheck);
|
|
838
770
|
|
|
@@ -844,10 +776,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
844
776
|
})
|
|
845
777
|
.filter(nullifier => nullifier !== undefined) as InBlock<Fr>[];
|
|
846
778
|
|
|
847
|
-
const nullifiedNotes = await this.noteDataProvider.removeNullifiedNotes(
|
|
848
|
-
foundNullifiers,
|
|
849
|
-
await recipient.toAddressPoint(),
|
|
850
|
-
);
|
|
779
|
+
const nullifiedNotes = await this.noteDataProvider.removeNullifiedNotes(foundNullifiers, recipient);
|
|
851
780
|
nullifiedNotes.forEach(noteDao => {
|
|
852
781
|
this.log.verbose(`Removed note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
|
|
853
782
|
contract: noteDao.contractAddress,
|
|
@@ -860,7 +789,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
860
789
|
|
|
861
790
|
async callProcessLog(
|
|
862
791
|
contractAddress: AztecAddress,
|
|
863
|
-
|
|
792
|
+
logCiphertext: Fr[],
|
|
864
793
|
txHash: TxHash,
|
|
865
794
|
noteHashes: Fr[],
|
|
866
795
|
firstNullifier: Fr,
|
|
@@ -885,7 +814,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
885
814
|
type: FunctionType.UNCONSTRAINED,
|
|
886
815
|
isStatic: artifact.isStatic,
|
|
887
816
|
args: encodeArguments(artifact, [
|
|
888
|
-
toBoundedVec(
|
|
817
|
+
toBoundedVec(logCiphertext, PRIVATE_LOG_SIZE_IN_FIELDS),
|
|
889
818
|
txHash.toString(),
|
|
890
819
|
toBoundedVec(noteHashes, MAX_NOTE_HASHES_PER_TX),
|
|
891
820
|
firstNullifier,
|
|
@@ -917,6 +846,16 @@ export class PXEOracleInterface implements ExecutionDataProvider {
|
|
|
917
846
|
copyCapsule(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
|
|
918
847
|
return this.capsuleDataProvider.copyCapsule(contractAddress, srcSlot, dstSlot, numEntries);
|
|
919
848
|
}
|
|
849
|
+
|
|
850
|
+
async getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
|
|
851
|
+
// TODO(#12656): return an app-siloed secret
|
|
852
|
+
const recipientCompleteAddress = await this.getCompleteAddress(address);
|
|
853
|
+
const ivskM = await this.keyStore.getMasterSecretKey(
|
|
854
|
+
recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
|
|
855
|
+
);
|
|
856
|
+
const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
|
|
857
|
+
return deriveEcdhSharedSecret(addressSecret, ephPk);
|
|
858
|
+
}
|
|
920
859
|
}
|
|
921
860
|
|
|
922
861
|
function toBoundedVec(array: Fr[], maxLength: number) {
|
|
@@ -32,8 +32,9 @@ import {
|
|
|
32
32
|
type ContractInstanceWithAddress,
|
|
33
33
|
type NodeInfo,
|
|
34
34
|
type PartialAddress,
|
|
35
|
+
computeContractAddressFromInstance,
|
|
36
|
+
getContractClassFromArtifact,
|
|
35
37
|
} from '@aztec/stdlib/contract';
|
|
36
|
-
import { computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/stdlib/contract';
|
|
37
38
|
import { SimulationError } from '@aztec/stdlib/errors';
|
|
38
39
|
import { EventMetadata, L1EventPayload } from '@aztec/stdlib/event';
|
|
39
40
|
import type { GasFees } from '@aztec/stdlib/gas';
|
|
@@ -436,27 +437,19 @@ export class PXEService implements PXE {
|
|
|
436
437
|
const noteDaos = await this.noteDataProvider.getNotes(filter);
|
|
437
438
|
|
|
438
439
|
const extendedNotes = noteDaos.map(async dao => {
|
|
439
|
-
let
|
|
440
|
-
if (
|
|
440
|
+
let recipient = filter.recipient;
|
|
441
|
+
if (recipient === undefined) {
|
|
441
442
|
const completeAddresses = await this.addressDataProvider.getCompleteAddresses();
|
|
442
|
-
const completeAddressIndex = (
|
|
443
|
-
|
|
444
|
-
)
|
|
443
|
+
const completeAddressIndex = completeAddresses.findIndex(completeAddress =>
|
|
444
|
+
completeAddress.address.equals(dao.recipient),
|
|
445
|
+
);
|
|
445
446
|
const completeAddress = completeAddresses[completeAddressIndex];
|
|
446
447
|
if (completeAddress === undefined) {
|
|
447
|
-
throw new Error(`Cannot find complete address for
|
|
448
|
+
throw new Error(`Cannot find complete address for recipient ${dao.recipient.toString()}`);
|
|
448
449
|
}
|
|
449
|
-
|
|
450
|
+
recipient = completeAddress.address;
|
|
450
451
|
}
|
|
451
|
-
return new UniqueNote(
|
|
452
|
-
dao.note,
|
|
453
|
-
owner,
|
|
454
|
-
dao.contractAddress,
|
|
455
|
-
dao.storageSlot,
|
|
456
|
-
dao.noteTypeId,
|
|
457
|
-
dao.txHash,
|
|
458
|
-
dao.nonce,
|
|
459
|
-
);
|
|
452
|
+
return new UniqueNote(dao.note, recipient, dao.contractAddress, dao.storageSlot, dao.txHash, dao.nonce);
|
|
460
453
|
});
|
|
461
454
|
return Promise.all(extendedNotes);
|
|
462
455
|
}
|