@aztec/pxe 0.23.0 → 0.24.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.
Files changed (53) hide show
  1. package/dest/database/deferred_note_dao.d.ts +4 -0
  2. package/dest/database/deferred_note_dao.d.ts.map +1 -1
  3. package/dest/database/deferred_note_dao.js +6 -3
  4. package/dest/database/note_dao.d.ts +4 -0
  5. package/dest/database/note_dao.d.ts.map +1 -1
  6. package/dest/database/note_dao.js +7 -2
  7. package/dest/database/pxe_database_test_suite.js +2 -2
  8. package/dest/kernel_prover/kernel_prover.js +9 -9
  9. package/dest/kernel_prover/proof_creator.d.ts +10 -10
  10. package/dest/kernel_prover/proof_creator.d.ts.map +1 -1
  11. package/dest/kernel_prover/proof_creator.js +4 -4
  12. package/dest/note_processor/note_processor.d.ts.map +1 -1
  13. package/dest/note_processor/note_processor.js +4 -4
  14. package/dest/note_processor/produce_note_dao.d.ts.map +1 -1
  15. package/dest/note_processor/produce_note_dao.js +4 -4
  16. package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
  17. package/dest/pxe_service/create_pxe_service.js +4 -1
  18. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  19. package/dest/pxe_service/pxe_service.js +5 -5
  20. package/package.json +13 -12
  21. package/src/bin/index.ts +42 -0
  22. package/src/config/index.ts +40 -0
  23. package/src/contract_data_oracle/index.ts +185 -0
  24. package/src/contract_data_oracle/private_functions_tree.ts +127 -0
  25. package/src/contract_database/index.ts +1 -0
  26. package/src/contract_database/memory_contract_database.ts +58 -0
  27. package/src/database/contracts/contract_artifact_db.ts +19 -0
  28. package/src/database/contracts/contract_instance_db.ts +18 -0
  29. package/src/database/deferred_note_dao.ts +55 -0
  30. package/src/database/index.ts +1 -0
  31. package/src/database/kv_pxe_database.ts +409 -0
  32. package/src/database/note_dao.ts +97 -0
  33. package/src/database/pxe_database.ts +162 -0
  34. package/src/database/pxe_database_test_suite.ts +258 -0
  35. package/src/index.ts +11 -0
  36. package/src/kernel_oracle/index.ts +61 -0
  37. package/src/kernel_prover/index.ts +2 -0
  38. package/src/kernel_prover/kernel_prover.ts +388 -0
  39. package/src/kernel_prover/proof_creator.ts +157 -0
  40. package/src/kernel_prover/proving_data_oracle.ts +76 -0
  41. package/src/note_processor/index.ts +1 -0
  42. package/src/note_processor/note_processor.ts +282 -0
  43. package/src/note_processor/produce_note_dao.ts +132 -0
  44. package/src/pxe_http/index.ts +1 -0
  45. package/src/pxe_http/pxe_http_server.ts +73 -0
  46. package/src/pxe_service/create_pxe_service.ts +52 -0
  47. package/src/pxe_service/index.ts +3 -0
  48. package/src/pxe_service/pxe_service.ts +756 -0
  49. package/src/pxe_service/test/pxe_test_suite.ts +138 -0
  50. package/src/simulator/index.ts +24 -0
  51. package/src/simulator_oracle/index.ts +210 -0
  52. package/src/synchronizer/index.ts +1 -0
  53. package/src/synchronizer/synchronizer.ts +427 -0
@@ -0,0 +1,258 @@
1
+ import { INITIAL_L2_BLOCK_NUM, NoteFilter, NoteStatus, randomTxHash } from '@aztec/circuit-types';
2
+ import { AztecAddress, CompleteAddress } from '@aztec/circuits.js';
3
+ import { makeHeader } from '@aztec/circuits.js/factories';
4
+ import { Fr, Point } from '@aztec/foundation/fields';
5
+ import { BenchmarkingContractArtifact } from '@aztec/noir-contracts.js/Benchmarking';
6
+ import { SerializableContractInstance } from '@aztec/types/contracts';
7
+
8
+ import { NoteDao } from './note_dao.js';
9
+ import { randomNoteDao } from './note_dao.test.js';
10
+ import { PxeDatabase } from './pxe_database.js';
11
+
12
+ /**
13
+ * A common test suite for a PXE database.
14
+ * @param getDatabase - A function that returns a database instance.
15
+ */
16
+ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
17
+ let database: PxeDatabase;
18
+
19
+ beforeEach(() => {
20
+ database = getDatabase();
21
+ });
22
+
23
+ describe('Database', () => {
24
+ describe('auth witnesses', () => {
25
+ it('stores and retrieves auth witnesses', async () => {
26
+ const messageHash = Fr.random();
27
+ const witness = [Fr.random(), Fr.random()];
28
+
29
+ await database.addAuthWitness(messageHash, witness);
30
+ await expect(database.getAuthWitness(messageHash)).resolves.toEqual(witness);
31
+ });
32
+
33
+ it("returns undefined if it doesn't have auth witnesses for the message", async () => {
34
+ const messageHash = Fr.random();
35
+ await expect(database.getAuthWitness(messageHash)).resolves.toBeUndefined();
36
+ });
37
+
38
+ it.skip('refuses to overwrite auth witnesses for the same message', async () => {
39
+ const messageHash = Fr.random();
40
+ const witness = [Fr.random(), Fr.random()];
41
+
42
+ await database.addAuthWitness(messageHash, witness);
43
+ await expect(database.addAuthWitness(messageHash, witness)).rejects.toThrow();
44
+ });
45
+ });
46
+
47
+ describe('capsules', () => {
48
+ it('stores and retrieves capsules', async () => {
49
+ const capsule = [Fr.random(), Fr.random()];
50
+
51
+ await database.addCapsule(capsule);
52
+ await expect(database.popCapsule()).resolves.toEqual(capsule);
53
+ });
54
+
55
+ it("returns undefined if it doesn't have capsules", async () => {
56
+ await expect(database.popCapsule()).resolves.toBeUndefined();
57
+ });
58
+
59
+ it('behaves like a stack when storing capsules', async () => {
60
+ const capsule1 = [Fr.random(), Fr.random()];
61
+ const capsule2 = [Fr.random(), Fr.random()];
62
+
63
+ await database.addCapsule(capsule1);
64
+ await database.addCapsule(capsule2);
65
+ await expect(database.popCapsule()).resolves.toEqual(capsule2);
66
+ await expect(database.popCapsule()).resolves.toEqual(capsule1);
67
+ });
68
+ });
69
+
70
+ describe('notes', () => {
71
+ let owners: CompleteAddress[];
72
+ let contractAddresses: AztecAddress[];
73
+ let storageSlots: Fr[];
74
+ let notes: NoteDao[];
75
+
76
+ const filteringTests: [() => NoteFilter, () => NoteDao[]][] = [
77
+ [() => ({}), () => notes],
78
+
79
+ [
80
+ () => ({ contractAddress: contractAddresses[0] }),
81
+ () => notes.filter(note => note.contractAddress.equals(contractAddresses[0])),
82
+ ],
83
+ [() => ({ contractAddress: AztecAddress.random() }), () => []],
84
+
85
+ [
86
+ () => ({ storageSlot: storageSlots[0] }),
87
+ () => notes.filter(note => note.storageSlot.equals(storageSlots[0])),
88
+ ],
89
+ [() => ({ storageSlot: Fr.random() }), () => []],
90
+
91
+ [() => ({ txHash: notes[0].txHash }), () => [notes[0]]],
92
+ [() => ({ txHash: randomTxHash() }), () => []],
93
+
94
+ [() => ({ owner: owners[0].address }), () => notes.filter(note => note.publicKey.equals(owners[0].publicKey))],
95
+
96
+ [
97
+ () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }),
98
+ () =>
99
+ notes.filter(
100
+ note => note.contractAddress.equals(contractAddresses[0]) && note.storageSlot.equals(storageSlots[0]),
101
+ ),
102
+ ],
103
+ [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []],
104
+ ];
105
+
106
+ beforeEach(() => {
107
+ owners = Array.from({ length: 2 }).map(() => CompleteAddress.random());
108
+ contractAddresses = Array.from({ length: 2 }).map(() => AztecAddress.random());
109
+ storageSlots = Array.from({ length: 2 }).map(() => Fr.random());
110
+
111
+ notes = Array.from({ length: 10 }).map((_, i) =>
112
+ randomNoteDao({
113
+ contractAddress: contractAddresses[i % contractAddresses.length],
114
+ storageSlot: storageSlots[i % storageSlots.length],
115
+ publicKey: owners[i % owners.length].publicKey,
116
+ index: BigInt(i),
117
+ }),
118
+ );
119
+ });
120
+
121
+ beforeEach(async () => {
122
+ for (const owner of owners) {
123
+ await database.addCompleteAddress(owner);
124
+ }
125
+ });
126
+
127
+ it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
128
+ await database.addNotes(notes);
129
+ await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected());
130
+ });
131
+
132
+ it.each(filteringTests)('stores notes one by one and retrieves notes', async (getFilter, getExpected) => {
133
+ for (const note of notes) {
134
+ await database.addNote(note);
135
+ }
136
+ await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected());
137
+ });
138
+
139
+ it.each(filteringTests)('retrieves nullified notes', async (getFilter, getExpected) => {
140
+ await database.addNotes(notes);
141
+
142
+ // Nullify all notes and use the same filter as other test cases
143
+ for (const owner of owners) {
144
+ const notesToNullify = notes.filter(note => note.publicKey.equals(owner.publicKey));
145
+ const nullifiers = notesToNullify.map(note => note.siloedNullifier);
146
+ await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify);
147
+ }
148
+
149
+ await expect(database.getNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED })).resolves.toEqual(
150
+ getExpected(),
151
+ );
152
+ });
153
+
154
+ it('skips nullified notes by default or when requesting active', async () => {
155
+ await database.addNotes(notes);
156
+
157
+ const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey));
158
+ const nullifiers = notesToNullify.map(note => note.siloedNullifier);
159
+ await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual(
160
+ notesToNullify,
161
+ );
162
+
163
+ const actualNotesWithDefault = await database.getNotes({});
164
+ const actualNotesWithActive = await database.getNotes({ status: NoteStatus.ACTIVE });
165
+
166
+ expect(actualNotesWithDefault).toEqual(actualNotesWithActive);
167
+ expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note)));
168
+ });
169
+
170
+ it('returns active and nullified notes when requesting either', async () => {
171
+ await database.addNotes(notes);
172
+
173
+ const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey));
174
+ const nullifiers = notesToNullify.map(note => note.siloedNullifier);
175
+ await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual(
176
+ notesToNullify,
177
+ );
178
+
179
+ const result = await database.getNotes({
180
+ status: NoteStatus.ACTIVE_OR_NULLIFIED,
181
+ });
182
+
183
+ // We have to compare the sorted arrays since the database does not return the same order as when originally
184
+ // inserted combining active and nullified results.
185
+ expect(result.sort()).toEqual([...notes].sort());
186
+ });
187
+ });
188
+
189
+ describe('block header', () => {
190
+ it('stores and retrieves the block header', async () => {
191
+ const header = makeHeader(Math.floor(Math.random() * 1000), INITIAL_L2_BLOCK_NUM);
192
+
193
+ await database.setHeader(header);
194
+ expect(database.getHeader()).toEqual(header);
195
+ });
196
+
197
+ it('rejects getting header if no block set', () => {
198
+ expect(() => database.getHeader()).toThrow();
199
+ });
200
+ });
201
+
202
+ describe('addresses', () => {
203
+ it('stores and retrieves addresses', async () => {
204
+ const address = CompleteAddress.random();
205
+ await expect(database.addCompleteAddress(address)).resolves.toBe(true);
206
+ await expect(database.getCompleteAddress(address.address)).resolves.toEqual(address);
207
+ });
208
+
209
+ it('silently ignores an address it already knows about', async () => {
210
+ const address = CompleteAddress.random();
211
+ await expect(database.addCompleteAddress(address)).resolves.toBe(true);
212
+ await expect(database.addCompleteAddress(address)).resolves.toBe(false);
213
+ });
214
+
215
+ it.skip('refuses to overwrite an address with a different public key', async () => {
216
+ const address = CompleteAddress.random();
217
+ const otherAddress = new CompleteAddress(address.address, Point.random(), address.partialAddress);
218
+
219
+ await database.addCompleteAddress(address);
220
+ await expect(database.addCompleteAddress(otherAddress)).rejects.toThrow();
221
+ });
222
+
223
+ it('returns all addresses', async () => {
224
+ const addresses = Array.from({ length: 10 }).map(() => CompleteAddress.random());
225
+ for (const address of addresses) {
226
+ await database.addCompleteAddress(address);
227
+ }
228
+
229
+ const result = await database.getCompleteAddresses();
230
+ expect(result).toEqual(expect.arrayContaining(addresses));
231
+ });
232
+
233
+ it("returns an empty array if it doesn't have addresses", async () => {
234
+ expect(await database.getCompleteAddresses()).toEqual([]);
235
+ });
236
+
237
+ it("returns undefined if it doesn't have an address", async () => {
238
+ expect(await database.getCompleteAddress(CompleteAddress.random().address)).toBeUndefined();
239
+ });
240
+ });
241
+
242
+ describe('contracts', () => {
243
+ it('stores a contract artifact', async () => {
244
+ const artifact = BenchmarkingContractArtifact;
245
+ const id = Fr.random();
246
+ await database.addContractArtifact(id, artifact);
247
+ await expect(database.getContractArtifact(id)).resolves.toEqual(artifact);
248
+ });
249
+
250
+ it('stores a contract instance', async () => {
251
+ const address = AztecAddress.random();
252
+ const instance = SerializableContractInstance.random().withAddress(address);
253
+ await database.addContractInstance(instance);
254
+ await expect(database.getContractInstance(address)).resolves.toEqual(instance);
255
+ });
256
+ });
257
+ });
258
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export * from './pxe_service/index.js';
2
+ export * from './pxe_http/index.js';
3
+ export * from './config/index.js';
4
+
5
+ export { Tx, TxHash } from '@aztec/circuit-types';
6
+
7
+ export { TxRequest, PartialAddress } from '@aztec/circuits.js';
8
+ export * from '@aztec/foundation/fields';
9
+ export * from '@aztec/foundation/eth-address';
10
+ export * from '@aztec/foundation/aztec-address';
11
+ export * from '@aztec/key-store';
@@ -0,0 +1,61 @@
1
+ import { AztecNode, KeyStore } from '@aztec/circuit-types';
2
+ import {
3
+ AztecAddress,
4
+ Fr,
5
+ FunctionSelector,
6
+ MembershipWitness,
7
+ NOTE_HASH_TREE_HEIGHT,
8
+ Point,
9
+ computeContractClassIdPreimage,
10
+ computeSaltedInitializationHash,
11
+ } from '@aztec/circuits.js';
12
+ import { Tuple } from '@aztec/foundation/serialize';
13
+
14
+ import { ContractDataOracle } from '../contract_data_oracle/index.js';
15
+ import { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js';
16
+
17
+ /**
18
+ * A data oracle that provides information needed for simulating a transaction.
19
+ */
20
+ export class KernelOracle implements ProvingDataOracle {
21
+ constructor(private contractDataOracle: ContractDataOracle, private keyStore: KeyStore, private node: AztecNode) {}
22
+
23
+ public async getContractAddressPreimage(address: AztecAddress) {
24
+ const instance = await this.contractDataOracle.getContractInstance(address);
25
+ return {
26
+ saltedInitializationHash: computeSaltedInitializationHash(instance),
27
+ ...instance,
28
+ };
29
+ }
30
+
31
+ public async getContractClassIdPreimage(contractClassId: Fr) {
32
+ const contractClass = await this.contractDataOracle.getContractClass(contractClassId);
33
+ return computeContractClassIdPreimage(contractClass);
34
+ }
35
+
36
+ public async getFunctionMembershipWitness(contractAddress: AztecAddress, selector: FunctionSelector) {
37
+ return await this.contractDataOracle.getFunctionMembershipWitness(contractAddress, selector);
38
+ }
39
+
40
+ public async getVkMembershipWitness() {
41
+ return await this.contractDataOracle.getVkMembershipWitness();
42
+ }
43
+
44
+ async getNoteMembershipWitness(leafIndex: bigint): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT>> {
45
+ const path = await this.node.getNoteHashSiblingPath('latest', leafIndex);
46
+ return new MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT>(
47
+ path.pathSize,
48
+ leafIndex,
49
+ path.toFields() as Tuple<Fr, typeof NOTE_HASH_TREE_HEIGHT>,
50
+ );
51
+ }
52
+
53
+ async getNoteHashTreeRoot(): Promise<Fr> {
54
+ const header = await this.node.getHeader();
55
+ return header.state.partial.noteHashTree.root;
56
+ }
57
+
58
+ public getMasterNullifierSecretKey(nullifierPublicKey: Point) {
59
+ return this.keyStore.getNullifierSecretKeyFromPublicKey(nullifierPublicKey);
60
+ }
61
+ }
@@ -0,0 +1,2 @@
1
+ export * from './kernel_prover.js';
2
+ export * from './proving_data_oracle.js';