@aztec/pxe 0.42.0 → 0.43.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/database/deferred_note_dao.d.ts +2 -2
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +2 -2
- package/dest/database/incoming_note_dao.d.ts +73 -0
- package/dest/database/incoming_note_dao.d.ts.map +1 -0
- package/dest/database/incoming_note_dao.js +92 -0
- package/dest/database/kv_pxe_database.d.ts +10 -7
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +149 -78
- package/dest/database/{note_dao.d.ts → outgoing_note_dao.d.ts} +7 -12
- package/dest/database/outgoing_note_dao.d.ts.map +1 -0
- package/dest/database/outgoing_note_dao.js +83 -0
- package/dest/database/pxe_database.d.ts +21 -9
- package/dest/database/pxe_database.d.ts.map +1 -1
- package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
- package/dest/database/pxe_database_test_suite.js +71 -24
- package/dest/kernel_oracle/index.d.ts +1 -1
- package/dest/note_processor/note_processor.d.ts +23 -20
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +123 -76
- package/dest/note_processor/produce_note_dao.d.ts +13 -4
- package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
- package/dest/note_processor/produce_note_dao.js +88 -31
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +3 -1
- package/dest/pxe_service/pxe_service.d.ts +9 -4
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +106 -28
- package/dest/simulator_oracle/index.js +2 -2
- package/dest/synchronizer/synchronizer.d.ts +2 -2
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +37 -36
- package/package.json +14 -14
- package/src/database/deferred_note_dao.ts +1 -1
- package/src/database/{note_dao.ts → incoming_note_dao.ts} +10 -7
- package/src/database/kv_pxe_database.ts +127 -29
- package/src/database/outgoing_note_dao.ts +90 -0
- package/src/database/pxe_database.ts +23 -9
- package/src/database/pxe_database_test_suite.ts +93 -29
- package/src/note_processor/note_processor.ts +191 -121
- package/src/note_processor/produce_note_dao.ts +164 -50
- package/src/pxe_service/create_pxe_service.ts +2 -0
- package/src/pxe_service/pxe_service.ts +170 -42
- package/src/simulator_oracle/index.ts +1 -1
- package/src/synchronizer/synchronizer.ts +48 -52
- package/dest/database/note_dao.d.ts.map +0 -1
- package/dest/database/note_dao.js +0 -89
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { type L1NotePayload, type TxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { Fr, type PublicKey } from '@aztec/circuits.js';
|
|
3
3
|
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
4
|
-
import { type
|
|
4
|
+
import { type Logger } from '@aztec/foundation/log';
|
|
5
|
+
import { type AcirSimulator, ContractNotFoundError } from '@aztec/simulator';
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { DeferredNoteDao } from '../database/deferred_note_dao.js';
|
|
8
|
+
import { IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
9
|
+
import { OutgoingNoteDao } from '../database/outgoing_note_dao.js';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Decodes a note from a transaction that we know was intended for us.
|
|
@@ -11,96 +14,207 @@ import { NoteDao } from '../database/note_dao.js';
|
|
|
11
14
|
* Accepts a set of excluded indices, which are indices that have been assigned a note in the same tx.
|
|
12
15
|
* Inserts the index of the note into the excludedIndices set if the note is successfully decoded.
|
|
13
16
|
*
|
|
14
|
-
* @param
|
|
17
|
+
* @param ivpkM - The public counterpart to the secret key to be used in the decryption of incoming note logs.
|
|
18
|
+
* @param ovpkM - The public counterpart to the secret key to be used in the decryption of outgoing note logs.
|
|
15
19
|
* @param payload - An instance of l1NotePayload.
|
|
16
20
|
* @param txHash - The hash of the transaction that created the note. Equivalent to the first nullifier of the transaction.
|
|
17
21
|
* @param newNoteHashes - New note hashes in this transaction, one of which belongs to this note.
|
|
18
22
|
* @param dataStartIndexForTx - The next available leaf index for the note hash tree for this transaction.
|
|
19
23
|
* @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same l1NotePayload, we need to find a different index for each replicate.
|
|
20
24
|
* @param simulator - An instance of AcirSimulator.
|
|
21
|
-
* @returns
|
|
25
|
+
* @returns An object containing the incoming, outgoing, and deferred notes.
|
|
22
26
|
*/
|
|
23
|
-
export async function
|
|
27
|
+
export async function produceNoteDaos(
|
|
24
28
|
simulator: AcirSimulator,
|
|
25
|
-
|
|
29
|
+
ivpkM: PublicKey | undefined,
|
|
30
|
+
ovpkM: PublicKey | undefined,
|
|
26
31
|
payload: L1NotePayload,
|
|
27
32
|
txHash: TxHash,
|
|
28
33
|
newNoteHashes: Fr[],
|
|
29
34
|
dataStartIndexForTx: number,
|
|
30
35
|
excludedIndices: Set<number>,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
log: Logger,
|
|
37
|
+
): Promise<{
|
|
38
|
+
incomingNote: IncomingNoteDao | undefined;
|
|
39
|
+
outgoingNote: OutgoingNoteDao | undefined;
|
|
40
|
+
incomingDeferredNote: DeferredNoteDao | undefined;
|
|
41
|
+
outgoingDeferredNote: DeferredNoteDao | undefined;
|
|
42
|
+
}> {
|
|
43
|
+
if (!ivpkM && !ovpkM) {
|
|
44
|
+
throw new Error('Both ivpkM and ovpkM are undefined. Cannot create note.');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let incomingNote: IncomingNoteDao | undefined;
|
|
48
|
+
let outgoingNote: OutgoingNoteDao | undefined;
|
|
49
|
+
let incomingDeferredNote: DeferredNoteDao | undefined;
|
|
50
|
+
let outgoingDeferredNote: DeferredNoteDao | undefined;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
if (ivpkM) {
|
|
54
|
+
const { noteHashIndex, nonce, innerNoteHash, siloedNullifier } = await findNoteIndexAndNullifier(
|
|
55
|
+
simulator,
|
|
56
|
+
newNoteHashes,
|
|
57
|
+
txHash,
|
|
58
|
+
payload,
|
|
59
|
+
excludedIndices,
|
|
60
|
+
true, // For incoming we compute a nullifier (recipient of incoming is the party that nullifies).
|
|
61
|
+
);
|
|
62
|
+
const index = BigInt(dataStartIndexForTx + noteHashIndex);
|
|
63
|
+
excludedIndices?.add(noteHashIndex);
|
|
64
|
+
|
|
65
|
+
incomingNote = new IncomingNoteDao(
|
|
66
|
+
payload.note,
|
|
67
|
+
payload.contractAddress,
|
|
68
|
+
payload.storageSlot,
|
|
69
|
+
payload.noteTypeId,
|
|
70
|
+
txHash,
|
|
71
|
+
nonce,
|
|
72
|
+
innerNoteHash,
|
|
73
|
+
siloedNullifier,
|
|
74
|
+
index,
|
|
75
|
+
ivpkM,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
if (e instanceof ContractNotFoundError) {
|
|
80
|
+
log.warn(e.message);
|
|
81
|
+
|
|
82
|
+
if (ivpkM) {
|
|
83
|
+
incomingDeferredNote = new DeferredNoteDao(
|
|
84
|
+
ivpkM,
|
|
85
|
+
payload.note,
|
|
86
|
+
payload.contractAddress,
|
|
87
|
+
payload.storageSlot,
|
|
88
|
+
payload.noteTypeId,
|
|
89
|
+
txHash,
|
|
90
|
+
newNoteHashes,
|
|
91
|
+
dataStartIndexForTx,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
log.error(`Could not process note because of "${e}". Discarding note...`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
if (ovpkM) {
|
|
101
|
+
if (incomingNote) {
|
|
102
|
+
// Incoming note is defined meaning that this PXE has both the incoming and outgoing keys. We can skip computing
|
|
103
|
+
// note hash and note index since we already have them in the incoming note.
|
|
104
|
+
outgoingNote = new OutgoingNoteDao(
|
|
105
|
+
payload.note,
|
|
106
|
+
payload.contractAddress,
|
|
107
|
+
payload.storageSlot,
|
|
108
|
+
payload.noteTypeId,
|
|
109
|
+
txHash,
|
|
110
|
+
incomingNote.nonce,
|
|
111
|
+
incomingNote.innerNoteHash,
|
|
112
|
+
incomingNote.index,
|
|
113
|
+
ovpkM,
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
const { noteHashIndex, nonce, innerNoteHash } = await findNoteIndexAndNullifier(
|
|
117
|
+
simulator,
|
|
118
|
+
newNoteHashes,
|
|
119
|
+
txHash,
|
|
120
|
+
payload,
|
|
121
|
+
excludedIndices,
|
|
122
|
+
false, // For outgoing we do not compute a nullifier.
|
|
123
|
+
);
|
|
124
|
+
const index = BigInt(dataStartIndexForTx + noteHashIndex);
|
|
125
|
+
excludedIndices?.add(noteHashIndex);
|
|
126
|
+
outgoingNote = new OutgoingNoteDao(
|
|
127
|
+
payload.note,
|
|
128
|
+
payload.contractAddress,
|
|
129
|
+
payload.storageSlot,
|
|
130
|
+
payload.noteTypeId,
|
|
131
|
+
txHash,
|
|
132
|
+
nonce,
|
|
133
|
+
innerNoteHash,
|
|
134
|
+
index,
|
|
135
|
+
ovpkM,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} catch (e) {
|
|
140
|
+
if (e instanceof ContractNotFoundError) {
|
|
141
|
+
log.warn(e.message);
|
|
142
|
+
|
|
143
|
+
if (ovpkM) {
|
|
144
|
+
outgoingDeferredNote = new DeferredNoteDao(
|
|
145
|
+
ovpkM,
|
|
146
|
+
payload.note,
|
|
147
|
+
payload.contractAddress,
|
|
148
|
+
payload.storageSlot,
|
|
149
|
+
payload.noteTypeId,
|
|
150
|
+
txHash,
|
|
151
|
+
newNoteHashes,
|
|
152
|
+
dataStartIndexForTx,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
log.error(`Could not process note because of "${e}". Discarding note...`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
incomingNote,
|
|
162
|
+
outgoingNote,
|
|
163
|
+
incomingDeferredNote,
|
|
164
|
+
outgoingDeferredNote,
|
|
165
|
+
};
|
|
53
166
|
}
|
|
54
167
|
|
|
55
168
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* @param
|
|
63
|
-
* @param txHash - First nullifier in the tx.
|
|
64
|
-
* @param l1NotePayload - An instance of l1NotePayload.
|
|
169
|
+
* Finds nonce, index, inner hash and siloed nullifier for a given note.
|
|
170
|
+
* @dev Finds the index in the note hash tree by computing the note hash with different nonce and see which hash for
|
|
171
|
+
* the current tx matches this value.
|
|
172
|
+
* @remarks This method assists in identifying spent notes in the note hash tree.
|
|
173
|
+
* @param noteHashes - Note hashes in the tx. One of them should correspond to the note we are looking for
|
|
174
|
+
* @param txHash - Hash of a tx the note was emitted in.
|
|
175
|
+
* @param l1NotePayload - The note payload.
|
|
65
176
|
* @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same
|
|
66
177
|
* l1NotePayload. We need to find a different index for each replicate.
|
|
67
|
-
* @
|
|
68
|
-
*
|
|
178
|
+
* @param computeNullifier - A flag indicating whether to compute the nullifier or just return 0.
|
|
179
|
+
* @returns Nonce, index, inner hash and siloed nullifier for a given note.
|
|
180
|
+
* @throws If cannot find the nonce for the note.
|
|
69
181
|
*/
|
|
70
182
|
async function findNoteIndexAndNullifier(
|
|
71
183
|
simulator: AcirSimulator,
|
|
72
|
-
|
|
184
|
+
noteHashes: Fr[],
|
|
73
185
|
txHash: TxHash,
|
|
74
186
|
{ contractAddress, storageSlot, noteTypeId, note }: L1NotePayload,
|
|
75
187
|
excludedIndices: Set<number>,
|
|
188
|
+
computeNullifier: boolean,
|
|
76
189
|
) {
|
|
77
|
-
let
|
|
190
|
+
let noteHashIndex = 0;
|
|
78
191
|
let nonce: Fr | undefined;
|
|
79
192
|
let innerNoteHash: Fr | undefined;
|
|
80
193
|
let siloedNoteHash: Fr | undefined;
|
|
81
194
|
let innerNullifier: Fr | undefined;
|
|
82
195
|
const firstNullifier = Fr.fromBuffer(txHash.toBuffer());
|
|
83
196
|
|
|
84
|
-
for (;
|
|
85
|
-
if (excludedIndices.has(
|
|
197
|
+
for (; noteHashIndex < noteHashes.length; ++noteHashIndex) {
|
|
198
|
+
if (excludedIndices.has(noteHashIndex)) {
|
|
86
199
|
continue;
|
|
87
200
|
}
|
|
88
201
|
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
202
|
+
const noteHash = noteHashes[noteHashIndex];
|
|
203
|
+
if (noteHash.equals(Fr.ZERO)) {
|
|
91
204
|
break;
|
|
92
205
|
}
|
|
93
206
|
|
|
94
|
-
const expectedNonce = computeNoteHashNonce(firstNullifier,
|
|
95
|
-
({ innerNoteHash, siloedNoteHash, innerNullifier } = await simulator.
|
|
207
|
+
const expectedNonce = computeNoteHashNonce(firstNullifier, noteHashIndex);
|
|
208
|
+
({ innerNoteHash, siloedNoteHash, innerNullifier } = await simulator.computeNoteHashAndOptionallyANullifier(
|
|
96
209
|
contractAddress,
|
|
97
210
|
expectedNonce,
|
|
98
211
|
storageSlot,
|
|
99
212
|
noteTypeId,
|
|
213
|
+
computeNullifier,
|
|
100
214
|
note,
|
|
101
215
|
));
|
|
102
216
|
|
|
103
|
-
if (
|
|
217
|
+
if (noteHash.equals(siloedNoteHash)) {
|
|
104
218
|
nonce = expectedNonce;
|
|
105
219
|
break;
|
|
106
220
|
}
|
|
@@ -109,11 +223,11 @@ async function findNoteIndexAndNullifier(
|
|
|
109
223
|
if (!nonce) {
|
|
110
224
|
// NB: this used to warn the user that a decrypted log didn't match any notes.
|
|
111
225
|
// This was previously fine as we didn't chop transient note logs, but now we do (#1641 complete).
|
|
112
|
-
throw new Error('Cannot find a matching
|
|
226
|
+
throw new Error('Cannot find a matching note hash for the note.');
|
|
113
227
|
}
|
|
114
228
|
|
|
115
229
|
return {
|
|
116
|
-
|
|
230
|
+
noteHashIndex,
|
|
117
231
|
nonce,
|
|
118
232
|
innerNoteHash: innerNoteHash!,
|
|
119
233
|
siloedNullifier: siloNullifier(contractAddress, innerNullifier!),
|
|
@@ -5,6 +5,7 @@ import { createDebugLogger } from '@aztec/foundation/log';
|
|
|
5
5
|
import { KeyStore } from '@aztec/key-store';
|
|
6
6
|
import { AztecLmdbStore } from '@aztec/kv-store/lmdb';
|
|
7
7
|
import { initStoreForRollup } from '@aztec/kv-store/utils';
|
|
8
|
+
import { getCanonicalAuthRegistry } from '@aztec/protocol-contracts/auth-registry';
|
|
8
9
|
import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer';
|
|
9
10
|
import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
|
|
10
11
|
import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
|
|
@@ -67,6 +68,7 @@ export async function createPXEService(
|
|
|
67
68
|
getCanonicalMultiCallEntrypointContract(),
|
|
68
69
|
getCanonicalGasToken(),
|
|
69
70
|
getCanonicalKeyRegistry(),
|
|
71
|
+
getCanonicalAuthRegistry(),
|
|
70
72
|
]) {
|
|
71
73
|
await server.registerContract(contract);
|
|
72
74
|
}
|
|
@@ -3,18 +3,22 @@ import {
|
|
|
3
3
|
type AztecNode,
|
|
4
4
|
EncryptedNoteTxL2Logs,
|
|
5
5
|
EncryptedTxL2Logs,
|
|
6
|
+
type EventMetadata,
|
|
6
7
|
ExtendedNote,
|
|
7
8
|
type FunctionCall,
|
|
8
9
|
type GetUnencryptedLogsResponse,
|
|
10
|
+
type IncomingNotesFilter,
|
|
11
|
+
L1EventPayload,
|
|
9
12
|
type L2Block,
|
|
10
13
|
type LogFilter,
|
|
11
14
|
MerkleTreeId,
|
|
12
|
-
type
|
|
15
|
+
type OutgoingNotesFilter,
|
|
13
16
|
type PXE,
|
|
14
17
|
type PXEInfo,
|
|
15
18
|
type ProofCreator,
|
|
16
19
|
SimulatedTx,
|
|
17
20
|
SimulationError,
|
|
21
|
+
TaggedLog,
|
|
18
22
|
Tx,
|
|
19
23
|
type TxEffect,
|
|
20
24
|
type TxExecutionRequest,
|
|
@@ -32,11 +36,11 @@ import {
|
|
|
32
36
|
} from '@aztec/circuits.js';
|
|
33
37
|
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
34
38
|
import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi';
|
|
35
|
-
import { type Fq, Fr } from '@aztec/foundation/fields';
|
|
39
|
+
import { type Fq, Fr, type Point } from '@aztec/foundation/fields';
|
|
36
40
|
import { SerialQueue } from '@aztec/foundation/fifo';
|
|
37
41
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
38
42
|
import { type KeyStore } from '@aztec/key-store';
|
|
39
|
-
import {
|
|
43
|
+
import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
|
|
40
44
|
import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token';
|
|
41
45
|
import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
|
|
42
46
|
import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
|
|
@@ -57,10 +61,11 @@ import { type NodeInfo } from '@aztec/types/interfaces';
|
|
|
57
61
|
|
|
58
62
|
import { type PXEServiceConfig, getPackageInfo } from '../config/index.js';
|
|
59
63
|
import { ContractDataOracle } from '../contract_data_oracle/index.js';
|
|
64
|
+
import { IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
60
65
|
import { type PxeDatabase } from '../database/index.js';
|
|
61
|
-
import { NoteDao } from '../database/note_dao.js';
|
|
62
66
|
import { KernelOracle } from '../kernel_oracle/index.js';
|
|
63
67
|
import { KernelProver } from '../kernel_prover/kernel_prover.js';
|
|
68
|
+
import { TestProofCreator } from '../kernel_prover/test/test_circuit_prover.js';
|
|
64
69
|
import { getAcirSimulator } from '../simulator/index.js';
|
|
65
70
|
import { Synchronizer } from '../synchronizer/index.js';
|
|
66
71
|
|
|
@@ -77,6 +82,8 @@ export class PXEService implements PXE {
|
|
|
77
82
|
// ensures that state is not changed while simulating
|
|
78
83
|
private jobQueue = new SerialQueue();
|
|
79
84
|
|
|
85
|
+
private fakeProofCreator = new TestProofCreator();
|
|
86
|
+
|
|
80
87
|
constructor(
|
|
81
88
|
private keyStore: KeyStore,
|
|
82
89
|
private node: AztecNode,
|
|
@@ -121,11 +128,7 @@ export class PXEService implements PXE {
|
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
count++;
|
|
124
|
-
this.synchronizer.addAccount(
|
|
125
|
-
address.publicKeys.masterIncomingViewingPublicKey,
|
|
126
|
-
this.keyStore,
|
|
127
|
-
this.config.l2StartingBlock,
|
|
128
|
-
);
|
|
131
|
+
await this.synchronizer.addAccount(address.address, this.keyStore, this.config.l2StartingBlock);
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
if (count > 0) {
|
|
@@ -177,6 +180,10 @@ export class PXEService implements PXE {
|
|
|
177
180
|
return artifact && getContractClassFromArtifact(artifact);
|
|
178
181
|
}
|
|
179
182
|
|
|
183
|
+
public getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
|
|
184
|
+
return this.db.getContractArtifact(id);
|
|
185
|
+
}
|
|
186
|
+
|
|
180
187
|
public async registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
|
|
181
188
|
const accounts = await this.keyStore.getAccounts();
|
|
182
189
|
const accountCompleteAddress = await this.keyStore.addAccount(secretKey, partialAddress);
|
|
@@ -184,10 +191,7 @@ export class PXEService implements PXE {
|
|
|
184
191
|
this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`);
|
|
185
192
|
return accountCompleteAddress;
|
|
186
193
|
} else {
|
|
187
|
-
|
|
188
|
-
accountCompleteAddress.address,
|
|
189
|
-
);
|
|
190
|
-
this.synchronizer.addAccount(masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock);
|
|
194
|
+
await this.synchronizer.addAccount(accountCompleteAddress.address, this.keyStore, this.config.l2StartingBlock);
|
|
191
195
|
this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`);
|
|
192
196
|
this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`);
|
|
193
197
|
}
|
|
@@ -258,6 +262,7 @@ export class PXEService implements PXE {
|
|
|
258
262
|
);
|
|
259
263
|
}
|
|
260
264
|
await this.db.addContractArtifact(contractClassId, artifact);
|
|
265
|
+
await this.node.addContractArtifact(instance.address, artifact);
|
|
261
266
|
} else {
|
|
262
267
|
// Otherwise, make sure there is an artifact already registered for that class id
|
|
263
268
|
artifact = await this.db.getContractArtifact(instance.contractClassId);
|
|
@@ -284,19 +289,40 @@ export class PXEService implements PXE {
|
|
|
284
289
|
return await this.node.getPublicStorageAt(contract, slot);
|
|
285
290
|
}
|
|
286
291
|
|
|
287
|
-
public async
|
|
288
|
-
const noteDaos = await this.db.
|
|
292
|
+
public async getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
|
|
293
|
+
const noteDaos = await this.db.getIncomingNotes(filter);
|
|
289
294
|
|
|
290
|
-
// TODO(
|
|
291
|
-
// key
|
|
295
|
+
// TODO(#6531): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
|
|
296
|
+
// key rotation will affect this
|
|
292
297
|
const extendedNotes = noteDaos.map(async dao => {
|
|
293
298
|
let owner = filter.owner;
|
|
294
299
|
if (owner === undefined) {
|
|
295
300
|
const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
|
|
296
|
-
address.publicKeys.masterIncomingViewingPublicKey.equals(dao.
|
|
301
|
+
address.publicKeys.masterIncomingViewingPublicKey.equals(dao.ivpkM),
|
|
297
302
|
);
|
|
298
303
|
if (completeAddresses === undefined) {
|
|
299
|
-
throw new Error(`Cannot find complete address for
|
|
304
|
+
throw new Error(`Cannot find complete address for IvpkM ${dao.ivpkM.toString()}`);
|
|
305
|
+
}
|
|
306
|
+
owner = completeAddresses.address;
|
|
307
|
+
}
|
|
308
|
+
return new ExtendedNote(dao.note, owner, dao.contractAddress, dao.storageSlot, dao.noteTypeId, dao.txHash);
|
|
309
|
+
});
|
|
310
|
+
return Promise.all(extendedNotes);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
public async getOutgoingNotes(filter: OutgoingNotesFilter): Promise<ExtendedNote[]> {
|
|
314
|
+
const noteDaos = await this.db.getOutgoingNotes(filter);
|
|
315
|
+
|
|
316
|
+
// TODO(#6532): Refactor --> This type conversion is ugly but I decided to keep it this way for now because
|
|
317
|
+
// key rotation will affect this
|
|
318
|
+
const extendedNotes = noteDaos.map(async dao => {
|
|
319
|
+
let owner = filter.owner;
|
|
320
|
+
if (owner === undefined) {
|
|
321
|
+
const completeAddresses = (await this.db.getCompleteAddresses()).find(address =>
|
|
322
|
+
address.publicKeys.masterOutgoingViewingPublicKey.equals(dao.ovpkM),
|
|
323
|
+
);
|
|
324
|
+
if (completeAddresses === undefined) {
|
|
325
|
+
throw new Error(`Cannot find complete address for OvpkM ${dao.ovpkM.toString()}`);
|
|
300
326
|
}
|
|
301
327
|
owner = completeAddresses.address;
|
|
302
328
|
}
|
|
@@ -317,13 +343,15 @@ export class PXEService implements PXE {
|
|
|
317
343
|
}
|
|
318
344
|
|
|
319
345
|
for (const nonce of nonces) {
|
|
320
|
-
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
346
|
+
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
347
|
+
await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
348
|
+
note.contractAddress,
|
|
349
|
+
nonce,
|
|
350
|
+
note.storageSlot,
|
|
351
|
+
note.noteTypeId,
|
|
352
|
+
true,
|
|
353
|
+
note.note,
|
|
354
|
+
);
|
|
327
355
|
|
|
328
356
|
const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
|
|
329
357
|
if (index === undefined) {
|
|
@@ -337,7 +365,7 @@ export class PXEService implements PXE {
|
|
|
337
365
|
}
|
|
338
366
|
|
|
339
367
|
await this.db.addNote(
|
|
340
|
-
new
|
|
368
|
+
new IncomingNoteDao(
|
|
341
369
|
note.note,
|
|
342
370
|
note.contractAddress,
|
|
343
371
|
note.storageSlot,
|
|
@@ -353,6 +381,54 @@ export class PXEService implements PXE {
|
|
|
353
381
|
}
|
|
354
382
|
}
|
|
355
383
|
|
|
384
|
+
public async addNullifiedNote(note: ExtendedNote) {
|
|
385
|
+
const owner = await this.db.getCompleteAddress(note.owner);
|
|
386
|
+
if (!owner) {
|
|
387
|
+
throw new Error(`Unknown account: ${note.owner.toString()}`);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const nonces = await this.getNoteNonces(note);
|
|
391
|
+
if (nonces.length === 0) {
|
|
392
|
+
throw new Error(`Cannot find the note in tx: ${note.txHash}.`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
for (const nonce of nonces) {
|
|
396
|
+
const { innerNoteHash, siloedNoteHash, innerNullifier } =
|
|
397
|
+
await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
398
|
+
note.contractAddress,
|
|
399
|
+
nonce,
|
|
400
|
+
note.storageSlot,
|
|
401
|
+
note.noteTypeId,
|
|
402
|
+
false,
|
|
403
|
+
note.note,
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
if (!innerNullifier.equals(Fr.ZERO)) {
|
|
407
|
+
throw new Error('Unexpectedly received non-zero nullifier.');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const index = await this.node.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, siloedNoteHash);
|
|
411
|
+
if (index === undefined) {
|
|
412
|
+
throw new Error('Note does not exist.');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
await this.db.addNullifiedNote(
|
|
416
|
+
new IncomingNoteDao(
|
|
417
|
+
note.note,
|
|
418
|
+
note.contractAddress,
|
|
419
|
+
note.storageSlot,
|
|
420
|
+
note.noteTypeId,
|
|
421
|
+
note.txHash,
|
|
422
|
+
nonce,
|
|
423
|
+
innerNoteHash,
|
|
424
|
+
Fr.ZERO, // We are not able to derive
|
|
425
|
+
index,
|
|
426
|
+
owner.publicKeys.masterIncomingViewingPublicKey,
|
|
427
|
+
),
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
356
432
|
/**
|
|
357
433
|
* Finds the nonce(s) for a given note.
|
|
358
434
|
* @param note - The note to find the nonces for.
|
|
@@ -372,11 +448,12 @@ export class PXEService implements PXE {
|
|
|
372
448
|
// Remove this once notes added from public also include nonces.
|
|
373
449
|
{
|
|
374
450
|
const publicNoteNonce = Fr.ZERO;
|
|
375
|
-
const { siloedNoteHash } = await this.simulator.
|
|
451
|
+
const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
376
452
|
note.contractAddress,
|
|
377
453
|
publicNoteNonce,
|
|
378
454
|
note.storageSlot,
|
|
379
455
|
note.noteTypeId,
|
|
456
|
+
false,
|
|
380
457
|
note.note,
|
|
381
458
|
);
|
|
382
459
|
if (tx.noteHashes.some(hash => hash.equals(siloedNoteHash))) {
|
|
@@ -393,11 +470,12 @@ export class PXEService implements PXE {
|
|
|
393
470
|
}
|
|
394
471
|
|
|
395
472
|
const nonce = computeNoteHashNonce(firstNullifier, i);
|
|
396
|
-
const { siloedNoteHash } = await this.simulator.
|
|
473
|
+
const { siloedNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(
|
|
397
474
|
note.contractAddress,
|
|
398
475
|
nonce,
|
|
399
476
|
note.storageSlot,
|
|
400
477
|
note.noteTypeId,
|
|
478
|
+
false,
|
|
401
479
|
note.note,
|
|
402
480
|
);
|
|
403
481
|
if (hash.equals(siloedNoteHash)) {
|
|
@@ -416,8 +494,14 @@ export class PXEService implements PXE {
|
|
|
416
494
|
return await this.node.getBlock(blockNumber);
|
|
417
495
|
}
|
|
418
496
|
|
|
419
|
-
public
|
|
420
|
-
return
|
|
497
|
+
public proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean): Promise<Tx> {
|
|
498
|
+
return this.jobQueue.put(async () => {
|
|
499
|
+
const simulatedTx = await this.#simulateAndProve(txRequest, this.proofCreator, undefined);
|
|
500
|
+
if (simulatePublic) {
|
|
501
|
+
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
|
|
502
|
+
}
|
|
503
|
+
return simulatedTx.tx;
|
|
504
|
+
});
|
|
421
505
|
}
|
|
422
506
|
|
|
423
507
|
public async simulateTx(
|
|
@@ -426,16 +510,15 @@ export class PXEService implements PXE {
|
|
|
426
510
|
msgSender: AztecAddress | undefined = undefined,
|
|
427
511
|
): Promise<SimulatedTx> {
|
|
428
512
|
return await this.jobQueue.put(async () => {
|
|
429
|
-
const simulatedTx = await this.#simulateAndProve(txRequest, msgSender);
|
|
430
|
-
// We log only if the msgSender is undefined, as simulating with a different msgSender
|
|
431
|
-
// is unlikely to be a real transaction, and likely to be only used to read data.
|
|
432
|
-
// Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
|
|
433
|
-
// If we log, the `getTxHash` function will throw.
|
|
434
|
-
|
|
513
|
+
const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender);
|
|
435
514
|
if (simulatePublic) {
|
|
436
515
|
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
|
|
437
516
|
}
|
|
438
517
|
|
|
518
|
+
// We log only if the msgSender is undefined, as simulating with a different msgSender
|
|
519
|
+
// is unlikely to be a real transaction, and likely to be only used to read data.
|
|
520
|
+
// Meaning that it will not necessarily have produced a nullifier (and thus have no TxHash)
|
|
521
|
+
// If we log, the `getTxHash` function will throw.
|
|
439
522
|
if (!msgSender) {
|
|
440
523
|
this.log.info(`Executed local simulation for ${simulatedTx.tx.getTxHash()}`);
|
|
441
524
|
}
|
|
@@ -539,7 +622,7 @@ export class PXEService implements PXE {
|
|
|
539
622
|
return Promise.resolve({
|
|
540
623
|
pxeVersion: this.packageVersion,
|
|
541
624
|
protocolContractAddresses: {
|
|
542
|
-
classRegisterer:
|
|
625
|
+
classRegisterer: ClassRegistererAddress,
|
|
543
626
|
gasToken: getCanonicalGasToken().address,
|
|
544
627
|
instanceDeployer: getCanonicalInstanceDeployer().address,
|
|
545
628
|
keyRegistry: getCanonicalKeyRegistryAddress(),
|
|
@@ -652,18 +735,22 @@ export class PXEService implements PXE {
|
|
|
652
735
|
* the function will also include the new contract's public functions in the transaction object.
|
|
653
736
|
*
|
|
654
737
|
* @param txExecutionRequest - The transaction request to be simulated and proved.
|
|
655
|
-
* @param
|
|
738
|
+
* @param proofCreator - The proof creator to use for proving the execution.
|
|
656
739
|
* @param msgSender - (Optional) The message sender to use for the simulation.
|
|
657
|
-
* @returns An object
|
|
740
|
+
* @returns An object that contains:
|
|
658
741
|
* A private transaction object containing the proof, public inputs, and encrypted logs.
|
|
659
742
|
* The return values of the private execution
|
|
660
743
|
*/
|
|
661
|
-
async #simulateAndProve(
|
|
744
|
+
async #simulateAndProve(
|
|
745
|
+
txExecutionRequest: TxExecutionRequest,
|
|
746
|
+
proofCreator: ProofCreator,
|
|
747
|
+
msgSender?: AztecAddress,
|
|
748
|
+
): Promise<SimulatedTx> {
|
|
662
749
|
// Get values that allow us to reconstruct the block hash
|
|
663
750
|
const executionResult = await this.#simulate(txExecutionRequest, msgSender);
|
|
664
751
|
|
|
665
752
|
const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node);
|
|
666
|
-
const kernelProver = new KernelProver(kernelOracle,
|
|
753
|
+
const kernelProver = new KernelProver(kernelOracle, proofCreator);
|
|
667
754
|
this.log.debug(`Executing kernel prover...`);
|
|
668
755
|
const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult);
|
|
669
756
|
|
|
@@ -746,4 +833,45 @@ export class PXEService implements PXE {
|
|
|
746
833
|
public async isContractPubliclyDeployed(address: AztecAddress): Promise<boolean> {
|
|
747
834
|
return !!(await this.node.getContract(address));
|
|
748
835
|
}
|
|
836
|
+
|
|
837
|
+
public async getEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>, ivpk: Point): Promise<T[]> {
|
|
838
|
+
const blocks = await this.node.getBlocks(from, limit);
|
|
839
|
+
|
|
840
|
+
const txEffects = blocks.flatMap(block => block.body.txEffects);
|
|
841
|
+
const encryptedTxLogs = txEffects.flatMap(txEffect => txEffect.encryptedLogs);
|
|
842
|
+
|
|
843
|
+
const encryptedLogs = encryptedTxLogs.flatMap(encryptedTxLog => encryptedTxLog.unrollLogs());
|
|
844
|
+
|
|
845
|
+
const ivsk = await this.keyStore.getMasterSecretKey(ivpk);
|
|
846
|
+
|
|
847
|
+
const visibleEvents = encryptedLogs
|
|
848
|
+
.map(encryptedLog => TaggedLog.decryptAsIncoming(encryptedLog, ivsk, L1EventPayload))
|
|
849
|
+
.filter(item => item !== undefined) as TaggedLog<L1EventPayload>[];
|
|
850
|
+
|
|
851
|
+
const decodedEvents = visibleEvents
|
|
852
|
+
.map(visibleEvent => {
|
|
853
|
+
if (visibleEvent.payload === undefined) {
|
|
854
|
+
return undefined;
|
|
855
|
+
}
|
|
856
|
+
if (!FunctionSelector.fromField(visibleEvent.payload.eventTypeId).equals(eventMetadata.functionSelector)) {
|
|
857
|
+
return undefined;
|
|
858
|
+
}
|
|
859
|
+
if (visibleEvent.payload.event.items.length !== eventMetadata.fieldNames.length) {
|
|
860
|
+
throw new Error(
|
|
861
|
+
'Something is weird here, we have matching FunctionSelectors, but the actual payload has mismatched length',
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return eventMetadata.fieldNames.reduce(
|
|
866
|
+
(acc, curr, i) => ({
|
|
867
|
+
...acc,
|
|
868
|
+
[curr]: visibleEvent.payload.event.items[i],
|
|
869
|
+
}),
|
|
870
|
+
{} as T,
|
|
871
|
+
);
|
|
872
|
+
})
|
|
873
|
+
.filter(visibleEvent => visibleEvent !== undefined) as T[];
|
|
874
|
+
|
|
875
|
+
return decodedEvents;
|
|
876
|
+
}
|
|
749
877
|
}
|