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