@aztec/pxe 0.70.0 → 0.72.1
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/config/index.d.ts.map +1 -1
- package/dest/config/index.js +3 -3
- package/dest/database/kv_pxe_database.d.ts +7 -5
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +33 -11
- package/dest/database/note_dao.d.ts +2 -4
- package/dest/database/note_dao.d.ts.map +1 -1
- package/dest/database/note_dao.js +3 -7
- package/dest/database/outgoing_note_dao.d.ts +2 -4
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/outgoing_note_dao.js +3 -7
- package/dest/database/pxe_database.d.ts +29 -12
- 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 +162 -67
- package/dest/note_decryption_utils/add_public_values_to_payload.js +2 -2
- package/dest/pxe_service/pxe_service.d.ts +6 -6
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +31 -28
- package/dest/pxe_service/test/pxe_test_suite.js +9 -9
- package/dest/simulator_oracle/index.d.ts +12 -20
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +123 -69
- package/package.json +15 -15
- package/src/config/index.ts +2 -1
- package/src/database/kv_pxe_database.ts +46 -12
- package/src/database/note_dao.ts +6 -34
- package/src/database/outgoing_note_dao.ts +6 -33
- package/src/database/pxe_database.ts +31 -12
- package/src/database/pxe_database_test_suite.ts +189 -75
- package/src/note_decryption_utils/add_public_values_to_payload.ts +1 -1
- package/src/pxe_service/pxe_service.ts +47 -46
- package/src/pxe_service/test/pxe_test_suite.ts +8 -8
- package/src/simulator_oracle/index.ts +237 -88
- package/dest/note_decryption_utils/brute_force_note_info.d.ts +0 -31
- package/dest/note_decryption_utils/brute_force_note_info.d.ts.map +0 -1
- package/dest/note_decryption_utils/brute_force_note_info.js +0 -54
- package/dest/note_decryption_utils/index.d.ts +0 -3
- package/dest/note_decryption_utils/index.d.ts.map +0 -1
- package/dest/note_decryption_utils/index.js +0 -2
- package/dest/note_decryption_utils/produce_note_daos.d.ts +0 -28
- package/dest/note_decryption_utils/produce_note_daos.d.ts.map +0 -1
- package/dest/note_decryption_utils/produce_note_daos.js +0 -33
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts +0 -8
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts.map +0 -1
- package/dest/note_decryption_utils/produce_note_daos_for_key.js +0 -17
- package/src/note_decryption_utils/brute_force_note_info.ts +0 -90
- package/src/note_decryption_utils/index.ts +0 -2
- package/src/note_decryption_utils/produce_note_daos.ts +0 -69
- package/src/note_decryption_utils/produce_note_daos_for_key.ts +0 -59
package/src/database/note_dao.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Note, TxHash, randomTxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { AztecAddress, Fr, Point, type PublicKey } from '@aztec/circuits.js';
|
|
3
3
|
import { NoteSelector } from '@aztec/foundation/abi';
|
|
4
4
|
import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
|
|
5
5
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
6
6
|
import { type NoteData } from '@aztec/simulator/client';
|
|
7
7
|
|
|
8
|
-
import { type NoteInfo } from '../note_decryption_utils/index.js';
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
9
|
* A Note Data Access Object, representing a note that was comitted to the note hash tree, holding all of the
|
|
12
10
|
* information required to use it during execution and manage its state.
|
|
@@ -61,32 +59,6 @@ export class NoteDao implements NoteData {
|
|
|
61
59
|
public noteTypeId: NoteSelector,
|
|
62
60
|
) {}
|
|
63
61
|
|
|
64
|
-
static fromPayloadAndNoteInfo(
|
|
65
|
-
note: Note,
|
|
66
|
-
payload: L1NotePayload,
|
|
67
|
-
noteInfo: NoteInfo,
|
|
68
|
-
l2BlockNumber: number,
|
|
69
|
-
l2BlockHash: string,
|
|
70
|
-
dataStartIndexForTx: number,
|
|
71
|
-
addressPoint: PublicKey,
|
|
72
|
-
) {
|
|
73
|
-
const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
|
|
74
|
-
return new NoteDao(
|
|
75
|
-
note,
|
|
76
|
-
payload.contractAddress,
|
|
77
|
-
payload.storageSlot,
|
|
78
|
-
noteInfo.nonce,
|
|
79
|
-
noteInfo.noteHash,
|
|
80
|
-
noteInfo.siloedNullifier,
|
|
81
|
-
noteInfo.txHash,
|
|
82
|
-
l2BlockNumber,
|
|
83
|
-
l2BlockHash,
|
|
84
|
-
noteHashIndexInTheWholeTree,
|
|
85
|
-
addressPoint,
|
|
86
|
-
payload.noteTypeId,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
62
|
toBuffer(): Buffer {
|
|
91
63
|
return serializeToBuffer([
|
|
92
64
|
this.note,
|
|
@@ -155,9 +127,9 @@ export class NoteDao implements NoteData {
|
|
|
155
127
|
return noteSize + AztecAddress.SIZE_IN_BYTES + Fr.SIZE_IN_BYTES * 4 + TxHash.SIZE + Point.SIZE_IN_BYTES + indexSize;
|
|
156
128
|
}
|
|
157
129
|
|
|
158
|
-
static random({
|
|
130
|
+
static async random({
|
|
159
131
|
note = Note.random(),
|
|
160
|
-
contractAddress =
|
|
132
|
+
contractAddress = undefined,
|
|
161
133
|
storageSlot = Fr.random(),
|
|
162
134
|
nonce = Fr.random(),
|
|
163
135
|
noteHash = Fr.random(),
|
|
@@ -166,12 +138,12 @@ export class NoteDao implements NoteData {
|
|
|
166
138
|
l2BlockNumber = Math.floor(Math.random() * 1000),
|
|
167
139
|
l2BlockHash = Fr.random().toString(),
|
|
168
140
|
index = Fr.random().toBigInt(),
|
|
169
|
-
addressPoint =
|
|
141
|
+
addressPoint = undefined,
|
|
170
142
|
noteTypeId = NoteSelector.random(),
|
|
171
143
|
}: Partial<NoteDao> = {}) {
|
|
172
144
|
return new NoteDao(
|
|
173
145
|
note,
|
|
174
|
-
contractAddress,
|
|
146
|
+
contractAddress ?? (await AztecAddress.random()),
|
|
175
147
|
storageSlot,
|
|
176
148
|
nonce,
|
|
177
149
|
noteHash,
|
|
@@ -180,7 +152,7 @@ export class NoteDao implements NoteData {
|
|
|
180
152
|
l2BlockNumber,
|
|
181
153
|
l2BlockHash,
|
|
182
154
|
index,
|
|
183
|
-
addressPoint,
|
|
155
|
+
addressPoint ?? (await Point.random()),
|
|
184
156
|
noteTypeId,
|
|
185
157
|
);
|
|
186
158
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Note, TxHash, randomTxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { AztecAddress, Fr, Point, type PublicKey } from '@aztec/circuits.js';
|
|
3
3
|
import { NoteSelector } from '@aztec/foundation/abi';
|
|
4
4
|
import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
|
|
5
5
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
6
6
|
|
|
7
|
-
import { type NoteInfo } from '../note_decryption_utils/index.js';
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* A note with contextual data which was decrypted as outgoing.
|
|
11
9
|
*/
|
|
@@ -38,31 +36,6 @@ export class OutgoingNoteDao {
|
|
|
38
36
|
public ovpkM: PublicKey,
|
|
39
37
|
) {}
|
|
40
38
|
|
|
41
|
-
static fromPayloadAndNoteInfo(
|
|
42
|
-
note: Note,
|
|
43
|
-
payload: L1NotePayload,
|
|
44
|
-
noteInfo: NoteInfo,
|
|
45
|
-
l2BlockNumber: number,
|
|
46
|
-
l2BlockHash: string,
|
|
47
|
-
dataStartIndexForTx: number,
|
|
48
|
-
ovpkM: PublicKey,
|
|
49
|
-
) {
|
|
50
|
-
const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
|
|
51
|
-
return new OutgoingNoteDao(
|
|
52
|
-
note,
|
|
53
|
-
payload.contractAddress,
|
|
54
|
-
payload.storageSlot,
|
|
55
|
-
payload.noteTypeId,
|
|
56
|
-
noteInfo.txHash,
|
|
57
|
-
l2BlockNumber,
|
|
58
|
-
l2BlockHash,
|
|
59
|
-
noteInfo.nonce,
|
|
60
|
-
noteInfo.noteHash,
|
|
61
|
-
noteHashIndexInTheWholeTree,
|
|
62
|
-
ovpkM,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
39
|
toBuffer(): Buffer {
|
|
67
40
|
return serializeToBuffer([
|
|
68
41
|
this.note,
|
|
@@ -126,9 +99,9 @@ export class OutgoingNoteDao {
|
|
|
126
99
|
return noteSize + AztecAddress.SIZE_IN_BYTES + Fr.SIZE_IN_BYTES * 2 + TxHash.SIZE + Point.SIZE_IN_BYTES;
|
|
127
100
|
}
|
|
128
101
|
|
|
129
|
-
static random({
|
|
102
|
+
static async random({
|
|
130
103
|
note = Note.random(),
|
|
131
|
-
contractAddress =
|
|
104
|
+
contractAddress = undefined,
|
|
132
105
|
txHash = randomTxHash(),
|
|
133
106
|
storageSlot = Fr.random(),
|
|
134
107
|
noteTypeId = NoteSelector.random(),
|
|
@@ -137,11 +110,11 @@ export class OutgoingNoteDao {
|
|
|
137
110
|
l2BlockHash = Fr.random().toString(),
|
|
138
111
|
noteHash = Fr.random(),
|
|
139
112
|
index = Fr.random().toBigInt(),
|
|
140
|
-
ovpkM =
|
|
113
|
+
ovpkM = undefined,
|
|
141
114
|
}: Partial<OutgoingNoteDao> = {}) {
|
|
142
115
|
return new OutgoingNoteDao(
|
|
143
116
|
note,
|
|
144
|
-
contractAddress,
|
|
117
|
+
contractAddress ?? (await AztecAddress.random()),
|
|
145
118
|
storageSlot,
|
|
146
119
|
noteTypeId,
|
|
147
120
|
txHash,
|
|
@@ -150,7 +123,7 @@ export class OutgoingNoteDao {
|
|
|
150
123
|
nonce,
|
|
151
124
|
noteHash,
|
|
152
125
|
index,
|
|
153
|
-
ovpkM,
|
|
126
|
+
ovpkM ?? (await Point.random()),
|
|
154
127
|
);
|
|
155
128
|
}
|
|
156
129
|
}
|
|
@@ -215,20 +215,39 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
|
|
|
215
215
|
resetNoteSyncData(): Promise<void>;
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* @param
|
|
221
|
-
* @param
|
|
222
|
-
* @param values -
|
|
218
|
+
* Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `dbLoad`.
|
|
219
|
+
* If data was already stored at this slot, it is overwrriten.
|
|
220
|
+
* @param contractAddress - The contract address to scope the data under.
|
|
221
|
+
* @param slot - The slot in the database in which to store the value. Slots need not be contiguous.
|
|
222
|
+
* @param values - The data to store.
|
|
223
223
|
*/
|
|
224
|
-
|
|
224
|
+
dbStore(contractAddress: AztecAddress, slot: Fr, values: Fr[]): Promise<void>;
|
|
225
225
|
|
|
226
226
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* @param
|
|
230
|
-
* @
|
|
231
|
-
* @returns An array of field elements representing the stored data or `null` if no data is stored under the key.
|
|
227
|
+
* Returns data previously stored via `dbStore` in the per-contract non-volatile database.
|
|
228
|
+
* @param contractAddress - The contract address under which the data is scoped.
|
|
229
|
+
* @param slot - The slot in the database to read.
|
|
230
|
+
* @returns The stored data or `null` if no data is stored under the slot.
|
|
232
231
|
*/
|
|
233
|
-
|
|
232
|
+
dbLoad(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null>;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Deletes data in the per-contract non-volatile database. Does nothing if no data was present.
|
|
236
|
+
* @param contractAddress - The contract address under which the data is scoped.
|
|
237
|
+
* @param slot - The slot in the database to delete.
|
|
238
|
+
*/
|
|
239
|
+
dbDelete(contractAddress: AztecAddress, slot: Fr): Promise<void>;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data
|
|
243
|
+
* structures by avoiding repeated calls to `dbLoad` and `dbStore`.
|
|
244
|
+
* Supports overlapping source and destination regions (which will result in the overlapped source values being
|
|
245
|
+
* overwritten). All copied slots must exist in the database (i.e. have been stored and not deleted)
|
|
246
|
+
*
|
|
247
|
+
* @param contractAddress - The contract address under which the data is scoped.
|
|
248
|
+
* @param srcSlot - The first slot to copy from.
|
|
249
|
+
* @param dstSlot - The first slot to copy to.
|
|
250
|
+
* @param numEntries - The number of entries to copy.
|
|
251
|
+
*/
|
|
252
|
+
dbCopy(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void>;
|
|
234
253
|
}
|
|
@@ -8,11 +8,14 @@ import {
|
|
|
8
8
|
} from '@aztec/circuits.js';
|
|
9
9
|
import { makeHeader } from '@aztec/circuits.js/testing';
|
|
10
10
|
import { FunctionType } from '@aztec/foundation/abi';
|
|
11
|
+
import { timesParallel } from '@aztec/foundation/collection';
|
|
11
12
|
import { randomInt } from '@aztec/foundation/crypto';
|
|
12
13
|
import { Fr, Point } from '@aztec/foundation/fields';
|
|
13
14
|
import { BenchmarkingContractArtifact } from '@aztec/noir-contracts.js/Benchmarking';
|
|
14
15
|
import { TestContractArtifact } from '@aztec/noir-contracts.js/Test';
|
|
15
16
|
|
|
17
|
+
import times from 'lodash.times';
|
|
18
|
+
|
|
16
19
|
import { NoteDao } from './note_dao.js';
|
|
17
20
|
import { type PxeDatabase } from './pxe_database.js';
|
|
18
21
|
|
|
@@ -80,53 +83,62 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
80
83
|
let storageSlots: Fr[];
|
|
81
84
|
let notes: NoteDao[];
|
|
82
85
|
|
|
83
|
-
const filteringTests: [() => NotesFilter
|
|
84
|
-
[() => ({}), () => notes],
|
|
86
|
+
const filteringTests: [() => Promise<NotesFilter>, () => Promise<NoteDao[]>][] = [
|
|
87
|
+
[() => Promise.resolve({}), () => Promise.resolve(notes)],
|
|
85
88
|
|
|
86
89
|
[
|
|
87
|
-
() => ({ contractAddress: contractAddresses[0] }),
|
|
88
|
-
() => notes.filter(note => note.contractAddress.equals(contractAddresses[0])),
|
|
90
|
+
() => Promise.resolve({ contractAddress: contractAddresses[0] }),
|
|
91
|
+
() => Promise.resolve(notes.filter(note => note.contractAddress.equals(contractAddresses[0]))),
|
|
89
92
|
],
|
|
90
|
-
[() => ({ contractAddress: AztecAddress.random() }), () => []],
|
|
93
|
+
[async () => ({ contractAddress: await AztecAddress.random() }), () => Promise.resolve([])],
|
|
91
94
|
|
|
92
95
|
[
|
|
93
|
-
() => ({ storageSlot: storageSlots[0] }),
|
|
94
|
-
() => notes.filter(note => note.storageSlot.equals(storageSlots[0])),
|
|
96
|
+
() => Promise.resolve({ storageSlot: storageSlots[0] }),
|
|
97
|
+
() => Promise.resolve(notes.filter(note => note.storageSlot.equals(storageSlots[0]))),
|
|
95
98
|
],
|
|
96
|
-
[() => ({ storageSlot: Fr.random() }), () => []],
|
|
99
|
+
[() => Promise.resolve({ storageSlot: Fr.random() }), () => Promise.resolve([])],
|
|
97
100
|
|
|
98
|
-
[() => ({ txHash: notes[0].txHash }), () => [notes[0]]],
|
|
99
|
-
[() => ({ txHash: randomTxHash() }), () => []],
|
|
101
|
+
[() => Promise.resolve({ txHash: notes[0].txHash }), () => Promise.resolve([notes[0]])],
|
|
102
|
+
[() => Promise.resolve({ txHash: randomTxHash() }), () => Promise.resolve([])],
|
|
100
103
|
|
|
101
104
|
[
|
|
102
|
-
() => ({ owner: owners[0].address }),
|
|
103
|
-
() =>
|
|
105
|
+
() => Promise.resolve({ owner: owners[0].address }),
|
|
106
|
+
async () => {
|
|
107
|
+
const ownerAddressPoint = await owners[0].address.toAddressPoint();
|
|
108
|
+
return notes.filter(note => note.addressPoint.equals(ownerAddressPoint));
|
|
109
|
+
},
|
|
104
110
|
],
|
|
105
111
|
|
|
106
112
|
[
|
|
107
|
-
() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }),
|
|
113
|
+
() => Promise.resolve({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }),
|
|
108
114
|
() =>
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
Promise.resolve(
|
|
116
|
+
notes.filter(
|
|
117
|
+
note => note.contractAddress.equals(contractAddresses[0]) && note.storageSlot.equals(storageSlots[0]),
|
|
118
|
+
),
|
|
111
119
|
),
|
|
112
120
|
],
|
|
113
|
-
[
|
|
121
|
+
[
|
|
122
|
+
() => Promise.resolve({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }),
|
|
123
|
+
() => Promise.resolve([]),
|
|
124
|
+
],
|
|
114
125
|
];
|
|
115
126
|
|
|
116
127
|
beforeEach(async () => {
|
|
117
|
-
owners =
|
|
118
|
-
contractAddresses =
|
|
119
|
-
storageSlots =
|
|
128
|
+
owners = await timesParallel(2, () => CompleteAddress.random());
|
|
129
|
+
contractAddresses = await timesParallel(2, () => AztecAddress.random());
|
|
130
|
+
storageSlots = times(2, () => Fr.random());
|
|
120
131
|
|
|
121
|
-
notes =
|
|
122
|
-
|
|
132
|
+
notes = await timesParallel(10, async i => {
|
|
133
|
+
const addressPoint = await owners[i % owners.length].address.toAddressPoint();
|
|
134
|
+
return NoteDao.random({
|
|
123
135
|
contractAddress: contractAddresses[i % contractAddresses.length],
|
|
124
136
|
storageSlot: storageSlots[i % storageSlots.length],
|
|
125
|
-
addressPoint
|
|
137
|
+
addressPoint,
|
|
126
138
|
index: BigInt(i),
|
|
127
139
|
l2BlockNumber: i,
|
|
128
|
-
})
|
|
129
|
-
);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
130
142
|
|
|
131
143
|
for (const owner of owners) {
|
|
132
144
|
await database.addCompleteAddress(owner);
|
|
@@ -135,9 +147,9 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
135
147
|
|
|
136
148
|
it.each(filteringTests)('stores notes in bulk and retrieves notes', async (getFilter, getExpected) => {
|
|
137
149
|
await database.addNotes(notes);
|
|
138
|
-
const returnedNotes = await database.getNotes(getFilter());
|
|
139
|
-
|
|
140
|
-
expect(returnedNotes.sort()).toEqual(
|
|
150
|
+
const returnedNotes = await database.getNotes(await getFilter());
|
|
151
|
+
const expected = await getExpected();
|
|
152
|
+
expect(returnedNotes.sort()).toEqual(expected.sort());
|
|
141
153
|
});
|
|
142
154
|
|
|
143
155
|
it.each(filteringTests)('stores notes one by one and retrieves notes', async (getFilter, getExpected) => {
|
|
@@ -145,9 +157,10 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
145
157
|
await database.addNote(note);
|
|
146
158
|
}
|
|
147
159
|
|
|
148
|
-
const returnedNotes = await database.getNotes(getFilter());
|
|
160
|
+
const returnedNotes = await database.getNotes(await getFilter());
|
|
149
161
|
|
|
150
|
-
|
|
162
|
+
const expected = await getExpected();
|
|
163
|
+
expect(returnedNotes.sort()).toEqual(expected.sort());
|
|
151
164
|
});
|
|
152
165
|
|
|
153
166
|
it.each(filteringTests)('retrieves nullified notes', async (getFilter, getExpected) => {
|
|
@@ -155,26 +168,25 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
155
168
|
|
|
156
169
|
// Nullify all notes and use the same filter as other test cases
|
|
157
170
|
for (const owner of owners) {
|
|
158
|
-
const
|
|
171
|
+
const ownerAddressPoint = await owner.address.toAddressPoint();
|
|
172
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(ownerAddressPoint));
|
|
159
173
|
const nullifiers = notesToNullify.map(note => ({
|
|
160
174
|
data: note.siloedNullifier,
|
|
161
175
|
l2BlockNumber: note.l2BlockNumber,
|
|
162
176
|
l2BlockHash: note.l2BlockHash,
|
|
163
177
|
}));
|
|
164
|
-
await expect(database.removeNullifiedNotes(nullifiers,
|
|
165
|
-
notesToNullify,
|
|
166
|
-
);
|
|
178
|
+
await expect(database.removeNullifiedNotes(nullifiers, ownerAddressPoint)).resolves.toEqual(notesToNullify);
|
|
167
179
|
}
|
|
168
|
-
|
|
169
|
-
await
|
|
170
|
-
|
|
171
|
-
);
|
|
180
|
+
const filter = await getFilter();
|
|
181
|
+
const returnedNotes = await database.getNotes({ ...filter, status: NoteStatus.ACTIVE_OR_NULLIFIED });
|
|
182
|
+
const expected = await getExpected();
|
|
183
|
+
expect(returnedNotes.sort()).toEqual(expected.sort());
|
|
172
184
|
});
|
|
173
185
|
|
|
174
186
|
it('skips nullified notes by default or when requesting active', async () => {
|
|
175
187
|
await database.addNotes(notes);
|
|
176
|
-
|
|
177
|
-
const notesToNullify = notes.filter(note => note.addressPoint.equals(
|
|
188
|
+
const ownerAddressPoint = await owners[0].address.toAddressPoint();
|
|
189
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(ownerAddressPoint));
|
|
178
190
|
const nullifiers = notesToNullify.map(note => ({
|
|
179
191
|
data: note.siloedNullifier,
|
|
180
192
|
l2BlockNumber: note.l2BlockNumber,
|
|
@@ -194,8 +206,9 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
194
206
|
it('handles note unnullification', async () => {
|
|
195
207
|
await database.setHeader(makeHeader(randomInt(1000), 100, 0 /** slot number */));
|
|
196
208
|
await database.addNotes(notes);
|
|
209
|
+
const ownerAddressPoint = await owners[0].address.toAddressPoint();
|
|
197
210
|
|
|
198
|
-
const notesToNullify = notes.filter(note => note.addressPoint.equals(
|
|
211
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(ownerAddressPoint));
|
|
199
212
|
const nullifiers = notesToNullify.map(note => ({
|
|
200
213
|
data: note.siloedNullifier,
|
|
201
214
|
l2BlockNumber: 99,
|
|
@@ -213,8 +226,9 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
213
226
|
|
|
214
227
|
it('returns active and nullified notes when requesting either', async () => {
|
|
215
228
|
await database.addNotes(notes);
|
|
229
|
+
const ownerAddressPoint = await owners[0].address.toAddressPoint();
|
|
216
230
|
|
|
217
|
-
const notesToNullify = notes.filter(note => note.addressPoint.equals(
|
|
231
|
+
const notesToNullify = notes.filter(note => note.addressPoint.equals(ownerAddressPoint));
|
|
218
232
|
const nullifiers = notesToNullify.map(note => ({
|
|
219
233
|
data: note.siloedNullifier,
|
|
220
234
|
l2BlockNumber: note.l2BlockNumber,
|
|
@@ -275,7 +289,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
275
289
|
scopes: [owners[1].address],
|
|
276
290
|
}),
|
|
277
291
|
).resolves.toEqual([notes[0]]);
|
|
278
|
-
|
|
292
|
+
const ownerAddressPoint = await owners[0].address.toAddressPoint();
|
|
279
293
|
await expect(
|
|
280
294
|
database.removeNullifiedNotes(
|
|
281
295
|
[
|
|
@@ -285,7 +299,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
285
299
|
l2BlockNumber: notes[0].l2BlockNumber,
|
|
286
300
|
},
|
|
287
301
|
],
|
|
288
|
-
|
|
302
|
+
ownerAddressPoint,
|
|
289
303
|
),
|
|
290
304
|
).resolves.toEqual([notes[0]]);
|
|
291
305
|
|
|
@@ -325,22 +339,22 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
325
339
|
|
|
326
340
|
describe('addresses', () => {
|
|
327
341
|
it('stores and retrieves addresses', async () => {
|
|
328
|
-
const address = CompleteAddress.random();
|
|
342
|
+
const address = await CompleteAddress.random();
|
|
329
343
|
await expect(database.addCompleteAddress(address)).resolves.toBe(true);
|
|
330
344
|
await expect(database.getCompleteAddress(address.address)).resolves.toEqual(address);
|
|
331
345
|
});
|
|
332
346
|
|
|
333
347
|
it('silently ignores an address it already knows about', async () => {
|
|
334
|
-
const address = CompleteAddress.random();
|
|
348
|
+
const address = await CompleteAddress.random();
|
|
335
349
|
await expect(database.addCompleteAddress(address)).resolves.toBe(true);
|
|
336
350
|
await expect(database.addCompleteAddress(address)).resolves.toBe(false);
|
|
337
351
|
});
|
|
338
352
|
|
|
339
353
|
it.skip('refuses to overwrite an address with a different public key', async () => {
|
|
340
|
-
const address = CompleteAddress.random();
|
|
341
|
-
const otherAddress =
|
|
354
|
+
const address = await CompleteAddress.random();
|
|
355
|
+
const otherAddress = await CompleteAddress.create(
|
|
342
356
|
address.address,
|
|
343
|
-
new PublicKeys(Point.random(), Point.random(), Point.random(), Point.random()),
|
|
357
|
+
new PublicKeys(await Point.random(), await Point.random(), await Point.random(), await Point.random()),
|
|
344
358
|
address.partialAddress,
|
|
345
359
|
);
|
|
346
360
|
|
|
@@ -349,7 +363,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
349
363
|
});
|
|
350
364
|
|
|
351
365
|
it('returns all addresses', async () => {
|
|
352
|
-
const addresses =
|
|
366
|
+
const addresses = await timesParallel(10, () => CompleteAddress.random());
|
|
353
367
|
for (const address of addresses) {
|
|
354
368
|
await database.addCompleteAddress(address);
|
|
355
369
|
}
|
|
@@ -359,7 +373,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
359
373
|
});
|
|
360
374
|
|
|
361
375
|
it('returns a single address', async () => {
|
|
362
|
-
const addresses =
|
|
376
|
+
const addresses = await timesParallel(10, () => CompleteAddress.random());
|
|
363
377
|
for (const address of addresses) {
|
|
364
378
|
await database.addCompleteAddress(address);
|
|
365
379
|
}
|
|
@@ -373,7 +387,8 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
373
387
|
});
|
|
374
388
|
|
|
375
389
|
it("returns undefined if it doesn't have an address", async () => {
|
|
376
|
-
|
|
390
|
+
const completeAddress = await CompleteAddress.random();
|
|
391
|
+
expect(await database.getCompleteAddress(completeAddress.address)).toBeUndefined();
|
|
377
392
|
});
|
|
378
393
|
});
|
|
379
394
|
|
|
@@ -399,72 +414,171 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
399
414
|
});
|
|
400
415
|
|
|
401
416
|
it('stores a contract instance', async () => {
|
|
402
|
-
const address = AztecAddress.random();
|
|
403
|
-
const instance = SerializableContractInstance.random().withAddress(address);
|
|
417
|
+
const address = await AztecAddress.random();
|
|
418
|
+
const instance = (await SerializableContractInstance.random()).withAddress(address);
|
|
404
419
|
await database.addContractInstance(instance);
|
|
405
420
|
await expect(database.getContractInstance(address)).resolves.toEqual(instance);
|
|
406
421
|
});
|
|
407
422
|
});
|
|
408
423
|
|
|
409
|
-
describe('contract
|
|
424
|
+
describe('contract non-volatile database', () => {
|
|
410
425
|
let contract: AztecAddress;
|
|
411
426
|
|
|
412
|
-
beforeEach(() => {
|
|
427
|
+
beforeEach(async () => {
|
|
413
428
|
// Setup mock contract address
|
|
414
|
-
contract = AztecAddress.random();
|
|
429
|
+
contract = await AztecAddress.random();
|
|
415
430
|
});
|
|
416
431
|
|
|
417
432
|
it('stores and loads a single value', async () => {
|
|
418
|
-
const
|
|
433
|
+
const slot = new Fr(1);
|
|
419
434
|
const values = [new Fr(42)];
|
|
420
435
|
|
|
421
|
-
await database.
|
|
422
|
-
const result = await database.
|
|
436
|
+
await database.dbStore(contract, slot, values);
|
|
437
|
+
const result = await database.dbLoad(contract, slot);
|
|
423
438
|
expect(result).toEqual(values);
|
|
424
439
|
});
|
|
425
440
|
|
|
426
441
|
it('stores and loads multiple values', async () => {
|
|
427
|
-
const
|
|
442
|
+
const slot = new Fr(1);
|
|
428
443
|
const values = [new Fr(42), new Fr(43), new Fr(44)];
|
|
429
444
|
|
|
430
|
-
await database.
|
|
431
|
-
const result = await database.
|
|
445
|
+
await database.dbStore(contract, slot, values);
|
|
446
|
+
const result = await database.dbLoad(contract, slot);
|
|
432
447
|
expect(result).toEqual(values);
|
|
433
448
|
});
|
|
434
449
|
|
|
435
450
|
it('overwrites existing values', async () => {
|
|
436
|
-
const
|
|
451
|
+
const slot = new Fr(1);
|
|
437
452
|
const initialValues = [new Fr(42)];
|
|
438
453
|
const newValues = [new Fr(100)];
|
|
439
454
|
|
|
440
|
-
await database.
|
|
441
|
-
await database.
|
|
455
|
+
await database.dbStore(contract, slot, initialValues);
|
|
456
|
+
await database.dbStore(contract, slot, newValues);
|
|
442
457
|
|
|
443
|
-
const result = await database.
|
|
458
|
+
const result = await database.dbLoad(contract, slot);
|
|
444
459
|
expect(result).toEqual(newValues);
|
|
445
460
|
});
|
|
446
461
|
|
|
447
462
|
it('stores values for different contracts independently', async () => {
|
|
448
|
-
const anotherContract = AztecAddress.random();
|
|
449
|
-
const
|
|
463
|
+
const anotherContract = await AztecAddress.random();
|
|
464
|
+
const slot = new Fr(1);
|
|
450
465
|
const values1 = [new Fr(42)];
|
|
451
466
|
const values2 = [new Fr(100)];
|
|
452
467
|
|
|
453
|
-
await database.
|
|
454
|
-
await database.
|
|
468
|
+
await database.dbStore(contract, slot, values1);
|
|
469
|
+
await database.dbStore(anotherContract, slot, values2);
|
|
455
470
|
|
|
456
|
-
const result1 = await database.
|
|
457
|
-
const result2 = await database.
|
|
471
|
+
const result1 = await database.dbLoad(contract, slot);
|
|
472
|
+
const result2 = await database.dbLoad(anotherContract, slot);
|
|
458
473
|
|
|
459
474
|
expect(result1).toEqual(values1);
|
|
460
475
|
expect(result2).toEqual(values2);
|
|
461
476
|
});
|
|
462
477
|
|
|
463
|
-
it('returns null for non-existent
|
|
464
|
-
const
|
|
465
|
-
const result = await database.
|
|
478
|
+
it('returns null for non-existent slots', async () => {
|
|
479
|
+
const slot = Fr.random();
|
|
480
|
+
const result = await database.dbLoad(contract, slot);
|
|
466
481
|
expect(result).toBeNull();
|
|
467
482
|
});
|
|
483
|
+
|
|
484
|
+
it('deletes a slot', async () => {
|
|
485
|
+
const slot = new Fr(1);
|
|
486
|
+
const values = [new Fr(42)];
|
|
487
|
+
|
|
488
|
+
await database.dbStore(contract, slot, values);
|
|
489
|
+
await database.dbDelete(contract, slot);
|
|
490
|
+
|
|
491
|
+
expect(await database.dbLoad(contract, slot)).toBeNull();
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('deletes an empty slot', async () => {
|
|
495
|
+
const slot = new Fr(1);
|
|
496
|
+
await database.dbDelete(contract, slot);
|
|
497
|
+
|
|
498
|
+
expect(await database.dbLoad(contract, slot)).toBeNull();
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it('copies a single value', async () => {
|
|
502
|
+
const slot = new Fr(1);
|
|
503
|
+
const values = [new Fr(42)];
|
|
504
|
+
|
|
505
|
+
await database.dbStore(contract, slot, values);
|
|
506
|
+
|
|
507
|
+
const dstSlot = new Fr(5);
|
|
508
|
+
await database.dbCopy(contract, slot, dstSlot, 1);
|
|
509
|
+
|
|
510
|
+
expect(await database.dbLoad(contract, dstSlot)).toEqual(values);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
it('copies multiple non-overlapping values', async () => {
|
|
514
|
+
const src = new Fr(1);
|
|
515
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
516
|
+
|
|
517
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
518
|
+
await database.dbStore(contract, src.add(new Fr(1)), valuesArray[1]);
|
|
519
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
520
|
+
|
|
521
|
+
const dst = new Fr(5);
|
|
522
|
+
await database.dbCopy(contract, src, dst, 3);
|
|
523
|
+
|
|
524
|
+
expect(await database.dbLoad(contract, dst)).toEqual(valuesArray[0]);
|
|
525
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(1)))).toEqual(valuesArray[1]);
|
|
526
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(2)))).toEqual(valuesArray[2]);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it('copies overlapping values with src ahead', async () => {
|
|
530
|
+
const src = new Fr(1);
|
|
531
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
532
|
+
|
|
533
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
534
|
+
await database.dbStore(contract, src.add(new Fr(1)), valuesArray[1]);
|
|
535
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
536
|
+
|
|
537
|
+
const dst = new Fr(2);
|
|
538
|
+
await database.dbCopy(contract, src, dst, 3);
|
|
539
|
+
|
|
540
|
+
expect(await database.dbLoad(contract, dst)).toEqual(valuesArray[0]);
|
|
541
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(1)))).toEqual(valuesArray[1]);
|
|
542
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(2)))).toEqual(valuesArray[2]);
|
|
543
|
+
|
|
544
|
+
// Slots 2 and 3 (src[1] and src[2]) should have been overwritten since they are also dst[0] and dst[1]
|
|
545
|
+
expect(await database.dbLoad(contract, src)).toEqual(valuesArray[0]); // src[0] (unchanged)
|
|
546
|
+
expect(await database.dbLoad(contract, src.add(new Fr(1)))).toEqual(valuesArray[0]); // dst[0]
|
|
547
|
+
expect(await database.dbLoad(contract, src.add(new Fr(2)))).toEqual(valuesArray[1]); // dst[1]
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it('copies overlapping values with dst ahead', async () => {
|
|
551
|
+
const src = new Fr(5);
|
|
552
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
553
|
+
|
|
554
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
555
|
+
await database.dbStore(contract, src.add(new Fr(1)), valuesArray[1]);
|
|
556
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
557
|
+
|
|
558
|
+
const dst = new Fr(4);
|
|
559
|
+
await database.dbCopy(contract, src, dst, 3);
|
|
560
|
+
|
|
561
|
+
expect(await database.dbLoad(contract, dst)).toEqual(valuesArray[0]);
|
|
562
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(1)))).toEqual(valuesArray[1]);
|
|
563
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(2)))).toEqual(valuesArray[2]);
|
|
564
|
+
|
|
565
|
+
// Slots 5 and 6 (src[0] and src[1]) should have been overwritten since they are also dst[1] and dst[2]
|
|
566
|
+
expect(await database.dbLoad(contract, src)).toEqual(valuesArray[1]); // dst[1]
|
|
567
|
+
expect(await database.dbLoad(contract, src.add(new Fr(1)))).toEqual(valuesArray[2]); // dst[2]
|
|
568
|
+
expect(await database.dbLoad(contract, src.add(new Fr(2)))).toEqual(valuesArray[2]); // src[2] (unchanged)
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it('copying fails if any value is empty', async () => {
|
|
572
|
+
const src = new Fr(1);
|
|
573
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
574
|
+
|
|
575
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
576
|
+
// We skip src[1]
|
|
577
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
578
|
+
|
|
579
|
+
const dst = new Fr(5);
|
|
580
|
+
await expect(database.dbCopy(contract, src, dst, 3)).rejects.toThrow('Attempted to copy empty slot');
|
|
581
|
+
});
|
|
468
582
|
});
|
|
469
583
|
});
|
|
470
584
|
}
|