@aztec/archiver 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2 → 0.76.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/archiver/archiver.d.ts +186 -0
- package/dest/archiver/archiver.d.ts.map +1 -0
- package/dest/archiver/archiver.js +711 -729
- package/dest/archiver/archiver_store.d.ts +217 -0
- package/dest/archiver/archiver_store.d.ts.map +1 -0
- package/dest/archiver/archiver_store.js +2 -4
- package/dest/archiver/archiver_store_test_suite.d.ts +8 -0
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -0
- package/dest/archiver/archiver_store_test_suite.js +224 -385
- package/dest/archiver/config.d.ts +37 -0
- package/dest/archiver/config.d.ts.map +1 -0
- package/dest/archiver/config.js +15 -9
- package/dest/archiver/data_retrieval.d.ts +71 -0
- package/dest/archiver/data_retrieval.d.ts.map +1 -0
- package/dest/archiver/data_retrieval.js +67 -77
- package/dest/archiver/errors.d.ts +4 -0
- package/dest/archiver/errors.d.ts.map +1 -0
- package/dest/archiver/errors.js +2 -1
- package/dest/archiver/index.d.ts +8 -0
- package/dest/archiver/index.d.ts.map +1 -0
- package/dest/archiver/index.js +1 -0
- package/dest/archiver/instrumentation.d.ts +27 -0
- package/dest/archiver/instrumentation.d.ts.map +1 -0
- package/dest/archiver/instrumentation.js +17 -29
- package/dest/archiver/kv_archiver_store/block_store.d.ts +87 -0
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/block_store.js +127 -118
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +17 -0
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/contract_class_store.js +37 -43
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +13 -0
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/contract_instance_store.js +12 -7
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +147 -0
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +158 -135
- package/dest/archiver/kv_archiver_store/log_store.d.ts +47 -0
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/log_store.js +256 -271
- package/dest/archiver/kv_archiver_store/message_store.d.ts +33 -0
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/message_store.js +48 -42
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +12 -0
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +1 -0
- package/dest/archiver/kv_archiver_store/nullifier_store.js +42 -35
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +23 -0
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +1 -0
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +24 -15
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +168 -0
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +1 -0
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +231 -227
- package/dest/archiver/structs/data_retrieval.d.ts +27 -0
- package/dest/archiver/structs/data_retrieval.d.ts.map +1 -0
- package/dest/archiver/structs/data_retrieval.js +2 -5
- package/dest/archiver/structs/published.d.ts +11 -0
- package/dest/archiver/structs/published.d.ts.map +1 -0
- package/dest/archiver/structs/published.js +2 -1
- package/dest/factory.d.ts +10 -0
- package/dest/factory.d.ts.map +1 -0
- package/dest/factory.js +24 -32
- package/dest/index.d.ts +5 -0
- package/dest/index.d.ts.map +1 -0
- package/dest/index.js +1 -0
- package/dest/rpc/index.d.ts +9 -0
- package/dest/rpc/index.d.ts.map +1 -0
- package/dest/rpc/index.js +8 -7
- package/dest/test/index.d.ts +4 -0
- package/dest/test/index.d.ts.map +1 -0
- package/dest/test/index.js +1 -0
- package/dest/test/mock_archiver.d.ts +22 -0
- package/dest/test/mock_archiver.d.ts.map +1 -0
- package/dest/test/mock_archiver.js +13 -8
- package/dest/test/mock_l1_to_l2_message_source.d.ts +16 -0
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -0
- package/dest/test/mock_l1_to_l2_message_source.js +4 -4
- package/dest/test/mock_l2_block_source.d.ts +80 -0
- package/dest/test/mock_l2_block_source.d.ts.map +1 -0
- package/dest/test/mock_l2_block_source.js +67 -68
- package/package.json +15 -14
- package/src/archiver/config.ts +7 -1
- package/src/archiver/index.ts +1 -1
- package/src/factory.ts +7 -3
- package/src/rpc/index.ts +16 -3
|
@@ -1,340 +1,266 @@
|
|
|
1
1
|
import { InboxLeaf, L2Block, LogId, TxEffect, TxHash, wrapInBlock } from '@aztec/circuit-types';
|
|
2
2
|
import '@aztec/circuit-types/jest';
|
|
3
|
-
import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT, MAX_NULLIFIERS_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_LOG_DATA_SIZE_IN_FIELDS, PrivateLog, PublicLog, SerializableContractInstance, computePublicBytecodeCommitment } from '@aztec/circuits.js';
|
|
4
|
-
import { makeContractClassPublic, makeExecutablePrivateFunctionWithMembershipProof, makeUnconstrainedFunctionWithMembershipProof } from '@aztec/circuits.js/testing';
|
|
3
|
+
import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT, MAX_NULLIFIERS_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_LOG_DATA_SIZE_IN_FIELDS, PrivateLog, PublicLog, SerializableContractInstance, computePublicBytecodeCommitment, } from '@aztec/circuits.js';
|
|
4
|
+
import { makeContractClassPublic, makeExecutablePrivateFunctionWithMembershipProof, makeUnconstrainedFunctionWithMembershipProof, } from '@aztec/circuits.js/testing';
|
|
5
5
|
import { times, timesParallel } from '@aztec/foundation/collection';
|
|
6
6
|
import { randomInt } from '@aztec/foundation/crypto';
|
|
7
7
|
/**
|
|
8
8
|
* @param testName - The name of the test suite.
|
|
9
9
|
* @param getStore - Returns an instance of a store that's already been initialized.
|
|
10
|
-
*/
|
|
11
|
-
|
|
10
|
+
*/
|
|
11
|
+
export function describeArchiverDataStore(testName, getStore) {
|
|
12
|
+
describe(testName, () => {
|
|
12
13
|
let store;
|
|
13
14
|
let blocks;
|
|
14
15
|
const blockTests = [
|
|
15
|
-
[
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
],
|
|
20
|
-
[
|
|
21
|
-
10,
|
|
22
|
-
1,
|
|
23
|
-
()=>blocks.slice(9, 10)
|
|
24
|
-
],
|
|
25
|
-
[
|
|
26
|
-
1,
|
|
27
|
-
10,
|
|
28
|
-
()=>blocks.slice(0, 10)
|
|
29
|
-
],
|
|
30
|
-
[
|
|
31
|
-
2,
|
|
32
|
-
5,
|
|
33
|
-
()=>blocks.slice(1, 6)
|
|
34
|
-
],
|
|
35
|
-
[
|
|
36
|
-
5,
|
|
37
|
-
2,
|
|
38
|
-
()=>blocks.slice(4, 6)
|
|
39
|
-
]
|
|
16
|
+
[1, 1, () => blocks.slice(0, 1)],
|
|
17
|
+
[10, 1, () => blocks.slice(9, 10)],
|
|
18
|
+
[1, 10, () => blocks.slice(0, 10)],
|
|
19
|
+
[2, 5, () => blocks.slice(1, 6)],
|
|
20
|
+
[5, 2, () => blocks.slice(4, 6)],
|
|
40
21
|
];
|
|
41
|
-
const makeL1Published = (block, l1BlockNumber)=>({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
beforeEach(async ()=>{
|
|
22
|
+
const makeL1Published = (block, l1BlockNumber) => ({
|
|
23
|
+
data: block,
|
|
24
|
+
l1: {
|
|
25
|
+
blockNumber: BigInt(l1BlockNumber),
|
|
26
|
+
blockHash: `0x${l1BlockNumber}`,
|
|
27
|
+
timestamp: BigInt(l1BlockNumber * 1000),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
beforeEach(async () => {
|
|
50
31
|
store = await getStore();
|
|
51
|
-
blocks = await timesParallel(10, async (i)=>makeL1Published(await L2Block.random(i + 1), i + 10));
|
|
32
|
+
blocks = await timesParallel(10, async (i) => makeL1Published(await L2Block.random(i + 1), i + 10));
|
|
52
33
|
});
|
|
53
|
-
describe('addBlocks', ()=>{
|
|
54
|
-
it('returns success when adding blocks', async ()=>{
|
|
34
|
+
describe('addBlocks', () => {
|
|
35
|
+
it('returns success when adding blocks', async () => {
|
|
55
36
|
await expect(store.addBlocks(blocks)).resolves.toBe(true);
|
|
56
37
|
});
|
|
57
|
-
it('allows duplicate blocks', async ()=>{
|
|
38
|
+
it('allows duplicate blocks', async () => {
|
|
58
39
|
await store.addBlocks(blocks);
|
|
59
40
|
await expect(store.addBlocks(blocks)).resolves.toBe(true);
|
|
60
41
|
});
|
|
61
42
|
});
|
|
62
|
-
describe('unwindBlocks', ()=>{
|
|
63
|
-
it('unwinding blocks will remove blocks from the chain', async ()=>{
|
|
43
|
+
describe('unwindBlocks', () => {
|
|
44
|
+
it('unwinding blocks will remove blocks from the chain', async () => {
|
|
64
45
|
await store.addBlocks(blocks);
|
|
65
46
|
const blockNumber = await store.getSynchedL2BlockNumber();
|
|
66
|
-
expect(await store.getBlocks(blockNumber, 1)).toEqual([
|
|
67
|
-
blocks[blocks.length - 1]
|
|
68
|
-
]);
|
|
47
|
+
expect(await store.getBlocks(blockNumber, 1)).toEqual([blocks[blocks.length - 1]]);
|
|
69
48
|
await store.unwindBlocks(blockNumber, 1);
|
|
70
49
|
expect(await store.getSynchedL2BlockNumber()).toBe(blockNumber - 1);
|
|
71
50
|
expect(await store.getBlocks(blockNumber, 1)).toEqual([]);
|
|
72
51
|
});
|
|
73
|
-
it('can unwind multiple empty blocks', async ()=>{
|
|
74
|
-
const emptyBlocks = await timesParallel(10, async (i)=>makeL1Published(await L2Block.random(i + 1, 0), i + 10));
|
|
52
|
+
it('can unwind multiple empty blocks', async () => {
|
|
53
|
+
const emptyBlocks = await timesParallel(10, async (i) => makeL1Published(await L2Block.random(i + 1, 0), i + 10));
|
|
75
54
|
await store.addBlocks(emptyBlocks);
|
|
76
55
|
expect(await store.getSynchedL2BlockNumber()).toBe(10);
|
|
77
56
|
await store.unwindBlocks(10, 3);
|
|
78
57
|
expect(await store.getSynchedL2BlockNumber()).toBe(7);
|
|
79
|
-
expect((await store.getBlocks(1, 10)).map(
|
|
80
|
-
1,
|
|
81
|
-
2,
|
|
82
|
-
3,
|
|
83
|
-
4,
|
|
84
|
-
5,
|
|
85
|
-
6,
|
|
86
|
-
7
|
|
87
|
-
]);
|
|
58
|
+
expect((await store.getBlocks(1, 10)).map(b => b.data.number)).toEqual([1, 2, 3, 4, 5, 6, 7]);
|
|
88
59
|
});
|
|
89
|
-
it('refuses to unwind blocks if the tip is not the last block', async ()=>{
|
|
60
|
+
it('refuses to unwind blocks if the tip is not the last block', async () => {
|
|
90
61
|
await store.addBlocks(blocks);
|
|
91
62
|
await expect(store.unwindBlocks(5, 1)).rejects.toThrow(/can only unwind blocks from the tip/i);
|
|
92
63
|
});
|
|
93
64
|
});
|
|
94
|
-
describe('getBlocks', ()=>{
|
|
95
|
-
beforeEach(async ()=>{
|
|
65
|
+
describe('getBlocks', () => {
|
|
66
|
+
beforeEach(async () => {
|
|
96
67
|
await store.addBlocks(blocks);
|
|
97
68
|
});
|
|
98
|
-
it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks)=>{
|
|
69
|
+
it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks) => {
|
|
99
70
|
await expect(store.getBlocks(start, limit)).resolves.toEqual(getExpectedBlocks());
|
|
100
71
|
});
|
|
101
|
-
it('returns an empty array if no blocks are found', async ()=>{
|
|
72
|
+
it('returns an empty array if no blocks are found', async () => {
|
|
102
73
|
await expect(store.getBlocks(12, 1)).resolves.toEqual([]);
|
|
103
74
|
});
|
|
104
|
-
it('throws an error if limit is invalid', async ()=>{
|
|
75
|
+
it('throws an error if limit is invalid', async () => {
|
|
105
76
|
await expect(store.getBlocks(1, 0)).rejects.toThrow('Invalid limit: 0');
|
|
106
77
|
});
|
|
107
|
-
it('throws an error if `from` it is out of range', async ()=>{
|
|
78
|
+
it('throws an error if `from` it is out of range', async () => {
|
|
108
79
|
await expect(store.getBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).rejects.toThrow('Invalid start: -99');
|
|
109
80
|
});
|
|
110
81
|
});
|
|
111
|
-
describe('getSyncedL2BlockNumber', ()=>{
|
|
112
|
-
it('returns the block number before INITIAL_L2_BLOCK_NUM if no blocks have been added', async ()=>{
|
|
82
|
+
describe('getSyncedL2BlockNumber', () => {
|
|
83
|
+
it('returns the block number before INITIAL_L2_BLOCK_NUM if no blocks have been added', async () => {
|
|
113
84
|
await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(INITIAL_L2_BLOCK_NUM - 1);
|
|
114
85
|
});
|
|
115
|
-
it("returns the most recently added block's number", async ()=>{
|
|
86
|
+
it("returns the most recently added block's number", async () => {
|
|
116
87
|
await store.addBlocks(blocks);
|
|
117
88
|
await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.at(-1).data.number);
|
|
118
89
|
});
|
|
119
90
|
});
|
|
120
|
-
describe('getSynchPoint', ()=>{
|
|
121
|
-
it('returns undefined if no blocks have been added', async ()=>{
|
|
91
|
+
describe('getSynchPoint', () => {
|
|
92
|
+
it('returns undefined if no blocks have been added', async () => {
|
|
122
93
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
123
94
|
blocksSynchedTo: undefined,
|
|
124
|
-
messagesSynchedTo: undefined
|
|
95
|
+
messagesSynchedTo: undefined,
|
|
125
96
|
});
|
|
126
97
|
});
|
|
127
|
-
it('returns the L1 block number in which the most recent L2 block was published', async ()=>{
|
|
98
|
+
it('returns the L1 block number in which the most recent L2 block was published', async () => {
|
|
128
99
|
await store.addBlocks(blocks);
|
|
129
100
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
130
101
|
blocksSynchedTo: 19n,
|
|
131
|
-
messagesSynchedTo: undefined
|
|
102
|
+
messagesSynchedTo: undefined,
|
|
132
103
|
});
|
|
133
104
|
});
|
|
134
|
-
it('returns the L1 block number that most recently added messages from inbox', async ()=>{
|
|
105
|
+
it('returns the L1 block number that most recently added messages from inbox', async () => {
|
|
135
106
|
await store.addL1ToL2Messages({
|
|
136
107
|
lastProcessedL1BlockNumber: 1n,
|
|
137
|
-
retrievedData: [
|
|
138
|
-
new InboxLeaf(1n, Fr.ZERO)
|
|
139
|
-
]
|
|
108
|
+
retrievedData: [new InboxLeaf(1n, Fr.ZERO)],
|
|
140
109
|
});
|
|
141
110
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
142
111
|
blocksSynchedTo: undefined,
|
|
143
|
-
messagesSynchedTo: 1n
|
|
112
|
+
messagesSynchedTo: 1n,
|
|
144
113
|
});
|
|
145
114
|
});
|
|
146
115
|
});
|
|
147
|
-
describe('addLogs', ()=>{
|
|
148
|
-
it('adds private & public logs', async ()=>{
|
|
116
|
+
describe('addLogs', () => {
|
|
117
|
+
it('adds private & public logs', async () => {
|
|
149
118
|
const block = blocks[0].data;
|
|
150
|
-
await expect(store.addLogs([
|
|
151
|
-
block
|
|
152
|
-
])).resolves.toEqual(true);
|
|
119
|
+
await expect(store.addLogs([block])).resolves.toEqual(true);
|
|
153
120
|
});
|
|
154
121
|
});
|
|
155
|
-
describe('deleteLogs', ()=>{
|
|
156
|
-
it('deletes private & public logs', async ()=>{
|
|
122
|
+
describe('deleteLogs', () => {
|
|
123
|
+
it('deletes private & public logs', async () => {
|
|
157
124
|
const block = blocks[0].data;
|
|
158
|
-
await store.addBlocks([
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
await
|
|
162
|
-
block
|
|
163
|
-
])).resolves.toEqual(true);
|
|
164
|
-
expect((await store.getPrivateLogs(1, 1)).length).toEqual(block.body.txEffects.map((txEffect)=>txEffect.privateLogs).flat().length);
|
|
165
|
-
expect((await store.getPublicLogs({
|
|
166
|
-
fromBlock: 1
|
|
167
|
-
})).logs.length).toEqual(block.body.txEffects.map((txEffect)=>txEffect.publicLogs).flat().length);
|
|
125
|
+
await store.addBlocks([blocks[0]]);
|
|
126
|
+
await expect(store.addLogs([block])).resolves.toEqual(true);
|
|
127
|
+
expect((await store.getPrivateLogs(1, 1)).length).toEqual(block.body.txEffects.map(txEffect => txEffect.privateLogs).flat().length);
|
|
128
|
+
expect((await store.getPublicLogs({ fromBlock: 1 })).logs.length).toEqual(block.body.txEffects.map(txEffect => txEffect.publicLogs).flat().length);
|
|
168
129
|
// This one is a pain for memory as we would never want to just delete memory in the middle.
|
|
169
|
-
await store.deleteLogs([
|
|
170
|
-
block
|
|
171
|
-
]);
|
|
130
|
+
await store.deleteLogs([block]);
|
|
172
131
|
expect((await store.getPrivateLogs(1, 1)).length).toEqual(0);
|
|
173
|
-
expect((await store.getPublicLogs({
|
|
174
|
-
fromBlock: 1
|
|
175
|
-
})).logs.length).toEqual(0);
|
|
132
|
+
expect((await store.getPublicLogs({ fromBlock: 1 })).logs.length).toEqual(0);
|
|
176
133
|
});
|
|
177
134
|
});
|
|
178
|
-
describe('getPrivateLogs', ()=>{
|
|
179
|
-
it('gets added private logs', async ()=>{
|
|
135
|
+
describe('getPrivateLogs', () => {
|
|
136
|
+
it('gets added private logs', async () => {
|
|
180
137
|
const block = blocks[0].data;
|
|
181
|
-
await store.addBlocks([
|
|
182
|
-
|
|
183
|
-
]);
|
|
184
|
-
await store.addLogs([
|
|
185
|
-
block
|
|
186
|
-
]);
|
|
138
|
+
await store.addBlocks([blocks[0]]);
|
|
139
|
+
await store.addLogs([block]);
|
|
187
140
|
const privateLogs = await store.getPrivateLogs(1, 1);
|
|
188
|
-
expect(privateLogs).toEqual(block.body.txEffects.map(
|
|
141
|
+
expect(privateLogs).toEqual(block.body.txEffects.map(txEffect => txEffect.privateLogs).flat());
|
|
189
142
|
});
|
|
190
143
|
});
|
|
191
|
-
describe('getTxEffect', ()=>{
|
|
192
|
-
beforeEach(async ()=>{
|
|
193
|
-
await store.addLogs(blocks.map(
|
|
144
|
+
describe('getTxEffect', () => {
|
|
145
|
+
beforeEach(async () => {
|
|
146
|
+
await store.addLogs(blocks.map(b => b.data));
|
|
194
147
|
await store.addBlocks(blocks);
|
|
195
148
|
});
|
|
196
149
|
it.each([
|
|
197
|
-
()=>wrapInBlock(blocks[0].data.body.txEffects[0], blocks[0].data),
|
|
198
|
-
()=>wrapInBlock(blocks[9].data.body.txEffects[3], blocks[9].data),
|
|
199
|
-
()=>wrapInBlock(blocks[3].data.body.txEffects[1], blocks[3].data),
|
|
200
|
-
()=>wrapInBlock(blocks[5].data.body.txEffects[2], blocks[5].data),
|
|
201
|
-
()=>wrapInBlock(blocks[1].data.body.txEffects[0], blocks[1].data)
|
|
202
|
-
])('retrieves a previously stored transaction', async (getExpectedTx)=>{
|
|
150
|
+
() => wrapInBlock(blocks[0].data.body.txEffects[0], blocks[0].data),
|
|
151
|
+
() => wrapInBlock(blocks[9].data.body.txEffects[3], blocks[9].data),
|
|
152
|
+
() => wrapInBlock(blocks[3].data.body.txEffects[1], blocks[3].data),
|
|
153
|
+
() => wrapInBlock(blocks[5].data.body.txEffects[2], blocks[5].data),
|
|
154
|
+
() => wrapInBlock(blocks[1].data.body.txEffects[0], blocks[1].data),
|
|
155
|
+
])('retrieves a previously stored transaction', async (getExpectedTx) => {
|
|
203
156
|
const expectedTx = await getExpectedTx();
|
|
204
157
|
const actualTx = await store.getTxEffect(expectedTx.data.txHash);
|
|
205
158
|
expect(actualTx).toEqual(expectedTx);
|
|
206
159
|
});
|
|
207
|
-
it('returns undefined if tx is not found', async ()=>{
|
|
160
|
+
it('returns undefined if tx is not found', async () => {
|
|
208
161
|
await expect(store.getTxEffect(TxHash.random())).resolves.toBeUndefined();
|
|
209
162
|
});
|
|
210
163
|
it.each([
|
|
211
|
-
()=>wrapInBlock(blocks[0].data.body.txEffects[0], blocks[0].data),
|
|
212
|
-
()=>wrapInBlock(blocks[9].data.body.txEffects[3], blocks[9].data),
|
|
213
|
-
()=>wrapInBlock(blocks[3].data.body.txEffects[1], blocks[3].data),
|
|
214
|
-
()=>wrapInBlock(blocks[5].data.body.txEffects[2], blocks[5].data),
|
|
215
|
-
()=>wrapInBlock(blocks[1].data.body.txEffects[0], blocks[1].data)
|
|
216
|
-
])('tries to retrieves a previously stored transaction after deleted', async (getExpectedTx)=>{
|
|
164
|
+
() => wrapInBlock(blocks[0].data.body.txEffects[0], blocks[0].data),
|
|
165
|
+
() => wrapInBlock(blocks[9].data.body.txEffects[3], blocks[9].data),
|
|
166
|
+
() => wrapInBlock(blocks[3].data.body.txEffects[1], blocks[3].data),
|
|
167
|
+
() => wrapInBlock(blocks[5].data.body.txEffects[2], blocks[5].data),
|
|
168
|
+
() => wrapInBlock(blocks[1].data.body.txEffects[0], blocks[1].data),
|
|
169
|
+
])('tries to retrieves a previously stored transaction after deleted', async (getExpectedTx) => {
|
|
217
170
|
await store.unwindBlocks(blocks.length, blocks.length);
|
|
218
171
|
const expectedTx = await getExpectedTx();
|
|
219
172
|
const actualTx = await store.getTxEffect(expectedTx.data.txHash);
|
|
220
173
|
expect(actualTx).toEqual(undefined);
|
|
221
174
|
});
|
|
222
|
-
it('returns undefined if tx is not found', async ()=>{
|
|
175
|
+
it('returns undefined if tx is not found', async () => {
|
|
223
176
|
await expect(store.getTxEffect(TxHash.random())).resolves.toBeUndefined();
|
|
224
177
|
});
|
|
225
178
|
});
|
|
226
|
-
describe('L1 to L2 Messages', ()=>{
|
|
179
|
+
describe('L1 to L2 Messages', () => {
|
|
227
180
|
const l2BlockNumber = 13n;
|
|
228
181
|
const l1ToL2MessageSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT;
|
|
229
|
-
const generateBlockMessages = (blockNumber, numMessages)=>Array.from({
|
|
230
|
-
|
|
231
|
-
}, (_, i)=>new InboxLeaf(InboxLeaf.smallestIndexFromL2Block(blockNumber) + BigInt(i), Fr.random()));
|
|
232
|
-
it('returns messages in correct order', async ()=>{
|
|
182
|
+
const generateBlockMessages = (blockNumber, numMessages) => Array.from({ length: numMessages }, (_, i) => new InboxLeaf(InboxLeaf.smallestIndexFromL2Block(blockNumber) + BigInt(i), Fr.random()));
|
|
183
|
+
it('returns messages in correct order', async () => {
|
|
233
184
|
const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize);
|
|
234
|
-
const shuffledMessages = msgs.slice().sort(()=>randomInt(1) - 0.5);
|
|
235
|
-
await store.addL1ToL2Messages({
|
|
236
|
-
lastProcessedL1BlockNumber: 100n,
|
|
237
|
-
retrievedData: shuffledMessages
|
|
238
|
-
});
|
|
185
|
+
const shuffledMessages = msgs.slice().sort(() => randomInt(1) - 0.5);
|
|
186
|
+
await store.addL1ToL2Messages({ lastProcessedL1BlockNumber: 100n, retrievedData: shuffledMessages });
|
|
239
187
|
const retrievedMessages = await store.getL1ToL2Messages(l2BlockNumber);
|
|
240
|
-
const expectedLeavesOrder = msgs.map(
|
|
188
|
+
const expectedLeavesOrder = msgs.map(msg => msg.leaf);
|
|
241
189
|
expect(expectedLeavesOrder).toEqual(retrievedMessages);
|
|
242
190
|
});
|
|
243
|
-
it('throws if it is impossible to sequence messages correctly', async ()=>{
|
|
191
|
+
it('throws if it is impossible to sequence messages correctly', async () => {
|
|
244
192
|
const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize - 1);
|
|
245
193
|
// We replace a message with index 4 with a message with index at the end of the tree
|
|
246
194
|
// --> with that there will be a gap and it will be impossible to sequence the
|
|
247
195
|
// end of tree = start of next tree/block - 1
|
|
248
196
|
msgs[4] = new InboxLeaf(InboxLeaf.smallestIndexFromL2Block(l2BlockNumber + 1n) - 1n, Fr.random());
|
|
249
|
-
await store.addL1ToL2Messages({
|
|
250
|
-
|
|
251
|
-
retrievedData: msgs
|
|
252
|
-
});
|
|
253
|
-
await expect(async ()=>{
|
|
197
|
+
await store.addL1ToL2Messages({ lastProcessedL1BlockNumber: 100n, retrievedData: msgs });
|
|
198
|
+
await expect(async () => {
|
|
254
199
|
await store.getL1ToL2Messages(l2BlockNumber);
|
|
255
200
|
}).rejects.toThrow(`L1 to L2 message gap found in block ${l2BlockNumber}`);
|
|
256
201
|
});
|
|
257
202
|
});
|
|
258
|
-
describe('contractInstances', ()=>{
|
|
203
|
+
describe('contractInstances', () => {
|
|
259
204
|
let contractInstance;
|
|
260
205
|
const blockNum = 10;
|
|
261
|
-
beforeEach(async ()=>{
|
|
206
|
+
beforeEach(async () => {
|
|
262
207
|
const randomInstance = await SerializableContractInstance.random();
|
|
263
|
-
contractInstance = {
|
|
264
|
-
|
|
265
|
-
address: await AztecAddress.random()
|
|
266
|
-
};
|
|
267
|
-
await store.addContractInstances([
|
|
268
|
-
contractInstance
|
|
269
|
-
], blockNum);
|
|
208
|
+
contractInstance = { ...randomInstance, address: await AztecAddress.random() };
|
|
209
|
+
await store.addContractInstances([contractInstance], blockNum);
|
|
270
210
|
});
|
|
271
|
-
it('returns previously stored contract instances', async ()=>{
|
|
211
|
+
it('returns previously stored contract instances', async () => {
|
|
272
212
|
await expect(store.getContractInstance(contractInstance.address)).resolves.toMatchObject(contractInstance);
|
|
273
213
|
});
|
|
274
|
-
it('returns undefined if contract instance is not found', async ()=>{
|
|
214
|
+
it('returns undefined if contract instance is not found', async () => {
|
|
275
215
|
await expect(store.getContractInstance(await AztecAddress.random())).resolves.toBeUndefined();
|
|
276
216
|
});
|
|
277
|
-
it('returns undefined if previously stored contract instances was deleted', async ()=>{
|
|
278
|
-
await store.deleteContractInstances([
|
|
279
|
-
contractInstance
|
|
280
|
-
], blockNum);
|
|
217
|
+
it('returns undefined if previously stored contract instances was deleted', async () => {
|
|
218
|
+
await store.deleteContractInstances([contractInstance], blockNum);
|
|
281
219
|
await expect(store.getContractInstance(contractInstance.address)).resolves.toBeUndefined();
|
|
282
220
|
});
|
|
283
221
|
});
|
|
284
|
-
describe('contractClasses', ()=>{
|
|
222
|
+
describe('contractClasses', () => {
|
|
285
223
|
let contractClass;
|
|
286
224
|
const blockNum = 10;
|
|
287
|
-
beforeEach(async ()=>{
|
|
225
|
+
beforeEach(async () => {
|
|
288
226
|
contractClass = await makeContractClassPublic();
|
|
289
|
-
await store.addContractClasses([
|
|
290
|
-
contractClass
|
|
291
|
-
], [
|
|
292
|
-
await computePublicBytecodeCommitment(contractClass.packedBytecode)
|
|
293
|
-
], blockNum);
|
|
227
|
+
await store.addContractClasses([contractClass], [await computePublicBytecodeCommitment(contractClass.packedBytecode)], blockNum);
|
|
294
228
|
});
|
|
295
|
-
it('returns previously stored contract class', async ()=>{
|
|
229
|
+
it('returns previously stored contract class', async () => {
|
|
296
230
|
await expect(store.getContractClass(contractClass.id)).resolves.toMatchObject(contractClass);
|
|
297
231
|
});
|
|
298
|
-
it('returns undefined if the initial deployed contract class was deleted', async ()=>{
|
|
299
|
-
await store.deleteContractClasses([
|
|
300
|
-
contractClass
|
|
301
|
-
], blockNum);
|
|
232
|
+
it('returns undefined if the initial deployed contract class was deleted', async () => {
|
|
233
|
+
await store.deleteContractClasses([contractClass], blockNum);
|
|
302
234
|
await expect(store.getContractClass(contractClass.id)).resolves.toBeUndefined();
|
|
303
235
|
});
|
|
304
|
-
it('returns contract class if later "deployment" class was deleted', async ()=>{
|
|
305
|
-
await store.addContractClasses([
|
|
306
|
-
|
|
307
|
-
], [
|
|
308
|
-
await computePublicBytecodeCommitment(contractClass.packedBytecode)
|
|
309
|
-
], blockNum + 1);
|
|
310
|
-
await store.deleteContractClasses([
|
|
311
|
-
contractClass
|
|
312
|
-
], blockNum + 1);
|
|
236
|
+
it('returns contract class if later "deployment" class was deleted', async () => {
|
|
237
|
+
await store.addContractClasses([contractClass], [await computePublicBytecodeCommitment(contractClass.packedBytecode)], blockNum + 1);
|
|
238
|
+
await store.deleteContractClasses([contractClass], blockNum + 1);
|
|
313
239
|
await expect(store.getContractClass(contractClass.id)).resolves.toMatchObject(contractClass);
|
|
314
240
|
});
|
|
315
|
-
it('returns undefined if contract class is not found', async ()=>{
|
|
241
|
+
it('returns undefined if contract class is not found', async () => {
|
|
316
242
|
await expect(store.getContractClass(Fr.random())).resolves.toBeUndefined();
|
|
317
243
|
});
|
|
318
|
-
it('adds new private functions', async ()=>{
|
|
244
|
+
it('adds new private functions', async () => {
|
|
319
245
|
const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof);
|
|
320
246
|
await store.addFunctions(contractClass.id, fns, []);
|
|
321
247
|
const stored = await store.getContractClass(contractClass.id);
|
|
322
248
|
expect(stored?.privateFunctions).toEqual(fns);
|
|
323
249
|
});
|
|
324
|
-
it('does not duplicate private functions', async ()=>{
|
|
250
|
+
it('does not duplicate private functions', async () => {
|
|
325
251
|
const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof);
|
|
326
252
|
await store.addFunctions(contractClass.id, fns.slice(0, 1), []);
|
|
327
253
|
await store.addFunctions(contractClass.id, fns, []);
|
|
328
254
|
const stored = await store.getContractClass(contractClass.id);
|
|
329
255
|
expect(stored?.privateFunctions).toEqual(fns);
|
|
330
256
|
});
|
|
331
|
-
it('adds new unconstrained functions', async ()=>{
|
|
257
|
+
it('adds new unconstrained functions', async () => {
|
|
332
258
|
const fns = times(3, makeUnconstrainedFunctionWithMembershipProof);
|
|
333
259
|
await store.addFunctions(contractClass.id, [], fns);
|
|
334
260
|
const stored = await store.getContractClass(contractClass.id);
|
|
335
261
|
expect(stored?.unconstrainedFunctions).toEqual(fns);
|
|
336
262
|
});
|
|
337
|
-
it('does not duplicate unconstrained functions', async ()=>{
|
|
263
|
+
it('does not duplicate unconstrained functions', async () => {
|
|
338
264
|
const fns = times(3, makeUnconstrainedFunctionWithMembershipProof);
|
|
339
265
|
await store.addFunctions(contractClass.id, [], fns.slice(0, 1));
|
|
340
266
|
await store.addFunctions(contractClass.id, [], fns);
|
|
@@ -342,49 +268,46 @@ import { randomInt } from '@aztec/foundation/crypto';
|
|
|
342
268
|
expect(stored?.unconstrainedFunctions).toEqual(fns);
|
|
343
269
|
});
|
|
344
270
|
});
|
|
345
|
-
describe('getLogsByTags', ()=>{
|
|
271
|
+
describe('getLogsByTags', () => {
|
|
346
272
|
const numBlocks = 3;
|
|
347
273
|
const numTxsPerBlock = 4;
|
|
348
274
|
const numPrivateLogsPerTx = 3;
|
|
349
275
|
const numPublicLogsPerTx = 2;
|
|
350
276
|
let blocks;
|
|
351
|
-
const makeTag = (blockNumber, txIndex, logIndex, isPublic = false)=>new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1));
|
|
277
|
+
const makeTag = (blockNumber, txIndex, logIndex, isPublic = false) => new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1));
|
|
352
278
|
// See parseLogFromPublic
|
|
353
279
|
// Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
|
|
354
|
-
const makeLengthsField = (publicValuesLen, privateValuesLen)=>{
|
|
280
|
+
const makeLengthsField = (publicValuesLen, privateValuesLen) => {
|
|
355
281
|
const buf = Buffer.alloc(32);
|
|
356
282
|
buf.writeUint16BE(publicValuesLen, 27);
|
|
357
283
|
buf.writeUint16BE(privateValuesLen, 30);
|
|
358
284
|
return Fr.fromBuffer(buf);
|
|
359
285
|
};
|
|
360
|
-
const makePrivateLog = (tag)=>PrivateLog.fromFields([
|
|
361
|
-
tag,
|
|
362
|
-
...times(PRIVATE_LOG_SIZE_IN_FIELDS - 1, (i)=>new Fr(tag.toNumber() + i))
|
|
363
|
-
]);
|
|
286
|
+
const makePrivateLog = (tag) => PrivateLog.fromFields([tag, ...times(PRIVATE_LOG_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i))]);
|
|
364
287
|
// The tag lives in field 1, not 0, of a public log
|
|
365
288
|
// See extractTaggedLogsFromPublic and noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr -> emit_log
|
|
366
|
-
const makePublicLog = (tag)=>PublicLog.fromFields([
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const mockPrivateLogs = (blockNumber, txIndex)=>{
|
|
373
|
-
return times(numPrivateLogsPerTx, (logIndex)=>{
|
|
289
|
+
const makePublicLog = (tag) => PublicLog.fromFields([
|
|
290
|
+
AztecAddress.fromNumber(1).toField(), // log address
|
|
291
|
+
makeLengthsField(2, PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 3), // field 0
|
|
292
|
+
tag, // field 1
|
|
293
|
+
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i)), // fields 2 to end
|
|
294
|
+
]);
|
|
295
|
+
const mockPrivateLogs = (blockNumber, txIndex) => {
|
|
296
|
+
return times(numPrivateLogsPerTx, (logIndex) => {
|
|
374
297
|
const tag = makeTag(blockNumber, txIndex, logIndex);
|
|
375
298
|
return makePrivateLog(tag);
|
|
376
299
|
});
|
|
377
300
|
};
|
|
378
|
-
const mockPublicLogs = (blockNumber, txIndex)=>{
|
|
379
|
-
return times(numPublicLogsPerTx, (logIndex)=>{
|
|
301
|
+
const mockPublicLogs = (blockNumber, txIndex) => {
|
|
302
|
+
return times(numPublicLogsPerTx, (logIndex) => {
|
|
380
303
|
const tag = makeTag(blockNumber, txIndex, logIndex, /* isPublic */ true);
|
|
381
304
|
return makePublicLog(tag);
|
|
382
305
|
});
|
|
383
306
|
};
|
|
384
|
-
const mockBlockWithLogs = async (blockNumber)=>{
|
|
307
|
+
const mockBlockWithLogs = async (blockNumber) => {
|
|
385
308
|
const block = await L2Block.random(blockNumber);
|
|
386
309
|
block.header.globalVariables.blockNumber = new Fr(blockNumber);
|
|
387
|
-
block.body.txEffects = await timesParallel(numTxsPerBlock, async (txIndex)=>{
|
|
310
|
+
block.body.txEffects = await timesParallel(numTxsPerBlock, async (txIndex) => {
|
|
388
311
|
const txEffect = await TxEffect.random();
|
|
389
312
|
txEffect.privateLogs = mockPrivateLogs(blockNumber, txIndex);
|
|
390
313
|
txEffect.publicLogs = mockPublicLogs(blockNumber, txIndex);
|
|
@@ -392,242 +315,203 @@ import { randomInt } from '@aztec/foundation/crypto';
|
|
|
392
315
|
});
|
|
393
316
|
return {
|
|
394
317
|
data: block,
|
|
395
|
-
l1: {
|
|
396
|
-
blockNumber: BigInt(blockNumber),
|
|
397
|
-
blockHash: `0x${blockNumber}`,
|
|
398
|
-
timestamp: BigInt(blockNumber)
|
|
399
|
-
}
|
|
318
|
+
l1: { blockNumber: BigInt(blockNumber), blockHash: `0x${blockNumber}`, timestamp: BigInt(blockNumber) },
|
|
400
319
|
};
|
|
401
320
|
};
|
|
402
|
-
beforeEach(async ()=>{
|
|
403
|
-
blocks = await timesParallel(numBlocks, (index)=>mockBlockWithLogs(index));
|
|
321
|
+
beforeEach(async () => {
|
|
322
|
+
blocks = await timesParallel(numBlocks, (index) => mockBlockWithLogs(index));
|
|
404
323
|
await store.addBlocks(blocks);
|
|
405
|
-
await store.addLogs(blocks.map(
|
|
324
|
+
await store.addLogs(blocks.map(b => b.data));
|
|
406
325
|
});
|
|
407
|
-
it('is possible to batch request private logs via tags', async ()=>{
|
|
408
|
-
const tags = [
|
|
409
|
-
makeTag(1, 1, 2),
|
|
410
|
-
makeTag(0, 2, 0)
|
|
411
|
-
];
|
|
326
|
+
it('is possible to batch request private logs via tags', async () => {
|
|
327
|
+
const tags = [makeTag(1, 1, 2), makeTag(0, 2, 0)];
|
|
412
328
|
const logsByTags = await store.getLogsByTags(tags);
|
|
413
329
|
expect(logsByTags).toEqual([
|
|
414
330
|
[
|
|
415
331
|
expect.objectContaining({
|
|
416
332
|
blockNumber: 1,
|
|
417
333
|
logData: makePrivateLog(tags[0]).toBuffer(),
|
|
418
|
-
isFromPublic: false
|
|
419
|
-
})
|
|
334
|
+
isFromPublic: false,
|
|
335
|
+
}),
|
|
420
336
|
],
|
|
421
337
|
[
|
|
422
338
|
expect.objectContaining({
|
|
423
339
|
blockNumber: 0,
|
|
424
340
|
logData: makePrivateLog(tags[1]).toBuffer(),
|
|
425
|
-
isFromPublic: false
|
|
426
|
-
})
|
|
427
|
-
]
|
|
341
|
+
isFromPublic: false,
|
|
342
|
+
}),
|
|
343
|
+
],
|
|
428
344
|
]);
|
|
429
345
|
});
|
|
430
|
-
it('is possible to batch request all logs (private and public) via tags', async ()=>{
|
|
346
|
+
it('is possible to batch request all logs (private and public) via tags', async () => {
|
|
431
347
|
// Tag(0, 0, 0) is shared with the first private log and the first public log.
|
|
432
|
-
const tags = [
|
|
433
|
-
makeTag(0, 0, 0)
|
|
434
|
-
];
|
|
348
|
+
const tags = [makeTag(0, 0, 0)];
|
|
435
349
|
const logsByTags = await store.getLogsByTags(tags);
|
|
436
350
|
expect(logsByTags).toEqual([
|
|
437
351
|
[
|
|
438
352
|
expect.objectContaining({
|
|
439
353
|
blockNumber: 0,
|
|
440
354
|
logData: makePrivateLog(tags[0]).toBuffer(),
|
|
441
|
-
isFromPublic: false
|
|
355
|
+
isFromPublic: false,
|
|
442
356
|
}),
|
|
443
357
|
expect.objectContaining({
|
|
444
358
|
blockNumber: 0,
|
|
445
359
|
logData: makePublicLog(tags[0]).toBuffer(),
|
|
446
|
-
isFromPublic: true
|
|
447
|
-
})
|
|
448
|
-
]
|
|
360
|
+
isFromPublic: true,
|
|
361
|
+
}),
|
|
362
|
+
],
|
|
449
363
|
]);
|
|
450
364
|
});
|
|
451
|
-
it('is possible to batch request logs that have the same tag but different content', async ()=>{
|
|
452
|
-
const tags = [
|
|
453
|
-
makeTag(1, 2, 1)
|
|
454
|
-
];
|
|
365
|
+
it('is possible to batch request logs that have the same tag but different content', async () => {
|
|
366
|
+
const tags = [makeTag(1, 2, 1)];
|
|
455
367
|
// Create a block containing logs that have the same tag as the blocks before.
|
|
456
368
|
const newBlockNumber = numBlocks;
|
|
457
369
|
const newBlock = await mockBlockWithLogs(newBlockNumber);
|
|
458
370
|
const newLog = newBlock.data.body.txEffects[1].privateLogs[1];
|
|
459
371
|
newLog.fields[0] = tags[0];
|
|
460
372
|
newBlock.data.body.txEffects[1].privateLogs[1] = newLog;
|
|
461
|
-
await store.addBlocks([
|
|
462
|
-
|
|
463
|
-
]);
|
|
464
|
-
await store.addLogs([
|
|
465
|
-
newBlock.data
|
|
466
|
-
]);
|
|
373
|
+
await store.addBlocks([newBlock]);
|
|
374
|
+
await store.addLogs([newBlock.data]);
|
|
467
375
|
const logsByTags = await store.getLogsByTags(tags);
|
|
468
376
|
expect(logsByTags).toEqual([
|
|
469
377
|
[
|
|
470
378
|
expect.objectContaining({
|
|
471
379
|
blockNumber: 1,
|
|
472
380
|
logData: makePrivateLog(tags[0]).toBuffer(),
|
|
473
|
-
isFromPublic: false
|
|
381
|
+
isFromPublic: false,
|
|
474
382
|
}),
|
|
475
383
|
expect.objectContaining({
|
|
476
384
|
blockNumber: newBlockNumber,
|
|
477
385
|
logData: newLog.toBuffer(),
|
|
478
|
-
isFromPublic: false
|
|
479
|
-
})
|
|
480
|
-
]
|
|
386
|
+
isFromPublic: false,
|
|
387
|
+
}),
|
|
388
|
+
],
|
|
481
389
|
]);
|
|
482
390
|
});
|
|
483
|
-
it('is possible to request logs for non-existing tags and determine their position', async ()=>{
|
|
484
|
-
const tags = [
|
|
485
|
-
makeTag(99, 88, 77),
|
|
486
|
-
makeTag(1, 1, 1)
|
|
487
|
-
];
|
|
391
|
+
it('is possible to request logs for non-existing tags and determine their position', async () => {
|
|
392
|
+
const tags = [makeTag(99, 88, 77), makeTag(1, 1, 1)];
|
|
488
393
|
const logsByTags = await store.getLogsByTags(tags);
|
|
489
394
|
expect(logsByTags).toEqual([
|
|
490
|
-
[
|
|
395
|
+
[
|
|
396
|
+
// No logs for the first tag.
|
|
397
|
+
],
|
|
491
398
|
[
|
|
492
399
|
expect.objectContaining({
|
|
493
400
|
blockNumber: 1,
|
|
494
401
|
logData: makePrivateLog(tags[1]).toBuffer(),
|
|
495
|
-
isFromPublic: false
|
|
496
|
-
})
|
|
497
|
-
]
|
|
402
|
+
isFromPublic: false,
|
|
403
|
+
}),
|
|
404
|
+
],
|
|
498
405
|
]);
|
|
499
406
|
});
|
|
500
|
-
it('is not possible to add public logs by tag if they are invalid', async ()=>{
|
|
407
|
+
it('is not possible to add public logs by tag if they are invalid', async () => {
|
|
501
408
|
const tag = makeTag(99, 88, 77);
|
|
502
409
|
const invalidLogs = [
|
|
503
410
|
PublicLog.fromFields([
|
|
504
411
|
AztecAddress.fromNumber(1).toField(),
|
|
505
|
-
makeLengthsField(2, 3),
|
|
412
|
+
makeLengthsField(2, 3), // This field claims we have 5 items, but we actually have more
|
|
506
413
|
tag,
|
|
507
|
-
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1,
|
|
414
|
+
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i)),
|
|
508
415
|
]),
|
|
509
416
|
PublicLog.fromFields([
|
|
510
417
|
AztecAddress.fromNumber(1).toField(),
|
|
511
|
-
makeLengthsField(2, PUBLIC_LOG_DATA_SIZE_IN_FIELDS),
|
|
418
|
+
makeLengthsField(2, PUBLIC_LOG_DATA_SIZE_IN_FIELDS), // This field claims we have more than the max items
|
|
512
419
|
tag,
|
|
513
|
-
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1,
|
|
514
|
-
])
|
|
420
|
+
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i)),
|
|
421
|
+
]),
|
|
515
422
|
];
|
|
516
423
|
// Create a block containing these invalid logs
|
|
517
424
|
const newBlockNumber = numBlocks;
|
|
518
425
|
const newBlock = await mockBlockWithLogs(newBlockNumber);
|
|
519
426
|
newBlock.data.body.txEffects[0].publicLogs = invalidLogs;
|
|
520
|
-
await store.addBlocks([
|
|
521
|
-
|
|
522
|
-
]);
|
|
523
|
-
await store.addLogs([
|
|
524
|
-
newBlock.data
|
|
525
|
-
]);
|
|
526
|
-
const logsByTags = await store.getLogsByTags([
|
|
527
|
-
tag
|
|
528
|
-
]);
|
|
427
|
+
await store.addBlocks([newBlock]);
|
|
428
|
+
await store.addLogs([newBlock.data]);
|
|
429
|
+
const logsByTags = await store.getLogsByTags([tag]);
|
|
529
430
|
// Neither of the logs should have been added:
|
|
530
|
-
expect(logsByTags).toEqual([
|
|
531
|
-
[]
|
|
532
|
-
]);
|
|
431
|
+
expect(logsByTags).toEqual([[]]);
|
|
533
432
|
});
|
|
534
433
|
});
|
|
535
|
-
describe('getPublicLogs', ()=>{
|
|
434
|
+
describe('getPublicLogs', () => {
|
|
536
435
|
const txsPerBlock = 4;
|
|
537
436
|
const numPublicFunctionCalls = 3;
|
|
538
437
|
const numPublicLogs = 2;
|
|
539
438
|
const numBlocks = 10;
|
|
540
439
|
let blocks;
|
|
541
|
-
beforeEach(async ()=>{
|
|
542
|
-
blocks = await timesParallel(numBlocks, async (index)=>({
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
blockHash: `0x${index}`,
|
|
547
|
-
timestamp: BigInt(index)
|
|
548
|
-
}
|
|
549
|
-
}));
|
|
440
|
+
beforeEach(async () => {
|
|
441
|
+
blocks = await timesParallel(numBlocks, async (index) => ({
|
|
442
|
+
data: await L2Block.random(index + 1, txsPerBlock, numPublicFunctionCalls, numPublicLogs),
|
|
443
|
+
l1: { blockNumber: BigInt(index), blockHash: `0x${index}`, timestamp: BigInt(index) },
|
|
444
|
+
}));
|
|
550
445
|
await store.addBlocks(blocks);
|
|
551
|
-
await store.addLogs(blocks.map(
|
|
446
|
+
await store.addLogs(blocks.map(b => b.data));
|
|
552
447
|
});
|
|
553
|
-
it('no logs returned if deleted ("txHash" filter param is respected variant)', async ()=>{
|
|
448
|
+
it('no logs returned if deleted ("txHash" filter param is respected variant)', async () => {
|
|
554
449
|
// get random tx
|
|
555
450
|
const targetBlockIndex = randomInt(numBlocks);
|
|
556
451
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
557
452
|
const targetTxHash = blocks[targetBlockIndex].data.body.txEffects[targetTxIndex].txHash;
|
|
558
453
|
await Promise.all([
|
|
559
454
|
store.unwindBlocks(blocks.length, blocks.length),
|
|
560
|
-
store.deleteLogs(blocks.map(
|
|
455
|
+
store.deleteLogs(blocks.map(b => b.data)),
|
|
561
456
|
]);
|
|
562
|
-
const response = await store.getPublicLogs({
|
|
563
|
-
txHash: targetTxHash
|
|
564
|
-
});
|
|
457
|
+
const response = await store.getPublicLogs({ txHash: targetTxHash });
|
|
565
458
|
const logs = response.logs;
|
|
566
459
|
expect(response.maxLogsHit).toBeFalsy();
|
|
567
460
|
expect(logs.length).toEqual(0);
|
|
568
461
|
});
|
|
569
|
-
it('"txHash" filter param is respected', async ()=>{
|
|
462
|
+
it('"txHash" filter param is respected', async () => {
|
|
570
463
|
// get random tx
|
|
571
464
|
const targetBlockIndex = randomInt(numBlocks);
|
|
572
465
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
573
466
|
const targetTxHash = blocks[targetBlockIndex].data.body.txEffects[targetTxIndex].txHash;
|
|
574
|
-
const response = await store.getPublicLogs({
|
|
575
|
-
txHash: targetTxHash
|
|
576
|
-
});
|
|
467
|
+
const response = await store.getPublicLogs({ txHash: targetTxHash });
|
|
577
468
|
const logs = response.logs;
|
|
578
469
|
expect(response.maxLogsHit).toBeFalsy();
|
|
579
470
|
const expectedNumLogs = numPublicFunctionCalls * numPublicLogs;
|
|
580
471
|
expect(logs.length).toEqual(expectedNumLogs);
|
|
581
472
|
const targeBlockNumber = targetBlockIndex + INITIAL_L2_BLOCK_NUM;
|
|
582
|
-
for (const log of logs){
|
|
473
|
+
for (const log of logs) {
|
|
583
474
|
expect(log.id.blockNumber).toEqual(targeBlockNumber);
|
|
584
475
|
expect(log.id.txIndex).toEqual(targetTxIndex);
|
|
585
476
|
}
|
|
586
477
|
});
|
|
587
|
-
it('"fromBlock" and "toBlock" filter params are respected', async ()=>{
|
|
478
|
+
it('"fromBlock" and "toBlock" filter params are respected', async () => {
|
|
588
479
|
// Set "fromBlock" and "toBlock"
|
|
589
480
|
const fromBlock = 3;
|
|
590
481
|
const toBlock = 7;
|
|
591
|
-
const response = await store.getPublicLogs({
|
|
592
|
-
fromBlock,
|
|
593
|
-
toBlock
|
|
594
|
-
});
|
|
482
|
+
const response = await store.getPublicLogs({ fromBlock, toBlock });
|
|
595
483
|
const logs = response.logs;
|
|
596
484
|
expect(response.maxLogsHit).toBeFalsy();
|
|
597
485
|
const expectedNumLogs = txsPerBlock * numPublicFunctionCalls * numPublicLogs * (toBlock - fromBlock);
|
|
598
486
|
expect(logs.length).toEqual(expectedNumLogs);
|
|
599
|
-
for (const log of logs){
|
|
487
|
+
for (const log of logs) {
|
|
600
488
|
const blockNumber = log.id.blockNumber;
|
|
601
489
|
expect(blockNumber).toBeGreaterThanOrEqual(fromBlock);
|
|
602
490
|
expect(blockNumber).toBeLessThan(toBlock);
|
|
603
491
|
}
|
|
604
492
|
});
|
|
605
|
-
it('"contractAddress" filter param is respected', async ()=>{
|
|
493
|
+
it('"contractAddress" filter param is respected', async () => {
|
|
606
494
|
// Get a random contract address from the logs
|
|
607
495
|
const targetBlockIndex = randomInt(numBlocks);
|
|
608
496
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
609
497
|
const targetLogIndex = randomInt(numPublicLogs * numPublicFunctionCalls);
|
|
610
498
|
const targetContractAddress = blocks[targetBlockIndex].data.body.txEffects[targetTxIndex].publicLogs[targetLogIndex].contractAddress;
|
|
611
|
-
const response = await store.getPublicLogs({
|
|
612
|
-
contractAddress: targetContractAddress
|
|
613
|
-
});
|
|
499
|
+
const response = await store.getPublicLogs({ contractAddress: targetContractAddress });
|
|
614
500
|
expect(response.maxLogsHit).toBeFalsy();
|
|
615
|
-
for (const extendedLog of response.logs){
|
|
501
|
+
for (const extendedLog of response.logs) {
|
|
616
502
|
expect(extendedLog.log.contractAddress.equals(targetContractAddress)).toBeTruthy();
|
|
617
503
|
}
|
|
618
504
|
});
|
|
619
|
-
it('"afterLog" filter param is respected', async ()=>{
|
|
505
|
+
it('"afterLog" filter param is respected', async () => {
|
|
620
506
|
// Get a random log as reference
|
|
621
507
|
const targetBlockIndex = randomInt(numBlocks);
|
|
622
508
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
623
509
|
const targetLogIndex = randomInt(numPublicLogs);
|
|
624
510
|
const afterLog = new LogId(targetBlockIndex + INITIAL_L2_BLOCK_NUM, targetTxIndex, targetLogIndex);
|
|
625
|
-
const response = await store.getPublicLogs({
|
|
626
|
-
afterLog
|
|
627
|
-
});
|
|
511
|
+
const response = await store.getPublicLogs({ afterLog });
|
|
628
512
|
const logs = response.logs;
|
|
629
513
|
expect(response.maxLogsHit).toBeFalsy();
|
|
630
|
-
for (const log of logs){
|
|
514
|
+
for (const log of logs) {
|
|
631
515
|
const logId = log.id;
|
|
632
516
|
expect(logId.blockNumber).toBeGreaterThanOrEqual(afterLog.blockNumber);
|
|
633
517
|
if (logId.blockNumber === afterLog.blockNumber) {
|
|
@@ -638,87 +522,48 @@ import { randomInt } from '@aztec/foundation/crypto';
|
|
|
638
522
|
}
|
|
639
523
|
}
|
|
640
524
|
});
|
|
641
|
-
it('"txHash" filter param is ignored when "afterLog" is set', async ()=>{
|
|
525
|
+
it('"txHash" filter param is ignored when "afterLog" is set', async () => {
|
|
642
526
|
// Get random txHash
|
|
643
527
|
const txHash = TxHash.random();
|
|
644
528
|
const afterLog = new LogId(1, 0, 0);
|
|
645
|
-
const response = await store.getPublicLogs({
|
|
646
|
-
txHash,
|
|
647
|
-
afterLog
|
|
648
|
-
});
|
|
529
|
+
const response = await store.getPublicLogs({ txHash, afterLog });
|
|
649
530
|
expect(response.logs.length).toBeGreaterThan(1);
|
|
650
531
|
});
|
|
651
|
-
it('intersecting works', async ()=>{
|
|
652
|
-
let logs = (await store.getPublicLogs({
|
|
653
|
-
fromBlock: -10,
|
|
654
|
-
toBlock: -5
|
|
655
|
-
})).logs;
|
|
532
|
+
it('intersecting works', async () => {
|
|
533
|
+
let logs = (await store.getPublicLogs({ fromBlock: -10, toBlock: -5 })).logs;
|
|
656
534
|
expect(logs.length).toBe(0);
|
|
657
535
|
// "fromBlock" gets correctly trimmed to range and "toBlock" is exclusive
|
|
658
|
-
logs = (await store.getPublicLogs({
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
})).logs;
|
|
662
|
-
let blockNumbers = new Set(logs.map((log)=>log.id.blockNumber));
|
|
663
|
-
expect(blockNumbers).toEqual(new Set([
|
|
664
|
-
1,
|
|
665
|
-
2,
|
|
666
|
-
3,
|
|
667
|
-
4
|
|
668
|
-
]));
|
|
536
|
+
logs = (await store.getPublicLogs({ fromBlock: -10, toBlock: 5 })).logs;
|
|
537
|
+
let blockNumbers = new Set(logs.map(log => log.id.blockNumber));
|
|
538
|
+
expect(blockNumbers).toEqual(new Set([1, 2, 3, 4]));
|
|
669
539
|
// "toBlock" should be exclusive
|
|
670
|
-
logs = (await store.getPublicLogs({
|
|
671
|
-
fromBlock: 1,
|
|
672
|
-
toBlock: 1
|
|
673
|
-
})).logs;
|
|
540
|
+
logs = (await store.getPublicLogs({ fromBlock: 1, toBlock: 1 })).logs;
|
|
674
541
|
expect(logs.length).toBe(0);
|
|
675
|
-
logs = (await store.getPublicLogs({
|
|
676
|
-
fromBlock: 10,
|
|
677
|
-
toBlock: 5
|
|
678
|
-
})).logs;
|
|
542
|
+
logs = (await store.getPublicLogs({ fromBlock: 10, toBlock: 5 })).logs;
|
|
679
543
|
expect(logs.length).toBe(0);
|
|
680
544
|
// both "fromBlock" and "toBlock" get correctly capped to range and logs from all blocks are returned
|
|
681
|
-
logs = (await store.getPublicLogs({
|
|
682
|
-
|
|
683
|
-
toBlock: +100
|
|
684
|
-
})).logs;
|
|
685
|
-
blockNumbers = new Set(logs.map((log)=>log.id.blockNumber));
|
|
545
|
+
logs = (await store.getPublicLogs({ fromBlock: -100, toBlock: +100 })).logs;
|
|
546
|
+
blockNumbers = new Set(logs.map(log => log.id.blockNumber));
|
|
686
547
|
expect(blockNumbers.size).toBe(numBlocks);
|
|
687
548
|
// intersecting with "afterLog" works
|
|
688
|
-
logs = (await store.getPublicLogs({
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
})).logs;
|
|
693
|
-
blockNumbers = new Set(logs.map((log)=>log.id.blockNumber));
|
|
694
|
-
expect(blockNumbers).toEqual(new Set([
|
|
695
|
-
4
|
|
696
|
-
]));
|
|
697
|
-
logs = (await store.getPublicLogs({
|
|
698
|
-
toBlock: 5,
|
|
699
|
-
afterLog: new LogId(5, 1, 0)
|
|
700
|
-
})).logs;
|
|
549
|
+
logs = (await store.getPublicLogs({ fromBlock: 2, toBlock: 5, afterLog: new LogId(4, 0, 0) })).logs;
|
|
550
|
+
blockNumbers = new Set(logs.map(log => log.id.blockNumber));
|
|
551
|
+
expect(blockNumbers).toEqual(new Set([4]));
|
|
552
|
+
logs = (await store.getPublicLogs({ toBlock: 5, afterLog: new LogId(5, 1, 0) })).logs;
|
|
701
553
|
expect(logs.length).toBe(0);
|
|
702
|
-
logs = (await store.getPublicLogs({
|
|
703
|
-
fromBlock: 2,
|
|
704
|
-
toBlock: 5,
|
|
705
|
-
afterLog: new LogId(100, 0, 0)
|
|
706
|
-
})).logs;
|
|
554
|
+
logs = (await store.getPublicLogs({ fromBlock: 2, toBlock: 5, afterLog: new LogId(100, 0, 0) })).logs;
|
|
707
555
|
expect(logs.length).toBe(0);
|
|
708
556
|
});
|
|
709
|
-
it('"txIndex" and "logIndex" are respected when "afterLog.blockNumber" is equal to "fromBlock"', async ()=>{
|
|
557
|
+
it('"txIndex" and "logIndex" are respected when "afterLog.blockNumber" is equal to "fromBlock"', async () => {
|
|
710
558
|
// Get a random log as reference
|
|
711
559
|
const targetBlockIndex = randomInt(numBlocks);
|
|
712
560
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
713
561
|
const targetLogIndex = randomInt(numPublicLogs);
|
|
714
562
|
const afterLog = new LogId(targetBlockIndex + INITIAL_L2_BLOCK_NUM, targetTxIndex, targetLogIndex);
|
|
715
|
-
const response = await store.getPublicLogs({
|
|
716
|
-
afterLog,
|
|
717
|
-
fromBlock: afterLog.blockNumber
|
|
718
|
-
});
|
|
563
|
+
const response = await store.getPublicLogs({ afterLog, fromBlock: afterLog.blockNumber });
|
|
719
564
|
const logs = response.logs;
|
|
720
565
|
expect(response.maxLogsHit).toBeFalsy();
|
|
721
|
-
for (const log of logs){
|
|
566
|
+
for (const log of logs) {
|
|
722
567
|
const logId = log.id;
|
|
723
568
|
expect(logId.blockNumber).toBeGreaterThanOrEqual(afterLog.blockNumber);
|
|
724
569
|
if (logId.blockNumber === afterLog.blockNumber) {
|
|
@@ -730,28 +575,24 @@ import { randomInt } from '@aztec/foundation/crypto';
|
|
|
730
575
|
}
|
|
731
576
|
});
|
|
732
577
|
});
|
|
733
|
-
describe('findNullifiersIndexesWithBlock', ()=>{
|
|
578
|
+
describe('findNullifiersIndexesWithBlock', () => {
|
|
734
579
|
let blocks;
|
|
735
580
|
const numBlocks = 10;
|
|
736
581
|
const nullifiersPerBlock = new Map();
|
|
737
|
-
beforeEach(async ()=>{
|
|
738
|
-
blocks = await timesParallel(numBlocks, (index)=>L2Block.random(index + 1, 1));
|
|
739
|
-
blocks.forEach((block, blockIndex)=>{
|
|
740
|
-
nullifiersPerBlock.set(blockIndex, block.body.txEffects.flatMap(
|
|
582
|
+
beforeEach(async () => {
|
|
583
|
+
blocks = await timesParallel(numBlocks, (index) => L2Block.random(index + 1, 1));
|
|
584
|
+
blocks.forEach((block, blockIndex) => {
|
|
585
|
+
nullifiersPerBlock.set(blockIndex, block.body.txEffects.flatMap(txEffect => txEffect.nullifiers));
|
|
741
586
|
});
|
|
742
587
|
});
|
|
743
|
-
it('returns wrapped nullifiers with blocks if they exist', async ()=>{
|
|
588
|
+
it('returns wrapped nullifiers with blocks if they exist', async () => {
|
|
744
589
|
await store.addNullifiers(blocks);
|
|
745
|
-
const nullifiersToRetrieve = [
|
|
746
|
-
...nullifiersPerBlock.get(0),
|
|
747
|
-
...nullifiersPerBlock.get(5),
|
|
748
|
-
Fr.random()
|
|
749
|
-
];
|
|
590
|
+
const nullifiersToRetrieve = [...nullifiersPerBlock.get(0), ...nullifiersPerBlock.get(5), Fr.random()];
|
|
750
591
|
const blockScopedNullifiers = await store.findNullifiersIndexesWithBlock(10, nullifiersToRetrieve);
|
|
751
592
|
expect(blockScopedNullifiers).toHaveLength(nullifiersToRetrieve.length);
|
|
752
593
|
const [undefinedNullifier] = blockScopedNullifiers.slice(-1);
|
|
753
594
|
const realNullifiers = blockScopedNullifiers.slice(0, -1);
|
|
754
|
-
realNullifiers.forEach((blockScopedNullifier, index)=>{
|
|
595
|
+
realNullifiers.forEach((blockScopedNullifier, index) => {
|
|
755
596
|
expect(blockScopedNullifier).not.toBeUndefined();
|
|
756
597
|
const { data, l2BlockNumber } = blockScopedNullifier;
|
|
757
598
|
expect(data).toEqual(expect.any(BigInt));
|
|
@@ -759,26 +600,24 @@ import { randomInt } from '@aztec/foundation/crypto';
|
|
|
759
600
|
});
|
|
760
601
|
expect(undefinedNullifier).toBeUndefined();
|
|
761
602
|
});
|
|
762
|
-
it('returns wrapped nullifiers filtering by blockNumber', async ()=>{
|
|
603
|
+
it('returns wrapped nullifiers filtering by blockNumber', async () => {
|
|
763
604
|
await store.addNullifiers(blocks);
|
|
764
|
-
const nullifiersToRetrieve = [
|
|
765
|
-
...nullifiersPerBlock.get(0),
|
|
766
|
-
...nullifiersPerBlock.get(5)
|
|
767
|
-
];
|
|
605
|
+
const nullifiersToRetrieve = [...nullifiersPerBlock.get(0), ...nullifiersPerBlock.get(5)];
|
|
768
606
|
const blockScopedNullifiers = await store.findNullifiersIndexesWithBlock(5, nullifiersToRetrieve);
|
|
769
607
|
expect(blockScopedNullifiers).toHaveLength(nullifiersToRetrieve.length);
|
|
770
608
|
const undefinedNullifiers = blockScopedNullifiers.slice(-MAX_NULLIFIERS_PER_TX);
|
|
771
609
|
const realNullifiers = blockScopedNullifiers.slice(0, -MAX_NULLIFIERS_PER_TX);
|
|
772
|
-
realNullifiers.forEach(
|
|
610
|
+
realNullifiers.forEach(blockScopedNullifier => {
|
|
773
611
|
expect(blockScopedNullifier).not.toBeUndefined();
|
|
774
612
|
const { data, l2BlockNumber } = blockScopedNullifier;
|
|
775
613
|
expect(data).toEqual(expect.any(BigInt));
|
|
776
614
|
expect(l2BlockNumber).toEqual(1);
|
|
777
615
|
});
|
|
778
|
-
undefinedNullifiers.forEach(
|
|
616
|
+
undefinedNullifiers.forEach(undefinedNullifier => {
|
|
779
617
|
expect(undefinedNullifier).toBeUndefined();
|
|
780
618
|
});
|
|
781
619
|
});
|
|
782
620
|
});
|
|
783
621
|
});
|
|
784
622
|
}
|
|
623
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJjaGl2ZXJfc3RvcmVfdGVzdF9zdWl0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcmNoaXZlci9hcmNoaXZlcl9zdG9yZV90ZXN0X3N1aXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2hHLE9BQU8sMkJBQTJCLENBQUM7QUFDbkMsT0FBTyxFQUNMLFlBQVksRUFHWixFQUFFLEVBQ0Ysb0JBQW9CLEVBQ3BCLDJCQUEyQixFQUMzQixxQkFBcUIsRUFDckIsMEJBQTBCLEVBQzFCLDhCQUE4QixFQUM5QixVQUFVLEVBQ1YsU0FBUyxFQUNULDRCQUE0QixFQUM1QiwrQkFBK0IsR0FDaEMsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGdEQUFnRCxFQUNoRCw0Q0FBNEMsR0FDN0MsTUFBTSw0QkFBNEIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUtyRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUseUJBQXlCLENBQ3ZDLFFBQWdCLEVBQ2hCLFFBQThEO0lBRTlELFFBQVEsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFO1FBQ3RCLElBQUksS0FBd0IsQ0FBQztRQUM3QixJQUFJLE1BQThCLENBQUM7UUFDbkMsTUFBTSxVQUFVLEdBQXFEO1lBQ25FLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNoQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFB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
|