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