@aztec/archiver 0.0.1-commit.b2a5d0dd1 → 0.0.1-commit.b3d3157a
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 +7 -5
- package/dest/archiver.d.ts +49 -14
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +216 -68
- package/dest/config.d.ts +4 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +11 -16
- package/dest/errors.d.ts +19 -13
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +32 -16
- package/dest/factory.d.ts +12 -6
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +31 -21
- package/dest/index.d.ts +9 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +8 -1
- package/dest/l1/calldata_retriever.d.ts +2 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +13 -4
- package/dest/l1/trace_tx.d.ts +12 -66
- package/dest/l1/trace_tx.d.ts.map +1 -1
- package/dest/modules/contract_data_source_adapter.d.ts +25 -0
- package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
- package/dest/modules/contract_data_source_adapter.js +40 -0
- package/dest/modules/data_source_base.d.ts +71 -49
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +269 -143
- package/dest/modules/data_store_updater.d.ts +18 -6
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +108 -59
- package/dest/modules/instrumentation.js +3 -1
- package/dest/modules/l1_synchronizer.d.ts +6 -5
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +203 -100
- package/dest/modules/outbox_trees_resolver.d.ts +62 -0
- package/dest/modules/outbox_trees_resolver.d.ts.map +1 -0
- package/dest/modules/outbox_trees_resolver.js +162 -0
- package/dest/modules/validation.d.ts +4 -3
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +4 -4
- package/dest/store/block_store.d.ts +155 -98
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +473 -265
- package/dest/store/contract_class_store.d.ts +17 -3
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +17 -1
- package/dest/store/contract_instance_store.d.ts +28 -1
- package/dest/store/contract_instance_store.d.ts.map +1 -1
- package/dest/store/contract_instance_store.js +31 -0
- package/dest/store/data_stores.d.ts +68 -0
- package/dest/store/data_stores.d.ts.map +1 -0
- package/dest/store/data_stores.js +54 -0
- package/dest/store/function_names_cache.d.ts +17 -0
- package/dest/store/function_names_cache.d.ts.map +1 -0
- package/dest/store/function_names_cache.js +30 -0
- package/dest/store/l2_tips_cache.d.ts +13 -8
- package/dest/store/l2_tips_cache.d.ts.map +1 -1
- package/dest/store/l2_tips_cache.js +13 -96
- package/dest/store/log_store.d.ts +42 -40
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +257 -478
- package/dest/store/log_store_codec.d.ts +70 -0
- package/dest/store/log_store_codec.d.ts.map +1 -0
- package/dest/store/log_store_codec.js +101 -0
- package/dest/store/message_store.d.ts +9 -3
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +31 -1
- package/dest/test/fake_l1_state.d.ts +2 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +25 -8
- package/dest/test/mock_l2_block_source.d.ts +47 -51
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +223 -185
- package/dest/test/noop_l1_archiver.d.ts +10 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +19 -8
- package/package.json +14 -14
- package/src/archiver.ts +265 -72
- package/src/config.ts +12 -19
- package/src/errors.ts +46 -23
- package/src/factory.ts +38 -20
- package/src/index.ts +16 -1
- package/src/l1/calldata_retriever.ts +14 -4
- package/src/modules/contract_data_source_adapter.ts +55 -0
- package/src/modules/data_source_base.ts +335 -187
- package/src/modules/data_store_updater.ts +118 -61
- package/src/modules/instrumentation.ts +1 -1
- package/src/modules/l1_synchronizer.ts +278 -120
- package/src/modules/outbox_trees_resolver.ts +199 -0
- package/src/modules/validation.ts +8 -7
- package/src/store/block_store.ts +566 -323
- package/src/store/contract_class_store.ts +28 -2
- package/src/store/contract_instance_store.ts +43 -0
- package/src/store/data_stores.ts +104 -0
- package/src/store/function_names_cache.ts +37 -0
- package/src/store/l2_tips_cache.ts +16 -115
- package/src/store/log_store.ts +296 -650
- package/src/store/log_store_codec.ts +132 -0
- package/src/store/message_store.ts +35 -2
- package/src/test/fake_l1_state.ts +24 -14
- package/src/test/mock_l2_block_source.ts +271 -239
- package/src/test/noop_l1_archiver.ts +39 -8
- package/dest/store/kv_archiver_store.d.ts +0 -383
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -501
- package/src/store/kv_archiver_store.ts +0 -728
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
|
|
2
2
|
import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
BlockNumber,
|
|
5
|
+
CheckpointNumber,
|
|
6
|
+
EpochNumber,
|
|
7
|
+
IndexWithinCheckpoint,
|
|
8
|
+
SlotNumber,
|
|
9
|
+
} from '@aztec/foundation/branded-types';
|
|
4
10
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
5
11
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
12
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -9,11 +15,19 @@ import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
|
9
15
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
10
16
|
import {
|
|
11
17
|
type BlockData,
|
|
12
|
-
BlockHash,
|
|
13
|
-
|
|
18
|
+
type BlockHash,
|
|
19
|
+
type BlockQuery,
|
|
20
|
+
type BlockTag,
|
|
21
|
+
type BlocksQuery,
|
|
22
|
+
Body,
|
|
23
|
+
type CheckpointQuery,
|
|
24
|
+
type CheckpointsQuery,
|
|
25
|
+
GENESIS_BLOCK_HEADER_HASH,
|
|
26
|
+
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
14
27
|
L2Block,
|
|
15
28
|
type L2BlockSource,
|
|
16
29
|
type L2Tips,
|
|
30
|
+
type ProposedCheckpointQuery,
|
|
17
31
|
type ValidateCheckpointResult,
|
|
18
32
|
} from '@aztec/stdlib/block';
|
|
19
33
|
import {
|
|
@@ -24,15 +38,11 @@ import {
|
|
|
24
38
|
PublishedCheckpoint,
|
|
25
39
|
} from '@aztec/stdlib/checkpoint';
|
|
26
40
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
27
|
-
import {
|
|
28
|
-
EmptyL1RollupConstants,
|
|
29
|
-
type L1RollupConstants,
|
|
30
|
-
getEpochAtSlot,
|
|
31
|
-
getSlotRangeForEpoch,
|
|
32
|
-
} from '@aztec/stdlib/epoch-helpers';
|
|
41
|
+
import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
33
42
|
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
34
43
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
35
|
-
import {
|
|
44
|
+
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
45
|
+
import { BlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
36
46
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
37
47
|
|
|
38
48
|
/**
|
|
@@ -47,8 +57,66 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
47
57
|
private checkpointedBlockNumber: number = 0;
|
|
48
58
|
private proposedCheckpointBlockNumber: number = 0;
|
|
49
59
|
|
|
60
|
+
private initialHeader: BlockHeader = BlockHeader.empty();
|
|
61
|
+
private initialHeaderHash: BlockHash = GENESIS_BLOCK_HEADER_HASH;
|
|
62
|
+
private genesisArchiveRoot?: Fr;
|
|
63
|
+
private genesisBlock?: L2Block;
|
|
64
|
+
|
|
50
65
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
51
66
|
|
|
67
|
+
/** Returns the initial header used to synthesize block 0. */
|
|
68
|
+
public getInitialHeader(): BlockHeader {
|
|
69
|
+
return this.initialHeader;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Sets the initial header used to synthesize block 0. Tests that wire up a real
|
|
74
|
+
* world-state should call this with `worldState.getInitialHeader()` so the L2BlockStream
|
|
75
|
+
* agrees on the genesis hash on both sides. Precomputes and caches the header hash so
|
|
76
|
+
* `getGenesisBlockHash()` can return synchronously.
|
|
77
|
+
*/
|
|
78
|
+
public async setInitialHeader(header: BlockHeader): Promise<void> {
|
|
79
|
+
this.initialHeader = header;
|
|
80
|
+
this.initialHeaderHash = await header.hash();
|
|
81
|
+
this.genesisBlock = undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the precomputed hash of the genesis block header. Defaults to the static
|
|
86
|
+
* {@link GENESIS_BLOCK_HEADER_HASH} unless {@link setInitialHeader} has been called with a
|
|
87
|
+
* custom header.
|
|
88
|
+
*/
|
|
89
|
+
public getGenesisBlockHash(): BlockHash {
|
|
90
|
+
return this.initialHeaderHash;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Sets the post-genesis archive root used to synthesize block 0. Mirrors the real archiver,
|
|
95
|
+
* whose synthetic block 0 carries `new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1)` rather
|
|
96
|
+
* than `AppendOnlyTreeSnapshot.empty()`. Tests wiring up a real world-state should set this so
|
|
97
|
+
* archive-based block lookups against the mock match production semantics.
|
|
98
|
+
*/
|
|
99
|
+
public setGenesisArchiveRoot(root: Fr): void {
|
|
100
|
+
this.genesisArchiveRoot = root;
|
|
101
|
+
this.genesisBlock = undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private getGenesisBlock(): L2Block {
|
|
105
|
+
if (this.genesisBlock) {
|
|
106
|
+
return this.genesisBlock;
|
|
107
|
+
}
|
|
108
|
+
const archive = this.genesisArchiveRoot
|
|
109
|
+
? new AppendOnlyTreeSnapshot(this.genesisArchiveRoot, 1)
|
|
110
|
+
: AppendOnlyTreeSnapshot.empty();
|
|
111
|
+
return (this.genesisBlock = new L2Block(
|
|
112
|
+
archive,
|
|
113
|
+
this.initialHeader,
|
|
114
|
+
Body.empty(),
|
|
115
|
+
CheckpointNumber.ZERO,
|
|
116
|
+
IndexWithinCheckpoint(0),
|
|
117
|
+
));
|
|
118
|
+
}
|
|
119
|
+
|
|
52
120
|
/** Creates blocks grouped into single-block checkpoints. */
|
|
53
121
|
public async createBlocks(numBlocks: number) {
|
|
54
122
|
await this.createCheckpoints(numBlocks, 1);
|
|
@@ -171,84 +239,36 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
171
239
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
172
240
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
173
241
|
*/
|
|
174
|
-
public getBlockNumber()
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return
|
|
242
|
+
public getBlockNumber(): Promise<BlockNumber>;
|
|
243
|
+
public getBlockNumber(query: BlockQuery): Promise<BlockNumber | undefined>;
|
|
244
|
+
public async getBlockNumber(query?: BlockQuery): Promise<BlockNumber | undefined> {
|
|
245
|
+
if (!query) {
|
|
246
|
+
return BlockNumber(this.l2Blocks.length);
|
|
247
|
+
}
|
|
248
|
+
if ('number' in query) {
|
|
249
|
+
return query.number;
|
|
250
|
+
}
|
|
251
|
+
if ('tag' in query) {
|
|
252
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
253
|
+
}
|
|
254
|
+
const block = await this.getBlock(query);
|
|
255
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
188
256
|
}
|
|
189
257
|
|
|
190
258
|
public getProposedCheckpointL2BlockNumber() {
|
|
191
259
|
return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
|
|
192
260
|
}
|
|
193
261
|
|
|
194
|
-
public
|
|
195
|
-
|
|
262
|
+
public getCheckpoint(query: CheckpointQuery): Promise<PublishedCheckpoint | undefined> {
|
|
263
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
264
|
+
if (!checkpoint) {
|
|
196
265
|
return Promise.resolve(undefined);
|
|
197
266
|
}
|
|
198
|
-
|
|
199
|
-
if (!block) {
|
|
200
|
-
return Promise.resolve(undefined);
|
|
201
|
-
}
|
|
202
|
-
return Promise.resolve(this.toCheckpointedBlock(block));
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
public async getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
206
|
-
const result: CheckpointedL2Block[] = [];
|
|
207
|
-
for (let i = 0; i < limit; i++) {
|
|
208
|
-
const blockNum = from + i;
|
|
209
|
-
if (blockNum > this.checkpointedBlockNumber) {
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
const block = await this.getCheckpointedBlock(BlockNumber(blockNum));
|
|
213
|
-
if (block) {
|
|
214
|
-
result.push(block);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return result;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Gets an l2 block.
|
|
222
|
-
* @param number - The block number to return (inclusive).
|
|
223
|
-
* @returns The requested L2 block.
|
|
224
|
-
*/
|
|
225
|
-
public getBlock(number: number): Promise<L2Block | undefined> {
|
|
226
|
-
const block = this.l2Blocks[number - 1];
|
|
227
|
-
return Promise.resolve(block);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Gets an L2 block (new format).
|
|
232
|
-
* @param number - The block number to return.
|
|
233
|
-
* @returns The requested L2 block.
|
|
234
|
-
*/
|
|
235
|
-
public getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
236
|
-
const block = this.l2Blocks[number - 1];
|
|
237
|
-
return Promise.resolve(block);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
242
|
-
* @param from - Number of the first block to return (inclusive).
|
|
243
|
-
* @param limit - The maximum number of blocks to return.
|
|
244
|
-
* @returns The requested mocked L2 blocks.
|
|
245
|
-
*/
|
|
246
|
-
public getBlocks(from: number, limit: number): Promise<L2Block[]> {
|
|
247
|
-
return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit));
|
|
267
|
+
return Promise.resolve(new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), []));
|
|
248
268
|
}
|
|
249
269
|
|
|
250
|
-
public getCheckpoints(
|
|
251
|
-
const checkpoints = this.
|
|
270
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
271
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
252
272
|
return Promise.resolve(
|
|
253
273
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
254
274
|
);
|
|
@@ -259,115 +279,65 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
259
279
|
return Promise.resolve(checkpoint);
|
|
260
280
|
}
|
|
261
281
|
|
|
262
|
-
public
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (hash.equals(blockHash)) {
|
|
266
|
-
return this.toCheckpointedBlock(block);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return undefined;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
273
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
274
|
-
if (!block) {
|
|
282
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
283
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
284
|
+
if (!checkpoint) {
|
|
275
285
|
return Promise.resolve(undefined);
|
|
276
286
|
}
|
|
277
|
-
return Promise.resolve(this.
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
281
|
-
for (const block of this.l2Blocks) {
|
|
282
|
-
const hash = await block.hash();
|
|
283
|
-
if (hash.equals(blockHash)) {
|
|
284
|
-
return block;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return undefined;
|
|
287
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
public
|
|
291
|
-
const
|
|
292
|
-
return Promise.resolve(
|
|
290
|
+
public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
291
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
292
|
+
return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
|
|
296
|
-
for (const block of this.l2Blocks) {
|
|
297
|
-
const hash = await block.hash();
|
|
298
|
-
if (hash.equals(blockHash)) {
|
|
299
|
-
return block.header;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return undefined;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
public getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
306
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
307
|
-
return Promise.resolve(block?.header);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
public async getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
311
|
-
const block = this.l2Blocks[number - 1];
|
|
312
|
-
if (!block) {
|
|
313
|
-
return undefined;
|
|
314
|
-
}
|
|
295
|
+
private checkpointToData(checkpoint: Checkpoint): CheckpointData {
|
|
315
296
|
return {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
297
|
+
checkpointNumber: checkpoint.number,
|
|
298
|
+
header: checkpoint.header,
|
|
299
|
+
archive: checkpoint.archive,
|
|
300
|
+
checkpointOutHash: computeCheckpointOutHash(
|
|
301
|
+
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
302
|
+
),
|
|
303
|
+
startBlock: checkpoint.blocks[0].number,
|
|
304
|
+
blockCount: checkpoint.blocks.length,
|
|
305
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
|
|
306
|
+
attestations: [],
|
|
307
|
+
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
321
308
|
};
|
|
322
309
|
}
|
|
323
310
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
311
|
+
private resolveCheckpointQuery(query: CheckpointQuery): Checkpoint | undefined {
|
|
312
|
+
if ('number' in query) {
|
|
313
|
+
return this.checkpointList[query.number - 1];
|
|
314
|
+
}
|
|
315
|
+
if ('slot' in query) {
|
|
316
|
+
return this.checkpointList.find(c => c.header.slotNumber === query.slot);
|
|
317
|
+
}
|
|
318
|
+
switch (query.tag) {
|
|
319
|
+
case 'checkpointed':
|
|
320
|
+
return this.checkpointList[this.checkpointList.length - 1];
|
|
321
|
+
case 'proven': {
|
|
322
|
+
const provenCheckpoint = this.checkpointList.filter(c =>
|
|
323
|
+
c.blocks.some(b => b.number <= this.provenBlockNumber),
|
|
324
|
+
);
|
|
325
|
+
return provenCheckpoint.at(-1);
|
|
326
|
+
}
|
|
327
|
+
case 'finalized': {
|
|
328
|
+
const finalizedCheckpoint = this.checkpointList.filter(c =>
|
|
329
|
+
c.blocks.some(b => b.number <= this.finalizedBlockNumber),
|
|
330
|
+
);
|
|
331
|
+
return finalizedCheckpoint.at(-1);
|
|
332
|
+
}
|
|
328
333
|
}
|
|
329
|
-
return {
|
|
330
|
-
header: block.header,
|
|
331
|
-
archive: block.archive,
|
|
332
|
-
blockHash: await block.hash(),
|
|
333
|
-
checkpointNumber: block.checkpointNumber,
|
|
334
|
-
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
|
|
339
|
-
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
343
|
-
return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
347
|
-
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
348
|
-
return Promise.resolve(
|
|
349
|
-
checkpoints.map(
|
|
350
|
-
(checkpoint): CheckpointData => ({
|
|
351
|
-
checkpointNumber: checkpoint.number,
|
|
352
|
-
header: checkpoint.header,
|
|
353
|
-
archive: checkpoint.archive,
|
|
354
|
-
checkpointOutHash: computeCheckpointOutHash(
|
|
355
|
-
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
356
|
-
),
|
|
357
|
-
startBlock: checkpoint.blocks[0].number,
|
|
358
|
-
blockCount: checkpoint.blocks.length,
|
|
359
|
-
attestations: [],
|
|
360
|
-
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
361
|
-
}),
|
|
362
|
-
),
|
|
363
|
-
);
|
|
364
334
|
}
|
|
365
335
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
);
|
|
336
|
+
private resolveCheckpointsQuery(query: CheckpointsQuery): Checkpoint[] {
|
|
337
|
+
if ('from' in query) {
|
|
338
|
+
return this.checkpointList.slice(query.from - 1, query.from - 1 + query.limit);
|
|
339
|
+
}
|
|
340
|
+
return this.getCheckpointsInEpoch(query.epoch);
|
|
371
341
|
}
|
|
372
342
|
|
|
373
343
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -375,11 +345,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
375
345
|
return Promise.resolve(blocks);
|
|
376
346
|
}
|
|
377
347
|
|
|
378
|
-
async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
379
|
-
const checkpointedBlocks = await this.getCheckpointedBlocksForEpoch(epochNumber);
|
|
380
|
-
return checkpointedBlocks.map(b => b.block.header);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
348
|
/**
|
|
384
349
|
* Gets a tx effect.
|
|
385
350
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -397,40 +362,20 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
397
362
|
data: txEffect,
|
|
398
363
|
l2BlockNumber: block.number,
|
|
399
364
|
l2BlockHash: await block.hash(),
|
|
400
|
-
txIndexInBlock: block.body.txEffects.
|
|
365
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
366
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
401
367
|
};
|
|
402
368
|
}
|
|
403
369
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
* @returns The requested tx receipt (or undefined if not found).
|
|
408
|
-
*/
|
|
409
|
-
public async getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
410
|
-
for (const block of this.l2Blocks) {
|
|
411
|
-
for (const txEffect of block.body.txEffects) {
|
|
412
|
-
if (txEffect.txHash.equals(txHash)) {
|
|
413
|
-
// In mock, assume all txs are checkpointed with successful execution
|
|
414
|
-
return new TxReceipt(
|
|
415
|
-
txHash,
|
|
416
|
-
TxStatus.CHECKPOINTED,
|
|
417
|
-
TxExecutionResult.SUCCESS,
|
|
418
|
-
undefined,
|
|
419
|
-
txEffect.transactionFee.toBigInt(),
|
|
420
|
-
await block.hash(),
|
|
421
|
-
block.number,
|
|
422
|
-
getEpochAtSlot(block.slot, EmptyL1RollupConstants),
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
return undefined;
|
|
370
|
+
public getL2ToL1MembershipWitness(): Promise<undefined> {
|
|
371
|
+
// Mock does not back the L2-to-L1 message witness flow.
|
|
372
|
+
return Promise.resolve(undefined);
|
|
428
373
|
}
|
|
429
374
|
|
|
430
375
|
async getL2Tips(): Promise<L2Tips> {
|
|
431
376
|
const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
|
|
432
377
|
await this.getBlockNumber(),
|
|
433
|
-
|
|
378
|
+
this.provenBlockNumber,
|
|
434
379
|
this.finalizedBlockNumber,
|
|
435
380
|
this.checkpointedBlockNumber,
|
|
436
381
|
await this.getProposedCheckpointL2BlockNumber(),
|
|
@@ -442,34 +387,48 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
442
387
|
const checkpointedBlock = this.l2Blocks[checkpointed - 1];
|
|
443
388
|
const proposedCheckpointBlock = this.l2Blocks[proposedCheckpoint - 1];
|
|
444
389
|
|
|
390
|
+
// For genesis tips (block number 0) report the dynamic initial header hash so consumers
|
|
391
|
+
// running L2BlockStream against this mock agree at block 0 with their local tip store.
|
|
392
|
+
const genesisHash = (await this.initialHeader.hash()).toString();
|
|
393
|
+
const tipHash = async (block: L2Block | undefined, number: number): Promise<string> => {
|
|
394
|
+
if (block) {
|
|
395
|
+
return (await block.hash()).toString();
|
|
396
|
+
}
|
|
397
|
+
return number === 0 ? genesisHash : '';
|
|
398
|
+
};
|
|
399
|
+
|
|
445
400
|
const latestBlockId = {
|
|
446
401
|
number: BlockNumber(latest),
|
|
447
|
-
hash:
|
|
402
|
+
hash: await tipHash(latestBlock, latest),
|
|
448
403
|
};
|
|
449
404
|
const provenBlockId = {
|
|
450
405
|
number: BlockNumber(proven),
|
|
451
|
-
hash:
|
|
406
|
+
hash: await tipHash(provenBlock, proven),
|
|
452
407
|
};
|
|
453
408
|
const finalizedBlockId = {
|
|
454
409
|
number: BlockNumber(finalized),
|
|
455
|
-
hash:
|
|
410
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
456
411
|
};
|
|
457
412
|
const checkpointedBlockId = {
|
|
458
413
|
number: BlockNumber(checkpointed),
|
|
459
|
-
hash:
|
|
414
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
460
415
|
};
|
|
461
416
|
const proposedCheckpointBlockId = {
|
|
462
417
|
number: BlockNumber(proposedCheckpoint),
|
|
463
|
-
hash:
|
|
418
|
+
hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint),
|
|
464
419
|
};
|
|
465
420
|
|
|
466
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
421
|
+
const makeTipId = (blockId: typeof latestBlockId) => {
|
|
422
|
+
const checkpointNumber = this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0);
|
|
423
|
+
// Match production semantics: checkpoint 0 is fully synthetic (no real checkpoint header
|
|
424
|
+
// exists at 0), so its hash stays at the protocol constant `GENESIS_CHECKPOINT_HEADER_HASH`
|
|
425
|
+
// even though the block-0 hash is dynamic. See L2TipsCache for the production path.
|
|
426
|
+
const hash = checkpointNumber === 0 ? GENESIS_CHECKPOINT_HEADER_HASH.toString() : blockId.hash;
|
|
427
|
+
return {
|
|
428
|
+
block: blockId,
|
|
429
|
+
checkpoint: { number: checkpointNumber, hash },
|
|
430
|
+
};
|
|
431
|
+
};
|
|
473
432
|
|
|
474
433
|
return {
|
|
475
434
|
proposed: latestBlockId,
|
|
@@ -496,8 +455,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
496
455
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
497
456
|
}
|
|
498
457
|
|
|
458
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
459
|
+
return Promise.resolve(false);
|
|
460
|
+
}
|
|
461
|
+
|
|
499
462
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
500
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
463
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
501
464
|
}
|
|
502
465
|
|
|
503
466
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -550,6 +513,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
550
513
|
return Promise.resolve();
|
|
551
514
|
}
|
|
552
515
|
|
|
516
|
+
async getBlock(query: BlockQuery): Promise<L2Block | undefined> {
|
|
517
|
+
if ('number' in query) {
|
|
518
|
+
if (query.number === 0) {
|
|
519
|
+
return this.getGenesisBlock();
|
|
520
|
+
}
|
|
521
|
+
return this.l2Blocks[query.number - 1];
|
|
522
|
+
}
|
|
523
|
+
if ('hash' in query) {
|
|
524
|
+
const genesis = this.getGenesisBlock();
|
|
525
|
+
if ((await genesis.hash()).equals(query.hash)) {
|
|
526
|
+
return genesis;
|
|
527
|
+
}
|
|
528
|
+
for (const b of this.l2Blocks) {
|
|
529
|
+
const hash = await b.hash();
|
|
530
|
+
if (hash.equals(query.hash)) {
|
|
531
|
+
return b;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return undefined;
|
|
535
|
+
}
|
|
536
|
+
if ('archive' in query) {
|
|
537
|
+
const genesis = this.getGenesisBlock();
|
|
538
|
+
if (genesis.archive.root.equals(query.archive)) {
|
|
539
|
+
return genesis;
|
|
540
|
+
}
|
|
541
|
+
return this.l2Blocks.find(b => b.archive.root.equals(query.archive));
|
|
542
|
+
}
|
|
543
|
+
const number = this.resolveBlockTag(query.tag);
|
|
544
|
+
if (number === 0) {
|
|
545
|
+
return this.getGenesisBlock();
|
|
546
|
+
}
|
|
547
|
+
return this.l2Blocks[number - 1];
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private resolveBlockTag(tag: BlockTag): number {
|
|
551
|
+
switch (tag) {
|
|
552
|
+
case 'latest':
|
|
553
|
+
case 'proposed':
|
|
554
|
+
return this.l2Blocks.length;
|
|
555
|
+
case 'checkpointed':
|
|
556
|
+
return this.checkpointedBlockNumber;
|
|
557
|
+
case 'proven':
|
|
558
|
+
return this.provenBlockNumber;
|
|
559
|
+
case 'finalized':
|
|
560
|
+
return this.finalizedBlockNumber;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
getBlocks(query: BlocksQuery): Promise<L2Block[]> {
|
|
565
|
+
let blocks: L2Block[];
|
|
566
|
+
if ('from' in query) {
|
|
567
|
+
blocks = this.l2Blocks.slice(query.from - 1, query.from - 1 + query.limit);
|
|
568
|
+
} else {
|
|
569
|
+
const epochCheckpoints = this.getCheckpointsInEpoch(query.epoch);
|
|
570
|
+
blocks = epochCheckpoints.flatMap(c => c.blocks);
|
|
571
|
+
}
|
|
572
|
+
if (query.onlyCheckpointed) {
|
|
573
|
+
blocks = blocks.filter(b => b.header.globalVariables.blockNumber <= this.checkpointedBlockNumber);
|
|
574
|
+
}
|
|
575
|
+
return Promise.resolve(blocks);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
async getBlockData(query: BlockQuery): Promise<BlockData | undefined> {
|
|
579
|
+
const block = await this.getBlock(query);
|
|
580
|
+
if (!block) {
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
return {
|
|
584
|
+
header: block.header,
|
|
585
|
+
archive: block.archive,
|
|
586
|
+
blockHash: await block.hash(),
|
|
587
|
+
checkpointNumber: block.checkpointNumber,
|
|
588
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
async getBlocksData(query: BlocksQuery): Promise<BlockData[]> {
|
|
593
|
+
const blocks = await this.getBlocks(query);
|
|
594
|
+
return Promise.all(
|
|
595
|
+
blocks.map(async block => ({
|
|
596
|
+
header: block.header,
|
|
597
|
+
archive: block.archive,
|
|
598
|
+
blockHash: await block.hash(),
|
|
599
|
+
checkpointNumber: block.checkpointNumber,
|
|
600
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
601
|
+
})),
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
|
|
553
605
|
isPendingChainInvalid(): Promise<boolean> {
|
|
554
606
|
return Promise.resolve(false);
|
|
555
607
|
}
|
|
@@ -558,11 +610,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
558
610
|
return Promise.resolve({ valid: true });
|
|
559
611
|
}
|
|
560
612
|
|
|
561
|
-
|
|
562
|
-
return Promise.resolve(undefined);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
getProposedCheckpointOnly(): Promise<ProposedCheckpointData | undefined> {
|
|
613
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
566
614
|
return Promise.resolve(undefined);
|
|
567
615
|
}
|
|
568
616
|
|
|
@@ -578,22 +626,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
578
626
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
579
627
|
}
|
|
580
628
|
|
|
581
|
-
/** Creates a CheckpointedL2Block from a block using stored checkpoint info. */
|
|
582
|
-
private toCheckpointedBlock(block: L2Block): CheckpointedL2Block {
|
|
583
|
-
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === block.number));
|
|
584
|
-
const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
|
|
585
|
-
return new CheckpointedL2Block(
|
|
586
|
-
checkpointNumber,
|
|
587
|
-
block,
|
|
588
|
-
new L1PublishedData(
|
|
589
|
-
BigInt(block.number),
|
|
590
|
-
BigInt(block.number),
|
|
591
|
-
`0x${block.number.toString(16).padStart(64, '0')}`,
|
|
592
|
-
),
|
|
593
|
-
[],
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
629
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
598
630
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
599
631
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|