@aztec/archiver 0.0.0-test.1 → 0.0.1-commit.24de95ac
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/README.md +27 -6
- package/dest/archiver/archiver.d.ts +126 -46
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +683 -261
- package/dest/archiver/archiver_store.d.ts +84 -49
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +707 -213
- package/dest/archiver/config.d.ts +4 -20
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +16 -12
- package/dest/archiver/data_retrieval.d.ts +25 -20
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +147 -68
- package/dest/archiver/errors.d.ts +8 -0
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/errors.js +12 -0
- package/dest/archiver/index.d.ts +2 -3
- package/dest/archiver/index.d.ts.map +1 -1
- package/dest/archiver/index.js +1 -2
- package/dest/archiver/instrumentation.d.ts +9 -3
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/instrumentation.js +58 -17
- package/dest/archiver/kv_archiver_store/block_store.d.ts +47 -10
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +216 -63
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +12 -18
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +10 -7
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.js +30 -16
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +49 -34
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +88 -46
- package/dest/archiver/kv_archiver_store/log_store.d.ts +1 -1
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +18 -46
- package/dest/archiver/kv_archiver_store/message_store.d.ts +22 -16
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +150 -48
- package/dest/archiver/structs/inbox_message.d.ts +15 -0
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
- package/dest/archiver/structs/inbox_message.js +38 -0
- package/dest/archiver/structs/published.d.ts +1 -10
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/structs/published.js +1 -1
- package/dest/archiver/validation.d.ts +11 -0
- package/dest/archiver/validation.d.ts.map +1 -0
- package/dest/archiver/validation.js +90 -0
- package/dest/factory.d.ts +7 -12
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +18 -49
- package/dest/rpc/index.d.ts +1 -2
- package/dest/rpc/index.d.ts.map +1 -1
- package/dest/rpc/index.js +1 -4
- package/dest/test/mock_archiver.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts +4 -2
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +14 -1
- package/dest/test/mock_l2_block_source.d.ts +32 -5
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +118 -7
- package/dest/test/mock_structs.d.ts +9 -0
- package/dest/test/mock_structs.d.ts.map +1 -0
- package/dest/test/mock_structs.js +37 -0
- package/package.json +25 -27
- package/src/archiver/archiver.ts +858 -317
- package/src/archiver/archiver_store.ts +97 -55
- package/src/archiver/archiver_store_test_suite.ts +663 -210
- package/src/archiver/config.ts +23 -41
- package/src/archiver/data_retrieval.ts +215 -92
- package/src/archiver/errors.ts +21 -0
- package/src/archiver/index.ts +2 -3
- package/src/archiver/instrumentation.ts +75 -20
- package/src/archiver/kv_archiver_store/block_store.ts +270 -72
- package/src/archiver/kv_archiver_store/contract_class_store.ts +13 -23
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +35 -27
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +127 -63
- package/src/archiver/kv_archiver_store/log_store.ts +24 -62
- package/src/archiver/kv_archiver_store/message_store.ts +209 -53
- package/src/archiver/structs/inbox_message.ts +41 -0
- package/src/archiver/structs/published.ts +1 -11
- package/src/archiver/validation.ts +99 -0
- package/src/factory.ts +24 -66
- package/src/rpc/index.ts +1 -5
- package/src/test/mock_archiver.ts +1 -1
- package/src/test/mock_l1_to_l2_message_source.ts +14 -3
- package/src/test/mock_l2_block_source.ts +152 -8
- package/src/test/mock_structs.ts +49 -0
- 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/kv_archiver_store/nullifier_store.js +0 -73
- 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/l1_to_l2_message_store.js +0 -49
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -175
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +0 -636
- package/src/archiver/kv_archiver_store/nullifier_store.ts +0 -97
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +0 -801
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
INITIAL_L2_BLOCK_NUM,
|
|
3
|
-
|
|
4
|
-
MAX_NULLIFIERS_PER_TX,
|
|
3
|
+
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
5
4
|
PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
6
|
-
PUBLIC_LOG_DATA_SIZE_IN_FIELDS,
|
|
7
5
|
} from '@aztec/constants';
|
|
6
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
7
|
+
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
8
8
|
import { times, timesParallel } from '@aztec/foundation/collection';
|
|
9
9
|
import { randomInt } from '@aztec/foundation/crypto';
|
|
10
10
|
import { Fr } from '@aztec/foundation/fields';
|
|
11
|
+
import { toArray } from '@aztec/foundation/iterable';
|
|
12
|
+
import { sleep } from '@aztec/foundation/sleep';
|
|
11
13
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
12
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
CommitteeAttestation,
|
|
16
|
+
EthAddress,
|
|
17
|
+
L2Block,
|
|
18
|
+
L2BlockHash,
|
|
19
|
+
PublishedL2Block,
|
|
20
|
+
type ValidateBlockResult,
|
|
21
|
+
randomBlockInfo,
|
|
22
|
+
wrapInBlock,
|
|
23
|
+
} from '@aztec/stdlib/block';
|
|
13
24
|
import {
|
|
14
25
|
type ContractClassPublic,
|
|
15
26
|
type ContractInstanceWithAddress,
|
|
@@ -21,13 +32,16 @@ import { InboxLeaf } from '@aztec/stdlib/messaging';
|
|
|
21
32
|
import {
|
|
22
33
|
makeContractClassPublic,
|
|
23
34
|
makeExecutablePrivateFunctionWithMembershipProof,
|
|
24
|
-
|
|
35
|
+
makeUtilityFunctionWithMembershipProof,
|
|
25
36
|
} from '@aztec/stdlib/testing';
|
|
26
37
|
import '@aztec/stdlib/testing/jest';
|
|
27
|
-
import { TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
38
|
+
import { type IndexedTxEffect, TxEffect, TxHash } from '@aztec/stdlib/tx';
|
|
28
39
|
|
|
40
|
+
import { makeInboxMessage, makeInboxMessages } from '../test/mock_structs.js';
|
|
29
41
|
import type { ArchiverDataStore, ArchiverL1SynchPoint } from './archiver_store.js';
|
|
30
|
-
import
|
|
42
|
+
import { BlockNumberNotSequentialError, InitialBlockNumberNotSequentialError } from './errors.js';
|
|
43
|
+
import { MessageStoreError } from './kv_archiver_store/message_store.js';
|
|
44
|
+
import type { InboxMessage } from './structs/inbox_message.js';
|
|
31
45
|
|
|
32
46
|
/**
|
|
33
47
|
* @param testName - The name of the test suite.
|
|
@@ -39,8 +53,9 @@ export function describeArchiverDataStore(
|
|
|
39
53
|
) {
|
|
40
54
|
describe(testName, () => {
|
|
41
55
|
let store: ArchiverDataStore;
|
|
42
|
-
let blocks:
|
|
43
|
-
|
|
56
|
+
let blocks: PublishedL2Block[];
|
|
57
|
+
|
|
58
|
+
const blockTests: [number, number, () => PublishedL2Block[]][] = [
|
|
44
59
|
[1, 1, () => blocks.slice(0, 1)],
|
|
45
60
|
[10, 1, () => blocks.slice(9, 10)],
|
|
46
61
|
[1, 10, () => blocks.slice(0, 10)],
|
|
@@ -48,18 +63,33 @@ export function describeArchiverDataStore(
|
|
|
48
63
|
[5, 2, () => blocks.slice(4, 6)],
|
|
49
64
|
];
|
|
50
65
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
const makeBlockHash = (blockNumber: number) => `0x${blockNumber.toString(16).padStart(64, '0')}`;
|
|
67
|
+
|
|
68
|
+
const makePublished = (block: L2Block, l1BlockNumber: number): PublishedL2Block =>
|
|
69
|
+
PublishedL2Block.fromFields({
|
|
70
|
+
block: block,
|
|
71
|
+
l1: {
|
|
72
|
+
blockNumber: BigInt(l1BlockNumber),
|
|
73
|
+
blockHash: makeBlockHash(l1BlockNumber),
|
|
74
|
+
timestamp: BigInt(l1BlockNumber * 1000),
|
|
75
|
+
},
|
|
76
|
+
attestations: times(3, CommitteeAttestation.random),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const expectBlocksEqual = (actual: PublishedL2Block[], expected: PublishedL2Block[]) => {
|
|
80
|
+
expect(actual.length).toEqual(expected.length);
|
|
81
|
+
for (let i = 0; i < expected.length; i++) {
|
|
82
|
+
const expectedBlock = expected[i];
|
|
83
|
+
const actualBlock = actual[i];
|
|
84
|
+
expect(actualBlock.l1).toEqual(expectedBlock.l1);
|
|
85
|
+
expect(actualBlock.block.equals(expectedBlock.block)).toBe(true);
|
|
86
|
+
expect(actualBlock.attestations.every((a, i) => a.equals(expectedBlock.attestations[i]))).toBe(true);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
59
89
|
|
|
60
90
|
beforeEach(async () => {
|
|
61
91
|
store = await getStore();
|
|
62
|
-
blocks = await timesParallel(10, async i =>
|
|
92
|
+
blocks = await timesParallel(10, async i => makePublished(await L2Block.random(i + 1), i + 10));
|
|
63
93
|
});
|
|
64
94
|
|
|
65
95
|
describe('addBlocks', () => {
|
|
@@ -71,6 +101,18 @@ export function describeArchiverDataStore(
|
|
|
71
101
|
await store.addBlocks(blocks);
|
|
72
102
|
await expect(store.addBlocks(blocks)).resolves.toBe(true);
|
|
73
103
|
});
|
|
104
|
+
|
|
105
|
+
it('throws an error if the previous block does not exist in the store', async () => {
|
|
106
|
+
const block = makePublished(await L2Block.random(2), 2);
|
|
107
|
+
await expect(store.addBlocks([block])).rejects.toThrow(InitialBlockNumberNotSequentialError);
|
|
108
|
+
await expect(store.getPublishedBlocks(1, 10)).resolves.toEqual([]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('throws an error if there is a gap in the blocks being added', async () => {
|
|
112
|
+
const blocks = [makePublished(await L2Block.random(1), 1), makePublished(await L2Block.random(3), 3)];
|
|
113
|
+
await expect(store.addBlocks(blocks)).rejects.toThrow(BlockNumberNotSequentialError);
|
|
114
|
+
await expect(store.getPublishedBlocks(1, 10)).resolves.toEqual([]);
|
|
115
|
+
});
|
|
74
116
|
});
|
|
75
117
|
|
|
76
118
|
describe('unwindBlocks', () => {
|
|
@@ -78,28 +120,50 @@ export function describeArchiverDataStore(
|
|
|
78
120
|
await store.addBlocks(blocks);
|
|
79
121
|
const blockNumber = await store.getSynchedL2BlockNumber();
|
|
80
122
|
|
|
81
|
-
|
|
123
|
+
expectBlocksEqual(await store.getPublishedBlocks(blockNumber, 1), [blocks[blocks.length - 1]]);
|
|
82
124
|
|
|
83
125
|
await store.unwindBlocks(blockNumber, 1);
|
|
84
126
|
|
|
85
127
|
expect(await store.getSynchedL2BlockNumber()).toBe(blockNumber - 1);
|
|
86
|
-
expect(await store.
|
|
128
|
+
expect(await store.getPublishedBlocks(blockNumber, 1)).toEqual([]);
|
|
87
129
|
});
|
|
88
130
|
|
|
89
131
|
it('can unwind multiple empty blocks', async () => {
|
|
90
|
-
const emptyBlocks = await timesParallel(10, async i =>
|
|
132
|
+
const emptyBlocks = await timesParallel(10, async i => makePublished(await L2Block.random(i + 1, 0), i + 10));
|
|
91
133
|
await store.addBlocks(emptyBlocks);
|
|
92
134
|
expect(await store.getSynchedL2BlockNumber()).toBe(10);
|
|
93
135
|
|
|
94
136
|
await store.unwindBlocks(10, 3);
|
|
95
137
|
expect(await store.getSynchedL2BlockNumber()).toBe(7);
|
|
96
|
-
expect((await store.
|
|
138
|
+
expect((await store.getPublishedBlocks(1, 10)).map(b => b.block.number)).toEqual([1, 2, 3, 4, 5, 6, 7]);
|
|
97
139
|
});
|
|
98
140
|
|
|
99
141
|
it('refuses to unwind blocks if the tip is not the last block', async () => {
|
|
100
142
|
await store.addBlocks(blocks);
|
|
101
143
|
await expect(store.unwindBlocks(5, 1)).rejects.toThrow(/can only unwind blocks from the tip/i);
|
|
102
144
|
});
|
|
145
|
+
|
|
146
|
+
it('unwound blocks and headers cannot be retrieved by hash or archive', async () => {
|
|
147
|
+
await store.addBlocks(blocks);
|
|
148
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
149
|
+
const blockHash = await lastBlock.block.hash();
|
|
150
|
+
const archive = lastBlock.block.archive.root;
|
|
151
|
+
|
|
152
|
+
// Verify block and header exist before unwinding
|
|
153
|
+
expect(await store.getPublishedBlockByHash(blockHash)).toBeDefined();
|
|
154
|
+
expect(await store.getPublishedBlockByArchive(archive)).toBeDefined();
|
|
155
|
+
expect(await store.getBlockHeaderByHash(blockHash)).toBeDefined();
|
|
156
|
+
expect(await store.getBlockHeaderByArchive(archive)).toBeDefined();
|
|
157
|
+
|
|
158
|
+
// Unwind the block
|
|
159
|
+
await store.unwindBlocks(lastBlock.block.number, 1);
|
|
160
|
+
|
|
161
|
+
// Verify neither block nor header can be retrieved after unwinding
|
|
162
|
+
expect(await store.getPublishedBlockByHash(blockHash)).toBeUndefined();
|
|
163
|
+
expect(await store.getPublishedBlockByArchive(archive)).toBeUndefined();
|
|
164
|
+
expect(await store.getBlockHeaderByHash(blockHash)).toBeUndefined();
|
|
165
|
+
expect(await store.getBlockHeaderByArchive(archive)).toBeUndefined();
|
|
166
|
+
});
|
|
103
167
|
});
|
|
104
168
|
|
|
105
169
|
describe('getBlocks', () => {
|
|
@@ -108,19 +172,112 @@ export function describeArchiverDataStore(
|
|
|
108
172
|
});
|
|
109
173
|
|
|
110
174
|
it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks) => {
|
|
111
|
-
await
|
|
175
|
+
expectBlocksEqual(await store.getPublishedBlocks(start, limit), getExpectedBlocks());
|
|
112
176
|
});
|
|
113
177
|
|
|
114
178
|
it('returns an empty array if no blocks are found', async () => {
|
|
115
|
-
await expect(store.
|
|
179
|
+
await expect(store.getPublishedBlocks(12, 1)).resolves.toEqual([]);
|
|
116
180
|
});
|
|
117
181
|
|
|
118
182
|
it('throws an error if limit is invalid', async () => {
|
|
119
|
-
await expect(store.
|
|
183
|
+
await expect(store.getPublishedBlocks(1, 0)).rejects.toThrow('Invalid limit: 0');
|
|
120
184
|
});
|
|
121
185
|
|
|
122
186
|
it('throws an error if `from` it is out of range', async () => {
|
|
123
|
-
await expect(store.
|
|
187
|
+
await expect(store.getPublishedBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).rejects.toThrow('Invalid start: -99');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('throws an error if unexpected initial block number is found', async () => {
|
|
191
|
+
await store.addBlocks([makePublished(await L2Block.random(21), 31)], { force: true });
|
|
192
|
+
await expect(store.getPublishedBlocks(20, 1)).rejects.toThrow(`mismatch`);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('throws an error if a gap is found', async () => {
|
|
196
|
+
await store.addBlocks(
|
|
197
|
+
[makePublished(await L2Block.random(20), 30), makePublished(await L2Block.random(22), 32)],
|
|
198
|
+
{ force: true },
|
|
199
|
+
);
|
|
200
|
+
await expect(store.getPublishedBlocks(20, 2)).rejects.toThrow(`mismatch`);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe('getPublishedBlockByHash', () => {
|
|
205
|
+
beforeEach(async () => {
|
|
206
|
+
await store.addBlocks(blocks);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('retrieves a block by its hash', async () => {
|
|
210
|
+
const expectedBlock = blocks[5];
|
|
211
|
+
const blockHash = await expectedBlock.block.hash();
|
|
212
|
+
const retrievedBlock = await store.getPublishedBlockByHash(blockHash);
|
|
213
|
+
|
|
214
|
+
expect(retrievedBlock).toBeDefined();
|
|
215
|
+
expectBlocksEqual([retrievedBlock!], [expectedBlock]);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('returns undefined for non-existent block hash', async () => {
|
|
219
|
+
const nonExistentHash = Fr.random();
|
|
220
|
+
await expect(store.getPublishedBlockByHash(nonExistentHash)).resolves.toBeUndefined();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe('getPublishedBlockByArchive', () => {
|
|
225
|
+
beforeEach(async () => {
|
|
226
|
+
await store.addBlocks(blocks);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('retrieves a block by its archive root', async () => {
|
|
230
|
+
const expectedBlock = blocks[3];
|
|
231
|
+
const archive = expectedBlock.block.archive.root;
|
|
232
|
+
const retrievedBlock = await store.getPublishedBlockByArchive(archive);
|
|
233
|
+
|
|
234
|
+
expect(retrievedBlock).toBeDefined();
|
|
235
|
+
expectBlocksEqual([retrievedBlock!], [expectedBlock]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('returns undefined for non-existent archive root', async () => {
|
|
239
|
+
const nonExistentArchive = Fr.random();
|
|
240
|
+
await expect(store.getPublishedBlockByArchive(nonExistentArchive)).resolves.toBeUndefined();
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe('getBlockHeaderByHash', () => {
|
|
245
|
+
beforeEach(async () => {
|
|
246
|
+
await store.addBlocks(blocks);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('retrieves a block header by its hash', async () => {
|
|
250
|
+
const expectedBlock = blocks[7];
|
|
251
|
+
const blockHash = await expectedBlock.block.hash();
|
|
252
|
+
const retrievedHeader = await store.getBlockHeaderByHash(blockHash);
|
|
253
|
+
|
|
254
|
+
expect(retrievedHeader).toBeDefined();
|
|
255
|
+
expect(retrievedHeader!.equals(expectedBlock.block.getBlockHeader())).toBe(true);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('returns undefined for non-existent block hash', async () => {
|
|
259
|
+
const nonExistentHash = Fr.random();
|
|
260
|
+
await expect(store.getBlockHeaderByHash(nonExistentHash)).resolves.toBeUndefined();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe('getBlockHeaderByArchive', () => {
|
|
265
|
+
beforeEach(async () => {
|
|
266
|
+
await store.addBlocks(blocks);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('retrieves a block header by its archive root', async () => {
|
|
270
|
+
const expectedBlock = blocks[2];
|
|
271
|
+
const archive = expectedBlock.block.archive.root;
|
|
272
|
+
const retrievedHeader = await store.getBlockHeaderByArchive(archive);
|
|
273
|
+
|
|
274
|
+
expect(retrievedHeader).toBeDefined();
|
|
275
|
+
expect(retrievedHeader!.equals(expectedBlock.block.getBlockHeader())).toBe(true);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('returns undefined for non-existent archive root', async () => {
|
|
279
|
+
const nonExistentArchive = Fr.random();
|
|
280
|
+
await expect(store.getBlockHeaderByArchive(nonExistentArchive)).resolves.toBeUndefined();
|
|
124
281
|
});
|
|
125
282
|
});
|
|
126
283
|
|
|
@@ -131,7 +288,7 @@ export function describeArchiverDataStore(
|
|
|
131
288
|
|
|
132
289
|
it("returns the most recently added block's number", async () => {
|
|
133
290
|
await store.addBlocks(blocks);
|
|
134
|
-
await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.at(-1)!.
|
|
291
|
+
await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.at(-1)!.block.number);
|
|
135
292
|
});
|
|
136
293
|
});
|
|
137
294
|
|
|
@@ -152,27 +309,39 @@ export function describeArchiverDataStore(
|
|
|
152
309
|
});
|
|
153
310
|
|
|
154
311
|
it('returns the L1 block number that most recently added messages from inbox', async () => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
});
|
|
312
|
+
const l1BlockHash = Buffer32.random();
|
|
313
|
+
const l1BlockNumber = 10n;
|
|
314
|
+
await store.setMessageSynchedL1Block({ l1BlockNumber: 5n, l1BlockHash: Buffer32.random() });
|
|
315
|
+
await store.addL1ToL2Messages([makeInboxMessage(Buffer16.ZERO, { l1BlockNumber, l1BlockHash })]);
|
|
159
316
|
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
160
317
|
blocksSynchedTo: undefined,
|
|
161
|
-
messagesSynchedTo:
|
|
318
|
+
messagesSynchedTo: { l1BlockHash, l1BlockNumber },
|
|
319
|
+
} satisfies ArchiverL1SynchPoint);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('returns the latest syncpoint if latest message is behind', async () => {
|
|
323
|
+
const l1BlockHash = Buffer32.random();
|
|
324
|
+
const l1BlockNumber = 10n;
|
|
325
|
+
await store.setMessageSynchedL1Block({ l1BlockNumber, l1BlockHash });
|
|
326
|
+
const msg = makeInboxMessage(Buffer16.ZERO, { l1BlockNumber: 5n, l1BlockHash: Buffer32.random() });
|
|
327
|
+
await store.addL1ToL2Messages([msg]);
|
|
328
|
+
await expect(store.getSynchPoint()).resolves.toEqual({
|
|
329
|
+
blocksSynchedTo: undefined,
|
|
330
|
+
messagesSynchedTo: { l1BlockHash, l1BlockNumber },
|
|
162
331
|
} satisfies ArchiverL1SynchPoint);
|
|
163
332
|
});
|
|
164
333
|
});
|
|
165
334
|
|
|
166
335
|
describe('addLogs', () => {
|
|
167
336
|
it('adds private & public logs', async () => {
|
|
168
|
-
const block = blocks[0].
|
|
337
|
+
const block = blocks[0].block;
|
|
169
338
|
await expect(store.addLogs([block])).resolves.toEqual(true);
|
|
170
339
|
});
|
|
171
340
|
});
|
|
172
341
|
|
|
173
342
|
describe('deleteLogs', () => {
|
|
174
343
|
it('deletes private & public logs', async () => {
|
|
175
|
-
const block = blocks[0].
|
|
344
|
+
const block = blocks[0].block;
|
|
176
345
|
await store.addBlocks([blocks[0]]);
|
|
177
346
|
await expect(store.addLogs([block])).resolves.toEqual(true);
|
|
178
347
|
|
|
@@ -193,7 +362,7 @@ export function describeArchiverDataStore(
|
|
|
193
362
|
|
|
194
363
|
describe('getPrivateLogs', () => {
|
|
195
364
|
it('gets added private logs', async () => {
|
|
196
|
-
const block = blocks[0].
|
|
365
|
+
const block = blocks[0].block;
|
|
197
366
|
await store.addBlocks([blocks[0]]);
|
|
198
367
|
await store.addLogs([block]);
|
|
199
368
|
|
|
@@ -204,19 +373,25 @@ export function describeArchiverDataStore(
|
|
|
204
373
|
|
|
205
374
|
describe('getTxEffect', () => {
|
|
206
375
|
beforeEach(async () => {
|
|
207
|
-
await store.addLogs(blocks.map(b => b.
|
|
376
|
+
await store.addLogs(blocks.map(b => b.block));
|
|
208
377
|
await store.addBlocks(blocks);
|
|
209
378
|
});
|
|
210
379
|
|
|
211
380
|
it.each([
|
|
212
|
-
() =>
|
|
213
|
-
() =>
|
|
214
|
-
() =>
|
|
215
|
-
() =>
|
|
216
|
-
() =>
|
|
381
|
+
() => ({ data: blocks[0].block.body.txEffects[0], block: blocks[0].block, txIndexInBlock: 0 }),
|
|
382
|
+
() => ({ data: blocks[9].block.body.txEffects[3], block: blocks[9].block, txIndexInBlock: 3 }),
|
|
383
|
+
() => ({ data: blocks[3].block.body.txEffects[1], block: blocks[3].block, txIndexInBlock: 1 }),
|
|
384
|
+
() => ({ data: blocks[5].block.body.txEffects[2], block: blocks[5].block, txIndexInBlock: 2 }),
|
|
385
|
+
() => ({ data: blocks[1].block.body.txEffects[0], block: blocks[1].block, txIndexInBlock: 0 }),
|
|
217
386
|
])('retrieves a previously stored transaction', async getExpectedTx => {
|
|
218
|
-
const
|
|
219
|
-
const
|
|
387
|
+
const { data, block, txIndexInBlock } = getExpectedTx();
|
|
388
|
+
const expectedTx: IndexedTxEffect = {
|
|
389
|
+
data,
|
|
390
|
+
l2BlockNumber: block.number,
|
|
391
|
+
l2BlockHash: L2BlockHash.fromField(await block.hash()),
|
|
392
|
+
txIndexInBlock,
|
|
393
|
+
};
|
|
394
|
+
const actualTx = await store.getTxEffect(data.txHash);
|
|
220
395
|
expect(actualTx).toEqual(expectedTx);
|
|
221
396
|
});
|
|
222
397
|
|
|
@@ -225,11 +400,11 @@ export function describeArchiverDataStore(
|
|
|
225
400
|
});
|
|
226
401
|
|
|
227
402
|
it.each([
|
|
228
|
-
() => wrapInBlock(blocks[0].
|
|
229
|
-
() => wrapInBlock(blocks[9].
|
|
230
|
-
() => wrapInBlock(blocks[3].
|
|
231
|
-
() => wrapInBlock(blocks[5].
|
|
232
|
-
() => wrapInBlock(blocks[1].
|
|
403
|
+
() => wrapInBlock(blocks[0].block.body.txEffects[0], blocks[0].block),
|
|
404
|
+
() => wrapInBlock(blocks[9].block.body.txEffects[3], blocks[9].block),
|
|
405
|
+
() => wrapInBlock(blocks[3].block.body.txEffects[1], blocks[3].block),
|
|
406
|
+
() => wrapInBlock(blocks[5].block.body.txEffects[2], blocks[5].block),
|
|
407
|
+
() => wrapInBlock(blocks[1].block.body.txEffects[0], blocks[1].block),
|
|
233
408
|
])('tries to retrieves a previously stored transaction after deleted', async getExpectedTx => {
|
|
234
409
|
await store.unwindBlocks(blocks.length, blocks.length);
|
|
235
410
|
|
|
@@ -241,45 +416,219 @@ export function describeArchiverDataStore(
|
|
|
241
416
|
it('returns undefined if tx is not found', async () => {
|
|
242
417
|
await expect(store.getTxEffect(TxHash.random())).resolves.toBeUndefined();
|
|
243
418
|
});
|
|
419
|
+
|
|
420
|
+
it('does not fail if the block is unwound while requesting a tx', async () => {
|
|
421
|
+
const expectedTx = await wrapInBlock(blocks[1].block.body.txEffects[0], blocks[1].block);
|
|
422
|
+
let done = false;
|
|
423
|
+
void (async () => {
|
|
424
|
+
while (!done) {
|
|
425
|
+
void store.getTxEffect(expectedTx.data.txHash);
|
|
426
|
+
await sleep(1);
|
|
427
|
+
}
|
|
428
|
+
})();
|
|
429
|
+
await store.unwindBlocks(blocks.length, blocks.length);
|
|
430
|
+
done = true;
|
|
431
|
+
expect(await store.getTxEffect(expectedTx.data.txHash)).toEqual(undefined);
|
|
432
|
+
});
|
|
244
433
|
});
|
|
245
434
|
|
|
246
435
|
describe('L1 to L2 Messages', () => {
|
|
247
|
-
const
|
|
248
|
-
|
|
436
|
+
const initialL2BlockNumber = 13;
|
|
437
|
+
|
|
438
|
+
const checkMessages = async (msgs: InboxMessage[]) => {
|
|
439
|
+
expect(await store.getLastL1ToL2Message()).toEqual(msgs.at(-1));
|
|
440
|
+
expect(await toArray(store.iterateL1ToL2Messages())).toEqual(msgs);
|
|
441
|
+
expect(await store.getTotalL1ToL2MessageCount()).toEqual(BigInt(msgs.length));
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const makeInboxMessagesWithFullBlocks = (blockCount: number, opts: { initialL2BlockNumber?: number } = {}) =>
|
|
445
|
+
makeInboxMessages(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * blockCount, {
|
|
446
|
+
overrideFn: (msg, i) => {
|
|
447
|
+
const l2BlockNumber =
|
|
448
|
+
(opts.initialL2BlockNumber ?? initialL2BlockNumber) + Math.floor(i / NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
449
|
+
const index =
|
|
450
|
+
InboxLeaf.smallestIndexFromL2Block(l2BlockNumber) + BigInt(i % NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
451
|
+
return { ...msg, l2BlockNumber, index };
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('stores first message ever', async () => {
|
|
456
|
+
const msg = makeInboxMessage(Buffer16.ZERO, { index: 0n, l2BlockNumber: 1 });
|
|
457
|
+
await store.addL1ToL2Messages([msg]);
|
|
458
|
+
|
|
459
|
+
await checkMessages([msg]);
|
|
460
|
+
expect(await store.getL1ToL2Messages(1)).toEqual([msg.leaf]);
|
|
461
|
+
});
|
|
249
462
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
463
|
+
it('stores single message', async () => {
|
|
464
|
+
const msg = makeInboxMessage(Buffer16.ZERO, { l2BlockNumber: 2 });
|
|
465
|
+
await store.addL1ToL2Messages([msg]);
|
|
466
|
+
|
|
467
|
+
await checkMessages([msg]);
|
|
468
|
+
expect(await store.getL1ToL2Messages(2)).toEqual([msg.leaf]);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it('stores and returns messages across different blocks', async () => {
|
|
472
|
+
const msgs = makeInboxMessages(5, { initialL2BlockNumber });
|
|
473
|
+
await store.addL1ToL2Messages(msgs);
|
|
474
|
+
|
|
475
|
+
await checkMessages(msgs);
|
|
476
|
+
expect(await store.getL1ToL2Messages(initialL2BlockNumber + 2)).toEqual([msgs[2]].map(m => m.leaf));
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it('stores the same messages again', async () => {
|
|
480
|
+
const msgs = makeInboxMessages(5, { initialL2BlockNumber });
|
|
481
|
+
await store.addL1ToL2Messages(msgs);
|
|
482
|
+
await store.addL1ToL2Messages(msgs.slice(2));
|
|
483
|
+
|
|
484
|
+
await checkMessages(msgs);
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it('stores and returns messages across different blocks with gaps', async () => {
|
|
488
|
+
const msgs1 = makeInboxMessages(3, { initialL2BlockNumber: 1 });
|
|
489
|
+
const msgs2 = makeInboxMessages(3, { initialL2BlockNumber: 20, initialHash: msgs1.at(-1)!.rollingHash });
|
|
490
|
+
|
|
491
|
+
await store.addL1ToL2Messages(msgs1);
|
|
492
|
+
await store.addL1ToL2Messages(msgs2);
|
|
493
|
+
|
|
494
|
+
await checkMessages([...msgs1, ...msgs2]);
|
|
495
|
+
|
|
496
|
+
expect(await store.getL1ToL2Messages(1)).toEqual([msgs1[0].leaf]);
|
|
497
|
+
expect(await store.getL1ToL2Messages(4)).toEqual([]);
|
|
498
|
+
expect(await store.getL1ToL2Messages(20)).toEqual([msgs2[0].leaf]);
|
|
499
|
+
expect(await store.getL1ToL2Messages(24)).toEqual([]);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it('stores and returns messages with block numbers larger than a byte', async () => {
|
|
503
|
+
const msgs = makeInboxMessages(5, { initialL2BlockNumber: 1000 });
|
|
504
|
+
await store.addL1ToL2Messages(msgs);
|
|
505
|
+
|
|
506
|
+
await checkMessages(msgs);
|
|
507
|
+
expect(await store.getL1ToL2Messages(1002)).toEqual([msgs[2]].map(m => m.leaf));
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('stores and returns multiple messages per block', async () => {
|
|
511
|
+
const msgs = makeInboxMessagesWithFullBlocks(4);
|
|
512
|
+
await store.addL1ToL2Messages(msgs);
|
|
513
|
+
|
|
514
|
+
await checkMessages(msgs);
|
|
515
|
+
const blockMessages = await store.getL1ToL2Messages(initialL2BlockNumber + 1);
|
|
516
|
+
expect(blockMessages).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
517
|
+
expect(blockMessages).toEqual(
|
|
518
|
+
msgs.slice(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2).map(m => m.leaf),
|
|
254
519
|
);
|
|
520
|
+
});
|
|
255
521
|
|
|
256
|
-
it('
|
|
257
|
-
const msgs =
|
|
258
|
-
|
|
259
|
-
await store.addL1ToL2Messages(
|
|
260
|
-
const retrievedMessages = await store.getL1ToL2Messages(l2BlockNumber);
|
|
522
|
+
it('stores messages in multiple operations', async () => {
|
|
523
|
+
const msgs = makeInboxMessages(20, { initialL2BlockNumber });
|
|
524
|
+
await store.addL1ToL2Messages(msgs.slice(0, 10));
|
|
525
|
+
await store.addL1ToL2Messages(msgs.slice(10, 20));
|
|
261
526
|
|
|
262
|
-
|
|
263
|
-
expect(
|
|
527
|
+
expect(await store.getL1ToL2Messages(initialL2BlockNumber + 2)).toEqual([msgs[2]].map(m => m.leaf));
|
|
528
|
+
expect(await store.getL1ToL2Messages(initialL2BlockNumber + 12)).toEqual([msgs[12]].map(m => m.leaf));
|
|
529
|
+
await checkMessages(msgs);
|
|
264
530
|
});
|
|
265
531
|
|
|
266
|
-
it('
|
|
267
|
-
const msgs =
|
|
268
|
-
|
|
269
|
-
// --> with that there will be a gap and it will be impossible to sequence the
|
|
270
|
-
// end of tree = start of next tree/block - 1
|
|
271
|
-
msgs[4] = new InboxLeaf(InboxLeaf.smallestIndexFromL2Block(l2BlockNumber + 1n) - 1n, Fr.random());
|
|
532
|
+
it('iterates over messages from start index', async () => {
|
|
533
|
+
const msgs = makeInboxMessages(10, { initialL2BlockNumber });
|
|
534
|
+
await store.addL1ToL2Messages(msgs);
|
|
272
535
|
|
|
273
|
-
await store.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
536
|
+
const iterated = await toArray(store.iterateL1ToL2Messages({ start: msgs[3].index }));
|
|
537
|
+
expect(iterated).toEqual(msgs.slice(3));
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it('iterates over messages in reverse', async () => {
|
|
541
|
+
const msgs = makeInboxMessages(10, { initialL2BlockNumber });
|
|
542
|
+
await store.addL1ToL2Messages(msgs);
|
|
543
|
+
|
|
544
|
+
const iterated = await toArray(store.iterateL1ToL2Messages({ reverse: true, end: msgs[3].index }));
|
|
545
|
+
expect(iterated).toEqual(msgs.slice(0, 4).reverse());
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it('throws if messages are added out of order', async () => {
|
|
549
|
+
const msgs = makeInboxMessages(5, { overrideFn: (msg, i) => ({ ...msg, index: BigInt(10 - i) }) });
|
|
550
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it('throws if block number for the first message is out of order', async () => {
|
|
554
|
+
const msgs = makeInboxMessages(4, { initialL2BlockNumber });
|
|
555
|
+
msgs[2].l2BlockNumber = initialL2BlockNumber - 1;
|
|
556
|
+
await store.addL1ToL2Messages(msgs.slice(0, 2));
|
|
557
|
+
await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it('throws if rolling hash is not correct', async () => {
|
|
561
|
+
const msgs = makeInboxMessages(5);
|
|
562
|
+
msgs[1].rollingHash = Buffer16.random();
|
|
563
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it('throws if rolling hash for first message is not correct', async () => {
|
|
567
|
+
const msgs = makeInboxMessages(4);
|
|
568
|
+
msgs[2].rollingHash = Buffer16.random();
|
|
569
|
+
await store.addL1ToL2Messages(msgs.slice(0, 2));
|
|
570
|
+
await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it('throws if index is not in the correct range', async () => {
|
|
574
|
+
const msgs = makeInboxMessages(5, { initialL2BlockNumber });
|
|
575
|
+
msgs.at(-1)!.index += 100n;
|
|
576
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
it('throws if first index in block has gaps', async () => {
|
|
580
|
+
const msgs = makeInboxMessages(4, { initialL2BlockNumber });
|
|
581
|
+
msgs[2].index++;
|
|
582
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it('throws if index does not follow previous one', async () => {
|
|
586
|
+
const msgs = makeInboxMessages(2, {
|
|
587
|
+
initialL2BlockNumber,
|
|
588
|
+
overrideFn: (msg, i) => ({
|
|
589
|
+
...msg,
|
|
590
|
+
l2BlockNumber: 2,
|
|
591
|
+
index: BigInt(i + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2),
|
|
592
|
+
}),
|
|
593
|
+
});
|
|
594
|
+
msgs[1].index++;
|
|
595
|
+
await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it('removes messages up to the given block number', async () => {
|
|
599
|
+
const msgs = makeInboxMessagesWithFullBlocks(4, { initialL2BlockNumber: 1 });
|
|
600
|
+
|
|
601
|
+
await store.addL1ToL2Messages(msgs);
|
|
602
|
+
await checkMessages(msgs);
|
|
603
|
+
|
|
604
|
+
expect(await store.getL1ToL2Messages(1)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
605
|
+
expect(await store.getL1ToL2Messages(2)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
606
|
+
expect(await store.getL1ToL2Messages(3)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
607
|
+
expect(await store.getL1ToL2Messages(4)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
608
|
+
|
|
609
|
+
await store.rollbackL1ToL2MessagesToL2Block(2);
|
|
610
|
+
|
|
611
|
+
expect(await store.getL1ToL2Messages(1)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
612
|
+
expect(await store.getL1ToL2Messages(2)).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
613
|
+
expect(await store.getL1ToL2Messages(3)).toHaveLength(0);
|
|
614
|
+
expect(await store.getL1ToL2Messages(4)).toHaveLength(0);
|
|
615
|
+
|
|
616
|
+
await checkMessages(msgs.slice(0, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2));
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
it('removes messages starting with the given index', async () => {
|
|
620
|
+
const msgs = makeInboxMessagesWithFullBlocks(4, { initialL2BlockNumber: 1 });
|
|
621
|
+
await store.addL1ToL2Messages(msgs);
|
|
622
|
+
|
|
623
|
+
await store.removeL1ToL2Messages(msgs[13].index);
|
|
624
|
+
await checkMessages(msgs.slice(0, 13));
|
|
277
625
|
});
|
|
278
626
|
});
|
|
279
627
|
|
|
280
628
|
describe('contractInstances', () => {
|
|
281
629
|
let contractInstance: ContractInstanceWithAddress;
|
|
282
630
|
const blockNum = 10;
|
|
631
|
+
const timestamp = 3600n;
|
|
283
632
|
|
|
284
633
|
beforeEach(async () => {
|
|
285
634
|
const classId = Fr.random();
|
|
@@ -292,16 +641,111 @@ export function describeArchiverDataStore(
|
|
|
292
641
|
});
|
|
293
642
|
|
|
294
643
|
it('returns previously stored contract instances', async () => {
|
|
295
|
-
await expect(store.getContractInstance(contractInstance.address)).resolves.toMatchObject(
|
|
644
|
+
await expect(store.getContractInstance(contractInstance.address, timestamp)).resolves.toMatchObject(
|
|
645
|
+
contractInstance,
|
|
646
|
+
);
|
|
296
647
|
});
|
|
297
648
|
|
|
298
649
|
it('returns undefined if contract instance is not found', async () => {
|
|
299
|
-
await expect(store.getContractInstance(await AztecAddress.random())).resolves.toBeUndefined();
|
|
650
|
+
await expect(store.getContractInstance(await AztecAddress.random(), timestamp)).resolves.toBeUndefined();
|
|
300
651
|
});
|
|
301
652
|
|
|
302
653
|
it('returns undefined if previously stored contract instances was deleted', async () => {
|
|
303
654
|
await store.deleteContractInstances([contractInstance], blockNum);
|
|
304
|
-
await expect(store.getContractInstance(contractInstance.address)).resolves.toBeUndefined();
|
|
655
|
+
await expect(store.getContractInstance(contractInstance.address, timestamp)).resolves.toBeUndefined();
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
describe('contractInstanceUpdates', () => {
|
|
660
|
+
let contractInstance: ContractInstanceWithAddress;
|
|
661
|
+
let classId: Fr;
|
|
662
|
+
let nextClassId: Fr;
|
|
663
|
+
const timestampOfChange = 3600n;
|
|
664
|
+
|
|
665
|
+
beforeEach(async () => {
|
|
666
|
+
classId = Fr.random();
|
|
667
|
+
nextClassId = Fr.random();
|
|
668
|
+
const randomInstance = await SerializableContractInstance.random({
|
|
669
|
+
currentContractClassId: classId,
|
|
670
|
+
originalContractClassId: classId,
|
|
671
|
+
});
|
|
672
|
+
contractInstance = { ...randomInstance, address: await AztecAddress.random() };
|
|
673
|
+
await store.addContractInstances([contractInstance], 1);
|
|
674
|
+
await store.addContractInstanceUpdates(
|
|
675
|
+
[
|
|
676
|
+
{
|
|
677
|
+
prevContractClassId: classId,
|
|
678
|
+
newContractClassId: nextClassId,
|
|
679
|
+
timestampOfChange,
|
|
680
|
+
address: contractInstance.address,
|
|
681
|
+
},
|
|
682
|
+
],
|
|
683
|
+
timestampOfChange - 1n,
|
|
684
|
+
);
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('gets the correct current class id for a contract not updated yet', async () => {
|
|
688
|
+
const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange - 1n);
|
|
689
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(classId);
|
|
690
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(classId);
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
it('gets the correct current class id for a contract that has just been updated', async () => {
|
|
694
|
+
const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange);
|
|
695
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(classId);
|
|
696
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
it('gets the correct current class id for a contract that was updated in the past', async () => {
|
|
700
|
+
const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange + 1n);
|
|
701
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(classId);
|
|
702
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it('ignores updates for the wrong contract', async () => {
|
|
706
|
+
const otherClassId = Fr.random();
|
|
707
|
+
const randomInstance = await SerializableContractInstance.random({
|
|
708
|
+
currentContractClassId: otherClassId,
|
|
709
|
+
originalContractClassId: otherClassId,
|
|
710
|
+
});
|
|
711
|
+
const otherContractInstance = {
|
|
712
|
+
...randomInstance,
|
|
713
|
+
address: await AztecAddress.random(),
|
|
714
|
+
};
|
|
715
|
+
await store.addContractInstances([otherContractInstance], 1);
|
|
716
|
+
|
|
717
|
+
const fetchedInstance = await store.getContractInstance(otherContractInstance.address, timestampOfChange + 1n);
|
|
718
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(otherClassId);
|
|
719
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(otherClassId);
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
it('bounds its search to the right contract if more than than one update exists', async () => {
|
|
723
|
+
const otherClassId = Fr.random();
|
|
724
|
+
const otherNextClassId = Fr.random();
|
|
725
|
+
const randomInstance = await SerializableContractInstance.random({
|
|
726
|
+
currentContractClassId: otherClassId,
|
|
727
|
+
originalContractClassId: otherNextClassId,
|
|
728
|
+
});
|
|
729
|
+
const otherContractInstance = {
|
|
730
|
+
...randomInstance,
|
|
731
|
+
address: await AztecAddress.random(),
|
|
732
|
+
};
|
|
733
|
+
await store.addContractInstances([otherContractInstance], 1);
|
|
734
|
+
await store.addContractInstanceUpdates(
|
|
735
|
+
[
|
|
736
|
+
{
|
|
737
|
+
prevContractClassId: otherClassId,
|
|
738
|
+
newContractClassId: otherNextClassId,
|
|
739
|
+
timestampOfChange,
|
|
740
|
+
address: otherContractInstance.address,
|
|
741
|
+
},
|
|
742
|
+
],
|
|
743
|
+
timestampOfChange - 1n,
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange + 1n);
|
|
747
|
+
expect(fetchedInstance?.originalContractClassId).toEqual(classId);
|
|
748
|
+
expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
|
|
305
749
|
});
|
|
306
750
|
});
|
|
307
751
|
|
|
@@ -356,19 +800,19 @@ export function describeArchiverDataStore(
|
|
|
356
800
|
expect(stored?.privateFunctions).toEqual(fns);
|
|
357
801
|
});
|
|
358
802
|
|
|
359
|
-
it('adds new
|
|
360
|
-
const fns = times(3,
|
|
803
|
+
it('adds new utility functions', async () => {
|
|
804
|
+
const fns = times(3, makeUtilityFunctionWithMembershipProof);
|
|
361
805
|
await store.addFunctions(contractClass.id, [], fns);
|
|
362
806
|
const stored = await store.getContractClass(contractClass.id);
|
|
363
|
-
expect(stored?.
|
|
807
|
+
expect(stored?.utilityFunctions).toEqual(fns);
|
|
364
808
|
});
|
|
365
809
|
|
|
366
|
-
it('does not duplicate
|
|
367
|
-
const fns = times(3,
|
|
810
|
+
it('does not duplicate utility functions', async () => {
|
|
811
|
+
const fns = times(3, makeUtilityFunctionWithMembershipProof);
|
|
368
812
|
await store.addFunctions(contractClass.id, [], fns.slice(0, 1));
|
|
369
813
|
await store.addFunctions(contractClass.id, [], fns);
|
|
370
814
|
const stored = await store.getContractClass(contractClass.id);
|
|
371
|
-
expect(stored?.
|
|
815
|
+
expect(stored?.utilityFunctions).toEqual(fns);
|
|
372
816
|
});
|
|
373
817
|
});
|
|
374
818
|
|
|
@@ -378,32 +822,25 @@ export function describeArchiverDataStore(
|
|
|
378
822
|
const numPrivateLogsPerTx = 3;
|
|
379
823
|
const numPublicLogsPerTx = 2;
|
|
380
824
|
|
|
381
|
-
let blocks:
|
|
825
|
+
let blocks: PublishedL2Block[];
|
|
382
826
|
|
|
383
827
|
const makeTag = (blockNumber: number, txIndex: number, logIndex: number, isPublic = false) =>
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
// 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.
|
|
388
|
-
const makeLengthsField = (publicValuesLen: number, privateValuesLen: number) => {
|
|
389
|
-
const buf = Buffer.alloc(32);
|
|
390
|
-
buf.writeUint16BE(publicValuesLen, 27);
|
|
391
|
-
buf.writeUint16BE(privateValuesLen, 30);
|
|
392
|
-
return Fr.fromBuffer(buf);
|
|
393
|
-
};
|
|
828
|
+
blockNumber === 1 && txIndex === 0 && logIndex === 0
|
|
829
|
+
? Fr.ZERO // Shared tag
|
|
830
|
+
: new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1));
|
|
394
831
|
|
|
395
832
|
const makePrivateLog = (tag: Fr) =>
|
|
396
|
-
PrivateLog.
|
|
833
|
+
PrivateLog.from({
|
|
834
|
+
fields: makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, i => (!i ? tag : new Fr(tag.toNumber() + i))),
|
|
835
|
+
emittedLength: PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
836
|
+
});
|
|
397
837
|
|
|
398
|
-
// The tag lives in field 1, not 0, of a public log
|
|
399
|
-
// See extractTaggedLogsFromPublic and noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr -> emit_log
|
|
400
838
|
const makePublicLog = (tag: Fr) =>
|
|
401
|
-
PublicLog.
|
|
402
|
-
AztecAddress.fromNumber(1)
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
]);
|
|
839
|
+
PublicLog.from({
|
|
840
|
+
contractAddress: AztecAddress.fromNumber(1),
|
|
841
|
+
// Arbitrary length
|
|
842
|
+
fields: new Array(10).fill(null).map((_, i) => (!i ? tag : new Fr(tag.toNumber() + i))),
|
|
843
|
+
});
|
|
407
844
|
|
|
408
845
|
const mockPrivateLogs = (blockNumber: number, txIndex: number) => {
|
|
409
846
|
return times(numPrivateLogsPerTx, (logIndex: number) => {
|
|
@@ -419,9 +856,9 @@ export function describeArchiverDataStore(
|
|
|
419
856
|
});
|
|
420
857
|
};
|
|
421
858
|
|
|
422
|
-
const mockBlockWithLogs = async (blockNumber: number): Promise<
|
|
859
|
+
const mockBlockWithLogs = async (blockNumber: number): Promise<PublishedL2Block> => {
|
|
423
860
|
const block = await L2Block.random(blockNumber);
|
|
424
|
-
block.header.globalVariables.blockNumber =
|
|
861
|
+
block.header.globalVariables.blockNumber = blockNumber;
|
|
425
862
|
|
|
426
863
|
block.body.txEffects = await timesParallel(numTxsPerBlock, async (txIndex: number) => {
|
|
427
864
|
const txEffect = await TxEffect.random();
|
|
@@ -430,36 +867,41 @@ export function describeArchiverDataStore(
|
|
|
430
867
|
return txEffect;
|
|
431
868
|
});
|
|
432
869
|
|
|
433
|
-
return {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
870
|
+
return PublishedL2Block.fromFields({
|
|
871
|
+
block: block,
|
|
872
|
+
attestations: times(3, CommitteeAttestation.random),
|
|
873
|
+
l1: {
|
|
874
|
+
blockNumber: BigInt(blockNumber),
|
|
875
|
+
blockHash: makeBlockHash(blockNumber),
|
|
876
|
+
timestamp: BigInt(blockNumber),
|
|
877
|
+
},
|
|
878
|
+
});
|
|
437
879
|
};
|
|
438
880
|
|
|
439
881
|
beforeEach(async () => {
|
|
440
|
-
blocks = await timesParallel(numBlocks, (index: number) => mockBlockWithLogs(index));
|
|
882
|
+
blocks = await timesParallel(numBlocks, (index: number) => mockBlockWithLogs(index + 1));
|
|
441
883
|
|
|
442
884
|
await store.addBlocks(blocks);
|
|
443
|
-
await store.addLogs(blocks.map(b => b.
|
|
885
|
+
await store.addLogs(blocks.map(b => b.block));
|
|
444
886
|
});
|
|
445
887
|
|
|
446
888
|
it('is possible to batch request private logs via tags', async () => {
|
|
447
|
-
const tags = [makeTag(
|
|
889
|
+
const tags = [makeTag(2, 1, 2), makeTag(1, 2, 0)];
|
|
448
890
|
|
|
449
891
|
const logsByTags = await store.getLogsByTags(tags);
|
|
450
892
|
|
|
451
893
|
expect(logsByTags).toEqual([
|
|
452
894
|
[
|
|
453
895
|
expect.objectContaining({
|
|
454
|
-
blockNumber:
|
|
455
|
-
|
|
896
|
+
blockNumber: 2,
|
|
897
|
+
log: makePrivateLog(tags[0]),
|
|
456
898
|
isFromPublic: false,
|
|
457
899
|
}),
|
|
458
900
|
],
|
|
459
901
|
[
|
|
460
902
|
expect.objectContaining({
|
|
461
|
-
blockNumber:
|
|
462
|
-
|
|
903
|
+
blockNumber: 1,
|
|
904
|
+
log: makePrivateLog(tags[1]),
|
|
463
905
|
isFromPublic: false,
|
|
464
906
|
}),
|
|
465
907
|
],
|
|
@@ -467,21 +909,21 @@ export function describeArchiverDataStore(
|
|
|
467
909
|
});
|
|
468
910
|
|
|
469
911
|
it('is possible to batch request all logs (private and public) via tags', async () => {
|
|
470
|
-
// Tag(
|
|
471
|
-
const tags = [makeTag(
|
|
912
|
+
// Tag(1, 0, 0) is shared with the first private log and the first public log.
|
|
913
|
+
const tags = [makeTag(1, 0, 0)];
|
|
472
914
|
|
|
473
915
|
const logsByTags = await store.getLogsByTags(tags);
|
|
474
916
|
|
|
475
917
|
expect(logsByTags).toEqual([
|
|
476
918
|
[
|
|
477
919
|
expect.objectContaining({
|
|
478
|
-
blockNumber:
|
|
479
|
-
|
|
920
|
+
blockNumber: 1,
|
|
921
|
+
log: makePrivateLog(tags[0]),
|
|
480
922
|
isFromPublic: false,
|
|
481
923
|
}),
|
|
482
924
|
expect.objectContaining({
|
|
483
|
-
blockNumber:
|
|
484
|
-
|
|
925
|
+
blockNumber: 1,
|
|
926
|
+
log: makePublicLog(tags[0]),
|
|
485
927
|
isFromPublic: true,
|
|
486
928
|
}),
|
|
487
929
|
],
|
|
@@ -494,11 +936,11 @@ export function describeArchiverDataStore(
|
|
|
494
936
|
// Create a block containing logs that have the same tag as the blocks before.
|
|
495
937
|
const newBlockNumber = numBlocks;
|
|
496
938
|
const newBlock = await mockBlockWithLogs(newBlockNumber);
|
|
497
|
-
const newLog = newBlock.
|
|
939
|
+
const newLog = newBlock.block.body.txEffects[1].privateLogs[1];
|
|
498
940
|
newLog.fields[0] = tags[0];
|
|
499
|
-
newBlock.
|
|
941
|
+
newBlock.block.body.txEffects[1].privateLogs[1] = newLog;
|
|
500
942
|
await store.addBlocks([newBlock]);
|
|
501
|
-
await store.addLogs([newBlock.
|
|
943
|
+
await store.addLogs([newBlock.block]);
|
|
502
944
|
|
|
503
945
|
const logsByTags = await store.getLogsByTags(tags);
|
|
504
946
|
|
|
@@ -506,12 +948,12 @@ export function describeArchiverDataStore(
|
|
|
506
948
|
[
|
|
507
949
|
expect.objectContaining({
|
|
508
950
|
blockNumber: 1,
|
|
509
|
-
|
|
951
|
+
log: makePrivateLog(tags[0]),
|
|
510
952
|
isFromPublic: false,
|
|
511
953
|
}),
|
|
512
954
|
expect.objectContaining({
|
|
513
955
|
blockNumber: newBlockNumber,
|
|
514
|
-
|
|
956
|
+
log: newLog,
|
|
515
957
|
isFromPublic: false,
|
|
516
958
|
}),
|
|
517
959
|
],
|
|
@@ -530,42 +972,12 @@ export function describeArchiverDataStore(
|
|
|
530
972
|
[
|
|
531
973
|
expect.objectContaining({
|
|
532
974
|
blockNumber: 1,
|
|
533
|
-
|
|
975
|
+
log: makePrivateLog(tags[1]),
|
|
534
976
|
isFromPublic: false,
|
|
535
977
|
}),
|
|
536
978
|
],
|
|
537
979
|
]);
|
|
538
980
|
});
|
|
539
|
-
|
|
540
|
-
it('is not possible to add public logs by tag if they are invalid', async () => {
|
|
541
|
-
const tag = makeTag(99, 88, 77);
|
|
542
|
-
const invalidLogs = [
|
|
543
|
-
PublicLog.fromFields([
|
|
544
|
-
AztecAddress.fromNumber(1).toField(),
|
|
545
|
-
makeLengthsField(2, 3), // This field claims we have 5 items, but we actually have more
|
|
546
|
-
tag,
|
|
547
|
-
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i)),
|
|
548
|
-
]),
|
|
549
|
-
PublicLog.fromFields([
|
|
550
|
-
AztecAddress.fromNumber(1).toField(),
|
|
551
|
-
makeLengthsField(2, PUBLIC_LOG_DATA_SIZE_IN_FIELDS), // This field claims we have more than the max items
|
|
552
|
-
tag,
|
|
553
|
-
...times(PUBLIC_LOG_DATA_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i)),
|
|
554
|
-
]),
|
|
555
|
-
];
|
|
556
|
-
|
|
557
|
-
// Create a block containing these invalid logs
|
|
558
|
-
const newBlockNumber = numBlocks;
|
|
559
|
-
const newBlock = await mockBlockWithLogs(newBlockNumber);
|
|
560
|
-
newBlock.data.body.txEffects[0].publicLogs = invalidLogs;
|
|
561
|
-
await store.addBlocks([newBlock]);
|
|
562
|
-
await store.addLogs([newBlock.data]);
|
|
563
|
-
|
|
564
|
-
const logsByTags = await store.getLogsByTags([tag]);
|
|
565
|
-
|
|
566
|
-
// Neither of the logs should have been added:
|
|
567
|
-
expect(logsByTags).toEqual([[]]);
|
|
568
|
-
});
|
|
569
981
|
});
|
|
570
982
|
|
|
571
983
|
describe('getPublicLogs', () => {
|
|
@@ -573,27 +985,30 @@ export function describeArchiverDataStore(
|
|
|
573
985
|
const numPublicFunctionCalls = 3;
|
|
574
986
|
const numPublicLogs = 2;
|
|
575
987
|
const numBlocks = 10;
|
|
576
|
-
let blocks:
|
|
988
|
+
let blocks: PublishedL2Block[];
|
|
577
989
|
|
|
578
990
|
beforeEach(async () => {
|
|
579
|
-
blocks = await timesParallel(numBlocks, async (index: number) =>
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
991
|
+
blocks = await timesParallel(numBlocks, async (index: number) =>
|
|
992
|
+
PublishedL2Block.fromFields({
|
|
993
|
+
block: await L2Block.random(index + 1, txsPerBlock, numPublicFunctionCalls, numPublicLogs),
|
|
994
|
+
l1: { blockNumber: BigInt(index), blockHash: makeBlockHash(index), timestamp: BigInt(index) },
|
|
995
|
+
attestations: times(3, CommitteeAttestation.random),
|
|
996
|
+
}),
|
|
997
|
+
);
|
|
583
998
|
|
|
584
999
|
await store.addBlocks(blocks);
|
|
585
|
-
await store.addLogs(blocks.map(b => b.
|
|
1000
|
+
await store.addLogs(blocks.map(b => b.block));
|
|
586
1001
|
});
|
|
587
1002
|
|
|
588
1003
|
it('no logs returned if deleted ("txHash" filter param is respected variant)', async () => {
|
|
589
1004
|
// get random tx
|
|
590
1005
|
const targetBlockIndex = randomInt(numBlocks);
|
|
591
1006
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
592
|
-
const targetTxHash = blocks[targetBlockIndex].
|
|
1007
|
+
const targetTxHash = blocks[targetBlockIndex].block.body.txEffects[targetTxIndex].txHash;
|
|
593
1008
|
|
|
594
1009
|
await Promise.all([
|
|
595
1010
|
store.unwindBlocks(blocks.length, blocks.length),
|
|
596
|
-
store.deleteLogs(blocks.map(b => b.
|
|
1011
|
+
store.deleteLogs(blocks.map(b => b.block)),
|
|
597
1012
|
]);
|
|
598
1013
|
|
|
599
1014
|
const response = await store.getPublicLogs({ txHash: targetTxHash });
|
|
@@ -607,7 +1022,7 @@ export function describeArchiverDataStore(
|
|
|
607
1022
|
// get random tx
|
|
608
1023
|
const targetBlockIndex = randomInt(numBlocks);
|
|
609
1024
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
610
|
-
const targetTxHash = blocks[targetBlockIndex].
|
|
1025
|
+
const targetTxHash = blocks[targetBlockIndex].block.body.txEffects[targetTxIndex].txHash;
|
|
611
1026
|
|
|
612
1027
|
const response = await store.getPublicLogs({ txHash: targetTxHash });
|
|
613
1028
|
const logs = response.logs;
|
|
@@ -650,7 +1065,7 @@ export function describeArchiverDataStore(
|
|
|
650
1065
|
const targetTxIndex = randomInt(txsPerBlock);
|
|
651
1066
|
const targetLogIndex = randomInt(numPublicLogs * numPublicFunctionCalls);
|
|
652
1067
|
const targetContractAddress =
|
|
653
|
-
blocks[targetBlockIndex].
|
|
1068
|
+
blocks[targetBlockIndex].block.body.txEffects[targetTxIndex].publicLogs[targetLogIndex].contractAddress;
|
|
654
1069
|
|
|
655
1070
|
const response = await store.getPublicLogs({ contractAddress: targetContractAddress });
|
|
656
1071
|
|
|
@@ -754,56 +1169,94 @@ export function describeArchiverDataStore(
|
|
|
754
1169
|
});
|
|
755
1170
|
});
|
|
756
1171
|
|
|
757
|
-
describe('
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
1172
|
+
describe('pendingChainValidationStatus', () => {
|
|
1173
|
+
it('should return undefined when no status is set', async () => {
|
|
1174
|
+
const status = await store.getPendingChainValidationStatus();
|
|
1175
|
+
expect(status).toBeUndefined();
|
|
1176
|
+
});
|
|
761
1177
|
|
|
762
|
-
|
|
763
|
-
|
|
1178
|
+
it('should store and retrieve a valid validation status', async () => {
|
|
1179
|
+
const validStatus: ValidateBlockResult = { valid: true };
|
|
764
1180
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
);
|
|
770
|
-
});
|
|
1181
|
+
await store.setPendingChainValidationStatus(validStatus);
|
|
1182
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1183
|
+
|
|
1184
|
+
expect(retrievedStatus).toEqual(validStatus);
|
|
771
1185
|
});
|
|
772
1186
|
|
|
773
|
-
it('
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1187
|
+
it('should store and retrieve an invalid validation status with insufficient attestations', async () => {
|
|
1188
|
+
const invalidStatus: ValidateBlockResult = {
|
|
1189
|
+
valid: false,
|
|
1190
|
+
block: randomBlockInfo(1),
|
|
1191
|
+
committee: [EthAddress.random(), EthAddress.random()],
|
|
1192
|
+
epoch: 123n,
|
|
1193
|
+
seed: 456n,
|
|
1194
|
+
attestors: [EthAddress.random()],
|
|
1195
|
+
attestations: [CommitteeAttestation.random()],
|
|
1196
|
+
reason: 'insufficient-attestations',
|
|
1197
|
+
};
|
|
777
1198
|
|
|
778
|
-
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1199
|
+
await store.setPendingChainValidationStatus(invalidStatus);
|
|
1200
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1201
|
+
|
|
1202
|
+
expect(retrievedStatus).toEqual(invalidStatus);
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
it('should store and retrieve an invalid validation status with invalid attestation', async () => {
|
|
1206
|
+
const invalidStatus: ValidateBlockResult = {
|
|
1207
|
+
valid: false,
|
|
1208
|
+
block: randomBlockInfo(2),
|
|
1209
|
+
committee: [EthAddress.random()],
|
|
1210
|
+
attestors: [EthAddress.random()],
|
|
1211
|
+
epoch: 789n,
|
|
1212
|
+
seed: 101n,
|
|
1213
|
+
attestations: [CommitteeAttestation.random()],
|
|
1214
|
+
reason: 'invalid-attestation',
|
|
1215
|
+
invalidIndex: 5,
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
await store.setPendingChainValidationStatus(invalidStatus);
|
|
1219
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1220
|
+
|
|
1221
|
+
expect(retrievedStatus).toEqual(invalidStatus);
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
it('should overwrite existing status when setting a new one', async () => {
|
|
1225
|
+
const firstStatus: ValidateBlockResult = { valid: true };
|
|
1226
|
+
const secondStatus: ValidateBlockResult = {
|
|
1227
|
+
valid: false,
|
|
1228
|
+
block: randomBlockInfo(3),
|
|
1229
|
+
committee: [EthAddress.random()],
|
|
1230
|
+
epoch: 999n,
|
|
1231
|
+
seed: 888n,
|
|
1232
|
+
attestors: [EthAddress.random()],
|
|
1233
|
+
attestations: [CommitteeAttestation.random()],
|
|
1234
|
+
reason: 'insufficient-attestations',
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
await store.setPendingChainValidationStatus(firstStatus);
|
|
1238
|
+
await store.setPendingChainValidationStatus(secondStatus);
|
|
1239
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1240
|
+
|
|
1241
|
+
expect(retrievedStatus).toEqual(secondStatus);
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
it('should handle empty committee and attestations arrays', async () => {
|
|
1245
|
+
const statusWithEmptyArrays: ValidateBlockResult = {
|
|
1246
|
+
valid: false,
|
|
1247
|
+
block: randomBlockInfo(4),
|
|
1248
|
+
committee: [],
|
|
1249
|
+
epoch: 0n,
|
|
1250
|
+
seed: 0n,
|
|
1251
|
+
attestors: [],
|
|
1252
|
+
attestations: [],
|
|
1253
|
+
reason: 'insufficient-attestations',
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1256
|
+
await store.setPendingChainValidationStatus(statusWithEmptyArrays);
|
|
1257
|
+
const retrievedStatus = await store.getPendingChainValidationStatus();
|
|
1258
|
+
|
|
1259
|
+
expect(retrievedStatus).toEqual(statusWithEmptyArrays);
|
|
807
1260
|
});
|
|
808
1261
|
});
|
|
809
1262
|
});
|