@aztec/archiver 0.0.1-commit.9372f48 → 0.0.1-commit.967fc6998
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/archiver.d.ts +5 -2
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +9 -91
- package/dest/factory.d.ts +1 -1
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +9 -7
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/l1/bin/retrieve-calldata.js +36 -33
- package/dest/l1/calldata_retriever.d.ts +73 -50
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +190 -259
- package/dest/l1/data_retrieval.d.ts +9 -9
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +21 -19
- package/dest/l1/spire_proposer.d.ts +5 -5
- package/dest/l1/spire_proposer.d.ts.map +1 -1
- package/dest/l1/spire_proposer.js +9 -17
- package/dest/modules/data_source_base.d.ts +8 -3
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +28 -72
- package/dest/modules/data_store_updater.d.ts +9 -2
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +40 -19
- package/dest/modules/instrumentation.d.ts +15 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +19 -2
- package/dest/modules/l1_synchronizer.d.ts +4 -8
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +14 -9
- package/dest/store/block_store.d.ts +18 -14
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +69 -17
- package/dest/store/kv_archiver_store.d.ts +18 -4
- package/dest/store/kv_archiver_store.d.ts.map +1 -1
- package/dest/store/kv_archiver_store.js +18 -0
- package/dest/store/l2_tips_cache.d.ts +19 -0
- package/dest/store/l2_tips_cache.d.ts.map +1 -0
- package/dest/store/l2_tips_cache.js +89 -0
- package/dest/store/log_store.d.ts +1 -1
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +55 -35
- package/dest/test/fake_l1_state.d.ts +6 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +56 -18
- package/dest/test/mock_archiver.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +3 -2
- package/dest/test/mock_l2_block_source.d.ts +18 -3
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +125 -82
- package/package.json +13 -13
- package/src/archiver.ts +10 -110
- package/src/factory.ts +23 -9
- package/src/index.ts +1 -0
- package/src/l1/README.md +25 -68
- package/src/l1/bin/retrieve-calldata.ts +46 -39
- package/src/l1/calldata_retriever.ts +249 -379
- package/src/l1/data_retrieval.ts +23 -25
- package/src/l1/spire_proposer.ts +7 -15
- package/src/modules/data_source_base.ts +53 -92
- package/src/modules/data_store_updater.ts +43 -18
- package/src/modules/instrumentation.ts +29 -2
- package/src/modules/l1_synchronizer.ts +15 -12
- package/src/store/block_store.ts +85 -36
- package/src/store/kv_archiver_store.ts +35 -3
- package/src/store/l2_tips_cache.ts +89 -0
- package/src/store/log_store.ts +93 -31
- package/src/test/fake_l1_state.ts +75 -17
- package/src/test/mock_archiver.ts +3 -2
- package/src/test/mock_l2_block_source.ts +158 -78
|
@@ -5,27 +5,39 @@ import { Buffer32 } from '@aztec/foundation/buffer';
|
|
|
5
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
-
import { CheckpointedL2Block
|
|
8
|
+
import { CheckpointedL2Block } from '@aztec/stdlib/block';
|
|
9
9
|
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
10
10
|
import { EmptyL1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
11
|
+
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
12
|
+
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
11
13
|
import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
12
14
|
/**
|
|
13
15
|
* A mocked implementation of L2BlockSource to be used in tests.
|
|
14
16
|
*/ export class MockL2BlockSource {
|
|
15
17
|
l2Blocks = [];
|
|
18
|
+
checkpointList = [];
|
|
16
19
|
provenBlockNumber = 0;
|
|
17
20
|
finalizedBlockNumber = 0;
|
|
18
21
|
checkpointedBlockNumber = 0;
|
|
19
22
|
log = createLogger('archiver:mock_l2_block_source');
|
|
20
|
-
async createBlocks(numBlocks) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
/** Creates blocks grouped into single-block checkpoints. */ async createBlocks(numBlocks) {
|
|
24
|
+
await this.createCheckpoints(numBlocks, 1);
|
|
25
|
+
}
|
|
26
|
+
/** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */ async createCheckpoints(numCheckpoints, blocksPerCheckpoint = 1) {
|
|
27
|
+
for(let c = 0; c < numCheckpoints; c++){
|
|
28
|
+
const checkpointNum = CheckpointNumber(this.checkpointList.length + 1);
|
|
29
|
+
const startBlockNum = this.l2Blocks.length + 1;
|
|
30
|
+
const slotNumber = SlotNumber(Number(checkpointNum));
|
|
31
|
+
const checkpoint = await Checkpoint.random(checkpointNum, {
|
|
32
|
+
numBlocks: blocksPerCheckpoint,
|
|
33
|
+
startBlockNumber: startBlockNum,
|
|
34
|
+
slotNumber,
|
|
35
|
+
checkpointNumber: checkpointNum
|
|
25
36
|
});
|
|
26
|
-
this.
|
|
37
|
+
this.checkpointList.push(checkpoint);
|
|
38
|
+
this.l2Blocks.push(...checkpoint.blocks);
|
|
27
39
|
}
|
|
28
|
-
this.log.verbose(`Created ${
|
|
40
|
+
this.log.verbose(`Created ${numCheckpoints} checkpoints with ${blocksPerCheckpoint} blocks each in the mock L2 block source`);
|
|
29
41
|
}
|
|
30
42
|
addProposedBlocks(blocks) {
|
|
31
43
|
this.l2Blocks.push(...blocks);
|
|
@@ -33,6 +45,16 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
33
45
|
}
|
|
34
46
|
removeBlocks(numBlocks) {
|
|
35
47
|
this.l2Blocks = this.l2Blocks.slice(0, -numBlocks);
|
|
48
|
+
const maxBlockNum = this.l2Blocks.length;
|
|
49
|
+
// Remove any checkpoint whose last block is beyond the remaining blocks.
|
|
50
|
+
this.checkpointList = this.checkpointList.filter((c)=>{
|
|
51
|
+
const lastBlockNum = c.blocks[0].number + c.blocks.length - 1;
|
|
52
|
+
return lastBlockNum <= maxBlockNum;
|
|
53
|
+
});
|
|
54
|
+
// Keep tip numbers consistent with remaining blocks.
|
|
55
|
+
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
56
|
+
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
57
|
+
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
36
58
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
37
59
|
}
|
|
38
60
|
setProvenBlockNumber(provenBlockNumber) {
|
|
@@ -45,7 +67,32 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
45
67
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
46
68
|
}
|
|
47
69
|
setCheckpointedBlockNumber(checkpointedBlockNumber) {
|
|
70
|
+
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
48
71
|
this.checkpointedBlockNumber = checkpointedBlockNumber;
|
|
72
|
+
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
73
|
+
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
74
|
+
const newCheckpoints = [];
|
|
75
|
+
for(let blockNum = prevCheckpointed + 1; blockNum <= checkpointedBlockNumber; blockNum++){
|
|
76
|
+
const block = this.l2Blocks[blockNum - 1];
|
|
77
|
+
if (!block) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (this.checkpointList.some((c)=>c.blocks.some((b)=>b.number === block.number))) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const checkpointNum = CheckpointNumber(this.checkpointList.length + newCheckpoints.length + 1);
|
|
84
|
+
const checkpoint = new Checkpoint(block.archive, CheckpointHeader.random({
|
|
85
|
+
slotNumber: block.header.globalVariables.slotNumber
|
|
86
|
+
}), [
|
|
87
|
+
block
|
|
88
|
+
], checkpointNum);
|
|
89
|
+
newCheckpoints.push(checkpoint);
|
|
90
|
+
}
|
|
91
|
+
// Insert new checkpoints in order by number.
|
|
92
|
+
if (newCheckpoints.length > 0) {
|
|
93
|
+
this.checkpointList.push(...newCheckpoints);
|
|
94
|
+
this.checkpointList.sort((a, b)=>a.number - b.number);
|
|
95
|
+
}
|
|
49
96
|
}
|
|
50
97
|
/**
|
|
51
98
|
* Method to fetch the rollup contract address at the base-layer.
|
|
@@ -82,8 +129,7 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
82
129
|
if (!block) {
|
|
83
130
|
return Promise.resolve(undefined);
|
|
84
131
|
}
|
|
85
|
-
|
|
86
|
-
return Promise.resolve(checkpointedBlock);
|
|
132
|
+
return Promise.resolve(this.toCheckpointedBlock(block));
|
|
87
133
|
}
|
|
88
134
|
async getCheckpointedBlocks(from, limit) {
|
|
89
135
|
const result = [];
|
|
@@ -124,44 +170,18 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
124
170
|
return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit));
|
|
125
171
|
}
|
|
126
172
|
getCheckpoints(from, limit) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return Promise.all(blocks.map(async (block)=>{
|
|
130
|
-
// Create a checkpoint from the block - manually construct since L2Block doesn't have toCheckpoint()
|
|
131
|
-
const checkpoint = await Checkpoint.random(block.checkpointNumber, {
|
|
132
|
-
numBlocks: 1
|
|
133
|
-
});
|
|
134
|
-
checkpoint.blocks = [
|
|
135
|
-
block
|
|
136
|
-
];
|
|
137
|
-
return new PublishedCheckpoint(checkpoint, new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()), []);
|
|
138
|
-
}));
|
|
173
|
+
const checkpoints = this.checkpointList.slice(from - 1, from - 1 + limit);
|
|
174
|
+
return Promise.resolve(checkpoints.map((checkpoint)=>new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])));
|
|
139
175
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (!block) {
|
|
144
|
-
return undefined;
|
|
145
|
-
}
|
|
146
|
-
// Create a checkpoint from the block - manually construct since L2Block doesn't have toCheckpoint()
|
|
147
|
-
const checkpoint = await Checkpoint.random(block.checkpointNumber, {
|
|
148
|
-
numBlocks: 1
|
|
149
|
-
});
|
|
150
|
-
checkpoint.blocks = [
|
|
151
|
-
block
|
|
152
|
-
];
|
|
153
|
-
return checkpoint;
|
|
176
|
+
getCheckpointByArchive(archive) {
|
|
177
|
+
const checkpoint = this.checkpointList.find((c)=>c.archive.root.equals(archive));
|
|
178
|
+
return Promise.resolve(checkpoint);
|
|
154
179
|
}
|
|
155
180
|
async getCheckpointedBlockByHash(blockHash) {
|
|
156
181
|
for (const block of this.l2Blocks){
|
|
157
182
|
const hash = await block.hash();
|
|
158
183
|
if (hash.equals(blockHash)) {
|
|
159
|
-
return
|
|
160
|
-
checkpointNumber: CheckpointNumber.fromBlockNumber(block.number),
|
|
161
|
-
block,
|
|
162
|
-
l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
|
|
163
|
-
attestations: []
|
|
164
|
-
});
|
|
184
|
+
return this.toCheckpointedBlock(block);
|
|
165
185
|
}
|
|
166
186
|
}
|
|
167
187
|
return undefined;
|
|
@@ -171,12 +191,7 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
171
191
|
if (!block) {
|
|
172
192
|
return Promise.resolve(undefined);
|
|
173
193
|
}
|
|
174
|
-
return Promise.resolve(
|
|
175
|
-
checkpointNumber: CheckpointNumber.fromBlockNumber(block.number),
|
|
176
|
-
block,
|
|
177
|
-
l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
|
|
178
|
-
attestations: []
|
|
179
|
-
}));
|
|
194
|
+
return Promise.resolve(this.toCheckpointedBlock(block));
|
|
180
195
|
}
|
|
181
196
|
async getL2BlockByHash(blockHash) {
|
|
182
197
|
for (const block of this.l2Blocks){
|
|
@@ -204,45 +219,54 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
204
219
|
const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
|
|
205
220
|
return Promise.resolve(block?.header);
|
|
206
221
|
}
|
|
222
|
+
async getBlockData(number) {
|
|
223
|
+
const block = this.l2Blocks[number - 1];
|
|
224
|
+
if (!block) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
header: block.header,
|
|
229
|
+
archive: block.archive,
|
|
230
|
+
blockHash: await block.hash(),
|
|
231
|
+
checkpointNumber: block.checkpointNumber,
|
|
232
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async getBlockDataByArchive(archive) {
|
|
236
|
+
const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
|
|
237
|
+
if (!block) {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
header: block.header,
|
|
242
|
+
archive: block.archive,
|
|
243
|
+
blockHash: await block.hash(),
|
|
244
|
+
checkpointNumber: block.checkpointNumber,
|
|
245
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint
|
|
246
|
+
};
|
|
247
|
+
}
|
|
207
248
|
getBlockHeader(number) {
|
|
208
249
|
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
209
250
|
}
|
|
210
251
|
getCheckpointsForEpoch(epochNumber) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
});
|
|
225
|
-
checkpoint.blocks = [
|
|
226
|
-
block
|
|
227
|
-
];
|
|
228
|
-
return checkpoint;
|
|
229
|
-
}));
|
|
252
|
+
return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
|
|
253
|
+
}
|
|
254
|
+
getCheckpointsDataForEpoch(epochNumber) {
|
|
255
|
+
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
256
|
+
return Promise.resolve(checkpoints.map((checkpoint)=>({
|
|
257
|
+
checkpointNumber: checkpoint.number,
|
|
258
|
+
header: checkpoint.header,
|
|
259
|
+
archive: checkpoint.archive,
|
|
260
|
+
checkpointOutHash: computeCheckpointOutHash(checkpoint.blocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs))),
|
|
261
|
+
startBlock: checkpoint.blocks[0].number,
|
|
262
|
+
blockCount: checkpoint.blocks.length,
|
|
263
|
+
attestations: [],
|
|
264
|
+
l1: this.mockL1DataForCheckpoint(checkpoint)
|
|
265
|
+
})));
|
|
230
266
|
}
|
|
231
267
|
getCheckpointedBlocksForEpoch(epochNumber) {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
epochDuration
|
|
235
|
-
});
|
|
236
|
-
const blocks = this.l2Blocks.filter((b)=>{
|
|
237
|
-
const slot = b.header.globalVariables.slotNumber;
|
|
238
|
-
return slot >= start && slot <= end;
|
|
239
|
-
});
|
|
240
|
-
return Promise.resolve(blocks.map((block)=>CheckpointedL2Block.fromFields({
|
|
241
|
-
checkpointNumber: CheckpointNumber.fromBlockNumber(block.number),
|
|
242
|
-
block,
|
|
243
|
-
l1: new L1PublishedData(BigInt(block.number), BigInt(block.number), Buffer32.random().toString()),
|
|
244
|
-
attestations: []
|
|
245
|
-
})));
|
|
268
|
+
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
269
|
+
return Promise.resolve(checkpoints.flatMap((checkpoint)=>checkpoint.blocks.map((block)=>this.toCheckpointedBlock(block))));
|
|
246
270
|
}
|
|
247
271
|
getBlocksForSlot(slotNumber) {
|
|
248
272
|
const blocks = this.l2Blocks.filter((b)=>b.header.globalVariables.slotNumber === slotNumber);
|
|
@@ -317,7 +341,7 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
317
341
|
const makeTipId = (blockId)=>({
|
|
318
342
|
block: blockId,
|
|
319
343
|
checkpoint: {
|
|
320
|
-
number:
|
|
344
|
+
number: this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0),
|
|
321
345
|
hash: blockId.hash
|
|
322
346
|
}
|
|
323
347
|
});
|
|
@@ -391,4 +415,23 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
|
391
415
|
valid: true
|
|
392
416
|
});
|
|
393
417
|
}
|
|
418
|
+
/** Returns checkpoints whose slot falls within the given epoch. */ getCheckpointsInEpoch(epochNumber) {
|
|
419
|
+
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
420
|
+
const [start, end] = getSlotRangeForEpoch(epochNumber, {
|
|
421
|
+
epochDuration
|
|
422
|
+
});
|
|
423
|
+
return this.checkpointList.filter((c)=>c.header.slotNumber >= start && c.header.slotNumber <= end);
|
|
424
|
+
}
|
|
425
|
+
/** Creates a mock L1PublishedData for a checkpoint. */ mockL1DataForCheckpoint(checkpoint) {
|
|
426
|
+
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
427
|
+
}
|
|
428
|
+
/** Creates a CheckpointedL2Block from a block using stored checkpoint info. */ toCheckpointedBlock(block) {
|
|
429
|
+
const checkpoint = this.checkpointList.find((c)=>c.blocks.some((b)=>b.number === block.number));
|
|
430
|
+
const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
|
|
431
|
+
return new CheckpointedL2Block(checkpointNumber, block, new L1PublishedData(BigInt(block.number), BigInt(block.number), `0x${block.number.toString(16).padStart(64, '0')}`), []);
|
|
432
|
+
}
|
|
433
|
+
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */ findCheckpointNumberForBlock(blockNumber) {
|
|
434
|
+
const checkpoint = this.checkpointList.find((c)=>c.blocks.some((b)=>b.number === blockNumber));
|
|
435
|
+
return checkpoint?.number;
|
|
436
|
+
}
|
|
394
437
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/archiver",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.967fc6998",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -65,18 +65,18 @@
|
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
69
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
70
|
-
"@aztec/constants": "0.0.1-commit.
|
|
71
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
72
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
73
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
74
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
75
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
76
|
-
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.
|
|
77
|
-
"@aztec/protocol-contracts": "0.0.1-commit.
|
|
78
|
-
"@aztec/stdlib": "0.0.1-commit.
|
|
79
|
-
"@aztec/telemetry-client": "0.0.1-commit.
|
|
68
|
+
"@aztec/blob-client": "0.0.1-commit.967fc6998",
|
|
69
|
+
"@aztec/blob-lib": "0.0.1-commit.967fc6998",
|
|
70
|
+
"@aztec/constants": "0.0.1-commit.967fc6998",
|
|
71
|
+
"@aztec/epoch-cache": "0.0.1-commit.967fc6998",
|
|
72
|
+
"@aztec/ethereum": "0.0.1-commit.967fc6998",
|
|
73
|
+
"@aztec/foundation": "0.0.1-commit.967fc6998",
|
|
74
|
+
"@aztec/kv-store": "0.0.1-commit.967fc6998",
|
|
75
|
+
"@aztec/l1-artifacts": "0.0.1-commit.967fc6998",
|
|
76
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.967fc6998",
|
|
77
|
+
"@aztec/protocol-contracts": "0.0.1-commit.967fc6998",
|
|
78
|
+
"@aztec/stdlib": "0.0.1-commit.967fc6998",
|
|
79
|
+
"@aztec/telemetry-client": "0.0.1-commit.967fc6998",
|
|
80
80
|
"lodash.groupby": "^4.6.0",
|
|
81
81
|
"lodash.omit": "^4.5.0",
|
|
82
82
|
"tslib": "^2.5.0",
|
package/src/archiver.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
|
-
import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
3
2
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
4
3
|
import { BlockTagTooOldError, RollupContract } from '@aztec/ethereum/contracts';
|
|
5
4
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
@@ -15,8 +14,6 @@ import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/runni
|
|
|
15
14
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
16
15
|
import {
|
|
17
16
|
type ArchiverEmitter,
|
|
18
|
-
type CheckpointId,
|
|
19
|
-
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
20
17
|
L2Block,
|
|
21
18
|
type L2BlockSink,
|
|
22
19
|
type L2Tips,
|
|
@@ -41,6 +38,7 @@ import { ArchiverDataStoreUpdater } from './modules/data_store_updater.js';
|
|
|
41
38
|
import type { ArchiverInstrumentation } from './modules/instrumentation.js';
|
|
42
39
|
import type { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js';
|
|
43
40
|
import type { KVArchiverDataStore } from './store/kv_archiver_store.js';
|
|
41
|
+
import { L2TipsCache } from './store/l2_tips_cache.js';
|
|
44
42
|
|
|
45
43
|
/** Export ArchiverEmitter for use in factory and tests. */
|
|
46
44
|
export type { ArchiverEmitter };
|
|
@@ -83,6 +81,9 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
83
81
|
/** Helper to handle updates to the store */
|
|
84
82
|
private readonly updater: ArchiverDataStoreUpdater;
|
|
85
83
|
|
|
84
|
+
/** In-memory cache for L2 chain tips. */
|
|
85
|
+
private readonly l2TipsCache: L2TipsCache;
|
|
86
|
+
|
|
86
87
|
public readonly tracer: Tracer;
|
|
87
88
|
|
|
88
89
|
/**
|
|
@@ -122,6 +123,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
122
123
|
protected override readonly l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr },
|
|
123
124
|
synchronizer: ArchiverL1Synchronizer,
|
|
124
125
|
events: ArchiverEmitter,
|
|
126
|
+
l2TipsCache?: L2TipsCache,
|
|
125
127
|
private readonly log: Logger = createLogger('archiver'),
|
|
126
128
|
) {
|
|
127
129
|
super(dataStore, l1Constants);
|
|
@@ -130,7 +132,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
130
132
|
this.initialSyncPromise = promiseWithResolvers();
|
|
131
133
|
this.synchronizer = synchronizer;
|
|
132
134
|
this.events = events;
|
|
133
|
-
this.
|
|
135
|
+
this.l2TipsCache = l2TipsCache ?? new L2TipsCache(this.dataStore.blockStore);
|
|
136
|
+
this.updater = new ArchiverDataStoreUpdater(this.dataStore, this.l2TipsCache);
|
|
134
137
|
|
|
135
138
|
// Running promise starts with a small interval inbetween runs, so all iterations needed for the initial sync
|
|
136
139
|
// are done as fast as possible. This then gets updated once the initial sync completes.
|
|
@@ -391,111 +394,8 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
391
394
|
return true;
|
|
392
395
|
}
|
|
393
396
|
|
|
394
|
-
public
|
|
395
|
-
|
|
396
|
-
this.getBlockNumber(),
|
|
397
|
-
this.getProvenBlockNumber(),
|
|
398
|
-
this.getCheckpointedL2BlockNumber(),
|
|
399
|
-
this.getFinalizedL2BlockNumber(),
|
|
400
|
-
] as const);
|
|
401
|
-
|
|
402
|
-
const beforeInitialblockNumber = BlockNumber(INITIAL_L2_BLOCK_NUM - 1);
|
|
403
|
-
|
|
404
|
-
// Get the latest block header and checkpointed blocks for proven, finalised and checkpointed blocks
|
|
405
|
-
const [latestBlockHeader, provenCheckpointedBlock, finalizedCheckpointedBlock, checkpointedBlock] =
|
|
406
|
-
await Promise.all([
|
|
407
|
-
latestBlockNumber > beforeInitialblockNumber ? this.getBlockHeader(latestBlockNumber) : undefined,
|
|
408
|
-
provenBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(provenBlockNumber) : undefined,
|
|
409
|
-
finalizedBlockNumber > beforeInitialblockNumber ? this.getCheckpointedBlock(finalizedBlockNumber) : undefined,
|
|
410
|
-
checkpointedBlockNumber > beforeInitialblockNumber
|
|
411
|
-
? this.getCheckpointedBlock(checkpointedBlockNumber)
|
|
412
|
-
: undefined,
|
|
413
|
-
] as const);
|
|
414
|
-
|
|
415
|
-
if (latestBlockNumber > beforeInitialblockNumber && !latestBlockHeader) {
|
|
416
|
-
throw new Error(`Failed to retrieve latest block header for block ${latestBlockNumber}`);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Checkpointed blocks must exist for proven, finalized and checkpointed tips if they are beyond the initial block number.
|
|
420
|
-
if (checkpointedBlockNumber > beforeInitialblockNumber && !checkpointedBlock?.block.header) {
|
|
421
|
-
throw new Error(
|
|
422
|
-
`Failed to retrieve checkpointed block header for block ${checkpointedBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (provenBlockNumber > beforeInitialblockNumber && !provenCheckpointedBlock?.block.header) {
|
|
427
|
-
throw new Error(
|
|
428
|
-
`Failed to retrieve proven checkpointed for block ${provenBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (finalizedBlockNumber > beforeInitialblockNumber && !finalizedCheckpointedBlock?.block.header) {
|
|
433
|
-
throw new Error(
|
|
434
|
-
`Failed to retrieve finalized block header for block ${finalizedBlockNumber} (latest block is ${latestBlockNumber})`,
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const latestBlockHeaderHash = (await latestBlockHeader?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
439
|
-
const provenBlockHeaderHash = (await provenCheckpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
440
|
-
const finalizedBlockHeaderHash =
|
|
441
|
-
(await finalizedCheckpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
442
|
-
const checkpointedBlockHeaderHash = (await checkpointedBlock?.block.header?.hash()) ?? GENESIS_BLOCK_HEADER_HASH;
|
|
443
|
-
|
|
444
|
-
// Now attempt to retrieve checkpoints for proven, finalised and checkpointed blocks
|
|
445
|
-
const [[provenBlockCheckpoint], [finalizedBlockCheckpoint], [checkpointedBlockCheckpoint]] = await Promise.all([
|
|
446
|
-
provenCheckpointedBlock !== undefined
|
|
447
|
-
? await this.getCheckpoints(provenCheckpointedBlock?.checkpointNumber, 1)
|
|
448
|
-
: [undefined],
|
|
449
|
-
finalizedCheckpointedBlock !== undefined
|
|
450
|
-
? await this.getCheckpoints(finalizedCheckpointedBlock?.checkpointNumber, 1)
|
|
451
|
-
: [undefined],
|
|
452
|
-
checkpointedBlock !== undefined ? await this.getCheckpoints(checkpointedBlock?.checkpointNumber, 1) : [undefined],
|
|
453
|
-
]);
|
|
454
|
-
|
|
455
|
-
const initialcheckpointId: CheckpointId = {
|
|
456
|
-
number: CheckpointNumber.ZERO,
|
|
457
|
-
hash: GENESIS_CHECKPOINT_HEADER_HASH.toString(),
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
const makeCheckpointId = (checkpoint: PublishedCheckpoint | undefined) => {
|
|
461
|
-
if (checkpoint === undefined) {
|
|
462
|
-
return initialcheckpointId;
|
|
463
|
-
}
|
|
464
|
-
return {
|
|
465
|
-
number: checkpoint.checkpoint.number,
|
|
466
|
-
hash: checkpoint.checkpoint.hash().toString(),
|
|
467
|
-
};
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
const l2Tips: L2Tips = {
|
|
471
|
-
proposed: {
|
|
472
|
-
number: latestBlockNumber,
|
|
473
|
-
hash: latestBlockHeaderHash.toString(),
|
|
474
|
-
},
|
|
475
|
-
proven: {
|
|
476
|
-
block: {
|
|
477
|
-
number: provenBlockNumber,
|
|
478
|
-
hash: provenBlockHeaderHash.toString(),
|
|
479
|
-
},
|
|
480
|
-
checkpoint: makeCheckpointId(provenBlockCheckpoint),
|
|
481
|
-
},
|
|
482
|
-
finalized: {
|
|
483
|
-
block: {
|
|
484
|
-
number: finalizedBlockNumber,
|
|
485
|
-
hash: finalizedBlockHeaderHash.toString(),
|
|
486
|
-
},
|
|
487
|
-
checkpoint: makeCheckpointId(finalizedBlockCheckpoint),
|
|
488
|
-
},
|
|
489
|
-
checkpointed: {
|
|
490
|
-
block: {
|
|
491
|
-
number: checkpointedBlockNumber,
|
|
492
|
-
hash: checkpointedBlockHeaderHash.toString(),
|
|
493
|
-
},
|
|
494
|
-
checkpoint: makeCheckpointId(checkpointedBlockCheckpoint),
|
|
495
|
-
},
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
return l2Tips;
|
|
397
|
+
public getL2Tips(): Promise<L2Tips> {
|
|
398
|
+
return this.l2TipsCache.getL2Tips();
|
|
499
399
|
}
|
|
500
400
|
|
|
501
401
|
public async rollbackTo(targetL2BlockNumber: BlockNumber): Promise<void> {
|
|
@@ -532,7 +432,7 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra
|
|
|
532
432
|
await this.store.setMessageSynchedL1Block({ l1BlockNumber: targetL1BlockNumber, l1BlockHash: targetL1BlockHash });
|
|
533
433
|
if (targetL2BlockNumber < currentProvenBlock) {
|
|
534
434
|
this.log.info(`Clearing proven L2 block number`);
|
|
535
|
-
await this.
|
|
435
|
+
await this.updater.setProvenCheckpointNumber(CheckpointNumber.ZERO);
|
|
536
436
|
}
|
|
537
437
|
// TODO(palla/reorg): Set the finalized block when we add support for it.
|
|
538
438
|
// if (targetL2BlockNumber < currentFinalizedBlock) {
|
package/src/factory.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { type ArchiverConfig, mapArchiverConfig } from './config.js';
|
|
|
25
25
|
import { ArchiverInstrumentation } from './modules/instrumentation.js';
|
|
26
26
|
import { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js';
|
|
27
27
|
import { ARCHIVER_DB_VERSION, KVArchiverDataStore } from './store/kv_archiver_store.js';
|
|
28
|
+
import { L2TipsCache } from './store/l2_tips_cache.js';
|
|
28
29
|
|
|
29
30
|
export const ARCHIVER_STORE_NAME = 'archiver';
|
|
30
31
|
|
|
@@ -77,14 +78,21 @@ export async function createArchiver(
|
|
|
77
78
|
const inbox = new InboxContract(publicClient, config.l1Contracts.inboxAddress);
|
|
78
79
|
|
|
79
80
|
// Fetch L1 constants from rollup contract
|
|
80
|
-
const [
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
const [
|
|
82
|
+
l1StartBlock,
|
|
83
|
+
l1GenesisTime,
|
|
84
|
+
proofSubmissionEpochs,
|
|
85
|
+
genesisArchiveRoot,
|
|
86
|
+
slashingProposerAddress,
|
|
87
|
+
targetCommitteeSize,
|
|
88
|
+
] = await Promise.all([
|
|
89
|
+
rollup.getL1StartBlock(),
|
|
90
|
+
rollup.getL1GenesisTime(),
|
|
91
|
+
rollup.getProofSubmissionEpochs(),
|
|
92
|
+
rollup.getGenesisArchiveTreeRoot(),
|
|
93
|
+
rollup.getSlashingProposerAddress(),
|
|
94
|
+
rollup.getTargetCommitteeSize(),
|
|
95
|
+
] as const);
|
|
88
96
|
|
|
89
97
|
const l1StartBlockHash = await publicClient
|
|
90
98
|
.getBlock({ blockNumber: l1StartBlock, includeTransactions: false })
|
|
@@ -100,6 +108,7 @@ export async function createArchiver(
|
|
|
100
108
|
slotDuration,
|
|
101
109
|
ethereumSlotDuration,
|
|
102
110
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
111
|
+
targetCommitteeSize,
|
|
103
112
|
genesisArchiveRoot: Fr.fromString(genesisArchiveRoot.toString()),
|
|
104
113
|
};
|
|
105
114
|
|
|
@@ -120,13 +129,15 @@ export async function createArchiver(
|
|
|
120
129
|
// Create the event emitter that will be shared by archiver and synchronizer
|
|
121
130
|
const events = new EventEmitter() as ArchiverEmitter;
|
|
122
131
|
|
|
132
|
+
// Create L2 tips cache shared by archiver and synchronizer
|
|
133
|
+
const l2TipsCache = new L2TipsCache(archiverStore.blockStore);
|
|
134
|
+
|
|
123
135
|
// Create the L1 synchronizer
|
|
124
136
|
const synchronizer = new ArchiverL1Synchronizer(
|
|
125
137
|
publicClient,
|
|
126
138
|
debugClient,
|
|
127
139
|
rollup,
|
|
128
140
|
inbox,
|
|
129
|
-
{ ...config.l1Contracts, slashingProposerAddress },
|
|
130
141
|
archiverStore,
|
|
131
142
|
archiverConfig,
|
|
132
143
|
deps.blobClient,
|
|
@@ -136,6 +147,8 @@ export async function createArchiver(
|
|
|
136
147
|
l1Constants,
|
|
137
148
|
events,
|
|
138
149
|
instrumentation.tracer,
|
|
150
|
+
l2TipsCache,
|
|
151
|
+
undefined, // log (use default)
|
|
139
152
|
);
|
|
140
153
|
|
|
141
154
|
const archiver = new Archiver(
|
|
@@ -150,6 +163,7 @@ export async function createArchiver(
|
|
|
150
163
|
l1Constants,
|
|
151
164
|
synchronizer,
|
|
152
165
|
events,
|
|
166
|
+
l2TipsCache,
|
|
153
167
|
);
|
|
154
168
|
|
|
155
169
|
await archiver.start(opts.blockUntilSync);
|
package/src/index.ts
CHANGED
|
@@ -8,5 +8,6 @@ export * from './config.js';
|
|
|
8
8
|
export { type L1PublishedData } from './structs/published.js';
|
|
9
9
|
export { KVArchiverDataStore, ARCHIVER_DB_VERSION } from './store/kv_archiver_store.js';
|
|
10
10
|
export { ContractInstanceStore } from './store/contract_instance_store.js';
|
|
11
|
+
export { L2TipsCache } from './store/l2_tips_cache.js';
|
|
11
12
|
|
|
12
13
|
export { retrieveCheckpointsFromRollup, retrieveL2ProofVerifiedEvents } from './l1/data_retrieval.js';
|