@aztec/archiver 0.0.1-commit.4d3c002 → 0.0.1-commit.4d9804df
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 +70 -15
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +274 -71
- package/dest/config.d.ts +7 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +39 -16
- package/dest/errors.d.ts +35 -13
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +54 -16
- package/dest/factory.d.ts +11 -6
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +35 -21
- package/dest/index.d.ts +11 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +10 -2
- package/dest/l1/calldata_retriever.d.ts +9 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +20 -10
- package/dest/l1/data_retrieval.d.ts +24 -10
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +13 -19
- package/dest/l1/trace_tx.d.ts +12 -66
- package/dest/l1/trace_tx.d.ts.map +1 -1
- package/dest/l1/validate_historical_logs.d.ts +23 -0
- package/dest/l1/validate_historical_logs.d.ts.map +1 -0
- package/dest/l1/validate_historical_logs.js +108 -0
- 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 +32 -0
- package/dest/modules/data_source_base.d.ts +71 -50
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +250 -150
- package/dest/modules/data_store_updater.d.ts +28 -9
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +121 -61
- package/dest/modules/instrumentation.d.ts +15 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +48 -9
- package/dest/modules/l1_synchronizer.d.ts +11 -7
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +347 -118
- 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 +30 -7
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +33 -15
- package/dest/store/block_store.d.ts +167 -94
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +524 -260
- 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 +36 -2
- 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 +49 -1
- 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 -480
- package/dest/store/log_store_codec.d.ts +78 -0
- package/dest/store/log_store_codec.d.ts.map +1 -0
- package/dest/store/log_store_codec.js +110 -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 +7 -3
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +45 -18
- package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +1 -2
- package/dest/test/mock_l2_block_source.d.ts +47 -54
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +229 -205
- package/dest/test/mock_structs.d.ts +1 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +2 -2
- package/dest/test/noop_l1_archiver.d.ts +14 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +26 -10
- package/package.json +14 -14
- package/src/archiver.ts +355 -77
- package/src/config.ts +43 -20
- package/src/errors.ts +80 -23
- package/src/factory.ts +46 -19
- package/src/index.ts +18 -2
- package/src/l1/calldata_retriever.ts +27 -10
- package/src/l1/data_retrieval.ts +38 -36
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/modules/contract_data_source_adapter.ts +46 -0
- package/src/modules/data_source_base.ts +319 -200
- package/src/modules/data_store_updater.ts +146 -64
- package/src/modules/instrumentation.ts +43 -10
- package/src/modules/l1_synchronizer.ts +499 -136
- package/src/modules/outbox_trees_resolver.ts +199 -0
- package/src/modules/validation.ts +78 -21
- package/src/store/block_store.ts +627 -321
- package/src/store/contract_class_store.ts +47 -3
- package/src/store/contract_instance_store.ts +61 -1
- 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 -109
- package/src/store/log_store.ts +296 -652
- package/src/store/log_store_codec.ts +143 -0
- package/src/store/message_store.ts +35 -2
- package/src/test/fake_l1_state.ts +50 -27
- package/src/test/mock_l1_to_l2_message_source.ts +0 -1
- package/src/test/mock_l2_block_source.ts +276 -258
- package/src/test/mock_structs.ts +5 -2
- package/src/test/noop_l1_archiver.ts +54 -11
- package/dest/store/kv_archiver_store.d.ts +0 -377
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -494
- package/src/store/kv_archiver_store.ts +0 -713
|
@@ -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
|
/**
|
|
@@ -45,10 +55,67 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
45
55
|
private provenBlockNumber: number = 0;
|
|
46
56
|
private finalizedBlockNumber: number = 0;
|
|
47
57
|
private checkpointedBlockNumber: number = 0;
|
|
48
|
-
|
|
58
|
+
|
|
59
|
+
private initialHeader: BlockHeader = BlockHeader.empty();
|
|
60
|
+
private initialHeaderHash: BlockHash = GENESIS_BLOCK_HEADER_HASH;
|
|
61
|
+
private genesisArchiveRoot?: Fr;
|
|
62
|
+
private genesisBlock?: L2Block;
|
|
49
63
|
|
|
50
64
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
51
65
|
|
|
66
|
+
/** Returns the initial header used to synthesize block 0. */
|
|
67
|
+
public getInitialHeader(): BlockHeader {
|
|
68
|
+
return this.initialHeader;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Sets the initial header used to synthesize block 0. Tests that wire up a real
|
|
73
|
+
* world-state should call this with `worldState.getInitialHeader()` so the L2BlockStream
|
|
74
|
+
* agrees on the genesis hash on both sides. Precomputes and caches the header hash so
|
|
75
|
+
* `getGenesisBlockHash()` can return synchronously.
|
|
76
|
+
*/
|
|
77
|
+
public async setInitialHeader(header: BlockHeader): Promise<void> {
|
|
78
|
+
this.initialHeader = header;
|
|
79
|
+
this.initialHeaderHash = await header.hash();
|
|
80
|
+
this.genesisBlock = undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Returns the precomputed hash of the genesis block header. Defaults to the static
|
|
85
|
+
* {@link GENESIS_BLOCK_HEADER_HASH} unless {@link setInitialHeader} has been called with a
|
|
86
|
+
* custom header.
|
|
87
|
+
*/
|
|
88
|
+
public getGenesisBlockHash(): BlockHash {
|
|
89
|
+
return this.initialHeaderHash;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Sets the post-genesis archive root used to synthesize block 0. Mirrors the real archiver,
|
|
94
|
+
* whose synthetic block 0 carries `new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1)` rather
|
|
95
|
+
* than `AppendOnlyTreeSnapshot.empty()`. Tests wiring up a real world-state should set this so
|
|
96
|
+
* archive-based block lookups against the mock match production semantics.
|
|
97
|
+
*/
|
|
98
|
+
public setGenesisArchiveRoot(root: Fr): void {
|
|
99
|
+
this.genesisArchiveRoot = root;
|
|
100
|
+
this.genesisBlock = undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private getGenesisBlock(): L2Block {
|
|
104
|
+
if (this.genesisBlock) {
|
|
105
|
+
return this.genesisBlock;
|
|
106
|
+
}
|
|
107
|
+
const archive = this.genesisArchiveRoot
|
|
108
|
+
? new AppendOnlyTreeSnapshot(this.genesisArchiveRoot, 1)
|
|
109
|
+
: AppendOnlyTreeSnapshot.empty();
|
|
110
|
+
return (this.genesisBlock = new L2Block(
|
|
111
|
+
archive,
|
|
112
|
+
this.initialHeader,
|
|
113
|
+
Body.empty(),
|
|
114
|
+
CheckpointNumber.ZERO,
|
|
115
|
+
IndexWithinCheckpoint(0),
|
|
116
|
+
));
|
|
117
|
+
}
|
|
118
|
+
|
|
52
119
|
/** Creates blocks grouped into single-block checkpoints. */
|
|
53
120
|
public async createBlocks(numBlocks: number) {
|
|
54
121
|
await this.createCheckpoints(numBlocks, 1);
|
|
@@ -96,7 +163,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
96
163
|
});
|
|
97
164
|
// Keep tip numbers consistent with remaining blocks.
|
|
98
165
|
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
99
|
-
this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
|
|
100
166
|
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
101
167
|
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
102
168
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
@@ -113,17 +179,9 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
113
179
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
114
180
|
}
|
|
115
181
|
|
|
116
|
-
public setProposedCheckpointBlockNumber(blockNumber: number) {
|
|
117
|
-
this.proposedCheckpointBlockNumber = blockNumber;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
182
|
public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
|
|
121
183
|
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
122
184
|
this.checkpointedBlockNumber = checkpointedBlockNumber;
|
|
123
|
-
// Proposed checkpoint is always at least as advanced as checkpointed
|
|
124
|
-
if (this.proposedCheckpointBlockNumber < checkpointedBlockNumber) {
|
|
125
|
-
this.proposedCheckpointBlockNumber = checkpointedBlockNumber;
|
|
126
|
-
}
|
|
127
185
|
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
128
186
|
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
129
187
|
const newCheckpoints: Checkpoint[] = [];
|
|
@@ -171,84 +229,32 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
171
229
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
172
230
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
173
231
|
*/
|
|
174
|
-
public getBlockNumber()
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return Promise.resolve(BlockNumber(this.provenBlockNumber));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
public getCheckpointedL2BlockNumber() {
|
|
183
|
-
return Promise.resolve(BlockNumber(this.checkpointedBlockNumber));
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
public getFinalizedL2BlockNumber() {
|
|
187
|
-
return Promise.resolve(BlockNumber(this.finalizedBlockNumber));
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
public getProposedCheckpointL2BlockNumber() {
|
|
191
|
-
return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
195
|
-
if (number > this.checkpointedBlockNumber) {
|
|
196
|
-
return Promise.resolve(undefined);
|
|
232
|
+
public getBlockNumber(): Promise<BlockNumber>;
|
|
233
|
+
public getBlockNumber(query: BlockQuery): Promise<BlockNumber | undefined>;
|
|
234
|
+
public async getBlockNumber(query?: BlockQuery): Promise<BlockNumber | undefined> {
|
|
235
|
+
if (!query) {
|
|
236
|
+
return BlockNumber(this.l2Blocks.length);
|
|
197
237
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return Promise.resolve(undefined);
|
|
238
|
+
if ('number' in query) {
|
|
239
|
+
return query.number;
|
|
201
240
|
}
|
|
202
|
-
|
|
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
|
-
}
|
|
241
|
+
if ('tag' in query) {
|
|
242
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
216
243
|
}
|
|
217
|
-
|
|
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);
|
|
244
|
+
const block = await this.getBlock(query);
|
|
245
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
228
246
|
}
|
|
229
247
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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));
|
|
248
|
+
public getCheckpoint(query: CheckpointQuery): Promise<PublishedCheckpoint | undefined> {
|
|
249
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
250
|
+
if (!checkpoint) {
|
|
251
|
+
return Promise.resolve(undefined);
|
|
252
|
+
}
|
|
253
|
+
return Promise.resolve(new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), []));
|
|
248
254
|
}
|
|
249
255
|
|
|
250
|
-
public getCheckpoints(
|
|
251
|
-
const checkpoints = this.
|
|
256
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
257
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
252
258
|
return Promise.resolve(
|
|
253
259
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
254
260
|
);
|
|
@@ -259,115 +265,72 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
259
265
|
return Promise.resolve(checkpoint);
|
|
260
266
|
}
|
|
261
267
|
|
|
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) {
|
|
268
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
269
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
270
|
+
if (!checkpoint) {
|
|
275
271
|
return Promise.resolve(undefined);
|
|
276
272
|
}
|
|
277
|
-
return Promise.resolve(this.
|
|
273
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
278
274
|
}
|
|
279
275
|
|
|
280
|
-
public
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (hash.equals(blockHash)) {
|
|
284
|
-
return block;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return undefined;
|
|
276
|
+
public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
277
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
278
|
+
return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
|
|
288
279
|
}
|
|
289
280
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
281
|
+
private checkpointToData(checkpoint: Checkpoint): CheckpointData {
|
|
282
|
+
return {
|
|
283
|
+
checkpointNumber: checkpoint.number,
|
|
284
|
+
header: checkpoint.header,
|
|
285
|
+
archive: checkpoint.archive,
|
|
286
|
+
checkpointOutHash: computeCheckpointOutHash(
|
|
287
|
+
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
288
|
+
),
|
|
289
|
+
startBlock: checkpoint.blocks[0].number,
|
|
290
|
+
blockCount: checkpoint.blocks.length,
|
|
291
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
|
|
292
|
+
attestations: [],
|
|
293
|
+
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
294
|
+
};
|
|
293
295
|
}
|
|
294
296
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
private resolveCheckpointQuery(query: CheckpointQuery): Checkpoint | undefined {
|
|
298
|
+
if ('number' in query) {
|
|
299
|
+
return this.checkpointList[query.number - 1];
|
|
300
|
+
}
|
|
301
|
+
if ('slot' in query) {
|
|
302
|
+
return this.checkpointList.find(c => c.header.slotNumber === query.slot);
|
|
303
|
+
}
|
|
304
|
+
switch (query.tag) {
|
|
305
|
+
case 'checkpointed':
|
|
306
|
+
return this.checkpointList[this.checkpointList.length - 1];
|
|
307
|
+
case 'proven': {
|
|
308
|
+
const provenCheckpoint = this.checkpointList.filter(c =>
|
|
309
|
+
c.blocks.some(b => b.number <= this.provenBlockNumber),
|
|
310
|
+
);
|
|
311
|
+
return provenCheckpoint.at(-1);
|
|
312
|
+
}
|
|
313
|
+
case 'finalized': {
|
|
314
|
+
const finalizedCheckpoint = this.checkpointList.filter(c =>
|
|
315
|
+
c.blocks.some(b => b.number <= this.finalizedBlockNumber),
|
|
316
|
+
);
|
|
317
|
+
return finalizedCheckpoint.at(-1);
|
|
300
318
|
}
|
|
301
319
|
}
|
|
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
320
|
}
|
|
309
321
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return undefined;
|
|
322
|
+
private resolveCheckpointsQuery(query: CheckpointsQuery): Checkpoint[] {
|
|
323
|
+
if ('from' in query) {
|
|
324
|
+
return this.checkpointList.slice(query.from - 1, query.from - 1 + query.limit);
|
|
314
325
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
public async getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
325
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
326
|
-
if (!block) {
|
|
327
|
-
return undefined;
|
|
326
|
+
if ('fromSlot' in query) {
|
|
327
|
+
const matching = this.checkpointList.filter(c =>
|
|
328
|
+
query.reverse ? c.header.slotNumber <= query.fromSlot : c.header.slotNumber >= query.fromSlot,
|
|
329
|
+
);
|
|
330
|
+
const nearestFirst = query.reverse ? matching.reverse() : matching;
|
|
331
|
+
return nearestFirst.slice(0, query.limit);
|
|
328
332
|
}
|
|
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
|
-
}
|
|
365
|
-
|
|
366
|
-
getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
367
|
-
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
368
|
-
return Promise.resolve(
|
|
369
|
-
checkpoints.flatMap(checkpoint => checkpoint.blocks.map(block => this.toCheckpointedBlock(block))),
|
|
370
|
-
);
|
|
333
|
+
return this.getCheckpointsInEpoch(query.epoch);
|
|
371
334
|
}
|
|
372
335
|
|
|
373
336
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -375,11 +338,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
375
338
|
return Promise.resolve(blocks);
|
|
376
339
|
}
|
|
377
340
|
|
|
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
341
|
/**
|
|
384
342
|
* Gets a tx effect.
|
|
385
343
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -397,86 +355,73 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
397
355
|
data: txEffect,
|
|
398
356
|
l2BlockNumber: block.number,
|
|
399
357
|
l2BlockHash: await block.hash(),
|
|
400
|
-
txIndexInBlock: block.body.txEffects.
|
|
358
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
359
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
401
360
|
};
|
|
402
361
|
}
|
|
403
362
|
|
|
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;
|
|
363
|
+
public getL2ToL1MembershipWitness(): Promise<undefined> {
|
|
364
|
+
// Mock does not back the L2-to-L1 message witness flow.
|
|
365
|
+
return Promise.resolve(undefined);
|
|
428
366
|
}
|
|
429
367
|
|
|
430
368
|
async getL2Tips(): Promise<L2Tips> {
|
|
431
|
-
const [latest, proven, finalized, checkpointed
|
|
369
|
+
const [latest, proven, finalized, checkpointed] = [
|
|
432
370
|
await this.getBlockNumber(),
|
|
433
|
-
|
|
371
|
+
this.provenBlockNumber,
|
|
434
372
|
this.finalizedBlockNumber,
|
|
435
373
|
this.checkpointedBlockNumber,
|
|
436
|
-
await this.getProposedCheckpointL2BlockNumber(),
|
|
437
374
|
] as const;
|
|
438
375
|
|
|
439
376
|
const latestBlock = this.l2Blocks[latest - 1];
|
|
440
377
|
const provenBlock = this.l2Blocks[proven - 1];
|
|
441
378
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
442
379
|
const checkpointedBlock = this.l2Blocks[checkpointed - 1];
|
|
443
|
-
|
|
380
|
+
|
|
381
|
+
// For genesis tips (block number 0) report the dynamic initial header hash so consumers
|
|
382
|
+
// running L2BlockStream against this mock agree at block 0 with their local tip store.
|
|
383
|
+
const genesisHash = (await this.initialHeader.hash()).toString();
|
|
384
|
+
const tipHash = async (block: L2Block | undefined, number: number): Promise<string> => {
|
|
385
|
+
if (block) {
|
|
386
|
+
return (await block.hash()).toString();
|
|
387
|
+
}
|
|
388
|
+
return number === 0 ? genesisHash : '';
|
|
389
|
+
};
|
|
444
390
|
|
|
445
391
|
const latestBlockId = {
|
|
446
392
|
number: BlockNumber(latest),
|
|
447
|
-
hash:
|
|
393
|
+
hash: await tipHash(latestBlock, latest),
|
|
448
394
|
};
|
|
449
395
|
const provenBlockId = {
|
|
450
396
|
number: BlockNumber(proven),
|
|
451
|
-
hash:
|
|
397
|
+
hash: await tipHash(provenBlock, proven),
|
|
452
398
|
};
|
|
453
399
|
const finalizedBlockId = {
|
|
454
400
|
number: BlockNumber(finalized),
|
|
455
|
-
hash:
|
|
401
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
456
402
|
};
|
|
457
403
|
const checkpointedBlockId = {
|
|
458
404
|
number: BlockNumber(checkpointed),
|
|
459
|
-
hash:
|
|
460
|
-
};
|
|
461
|
-
const proposedCheckpointBlockId = {
|
|
462
|
-
number: BlockNumber(proposedCheckpoint),
|
|
463
|
-
hash: (await proposedCheckpointBlock?.hash())?.toString(),
|
|
405
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
464
406
|
};
|
|
465
407
|
|
|
466
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
408
|
+
const makeTipId = (blockId: typeof latestBlockId) => {
|
|
409
|
+
const checkpointNumber = this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0);
|
|
410
|
+
// Match production semantics: checkpoint 0 is fully synthetic (no real checkpoint header
|
|
411
|
+
// exists at 0), so its hash stays at the protocol constant `GENESIS_CHECKPOINT_HEADER_HASH`
|
|
412
|
+
// even though the block-0 hash is dynamic. See L2TipsCache for the production path.
|
|
413
|
+
const hash = checkpointNumber === 0 ? GENESIS_CHECKPOINT_HEADER_HASH.toString() : blockId.hash;
|
|
414
|
+
return {
|
|
415
|
+
block: blockId,
|
|
416
|
+
checkpoint: { number: checkpointNumber, hash },
|
|
417
|
+
};
|
|
418
|
+
};
|
|
473
419
|
|
|
474
420
|
return {
|
|
475
421
|
proposed: latestBlockId,
|
|
476
422
|
checkpointed: makeTipId(checkpointedBlockId),
|
|
477
423
|
proven: makeTipId(provenBlockId),
|
|
478
424
|
finalized: makeTipId(finalizedBlockId),
|
|
479
|
-
proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
|
|
480
425
|
};
|
|
481
426
|
}
|
|
482
427
|
|
|
@@ -496,8 +441,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
496
441
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
497
442
|
}
|
|
498
443
|
|
|
444
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
445
|
+
return Promise.resolve(false);
|
|
446
|
+
}
|
|
447
|
+
|
|
499
448
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
500
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
449
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
501
450
|
}
|
|
502
451
|
|
|
503
452
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -550,6 +499,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
550
499
|
return Promise.resolve();
|
|
551
500
|
}
|
|
552
501
|
|
|
502
|
+
async getBlock(query: BlockQuery): Promise<L2Block | undefined> {
|
|
503
|
+
if ('number' in query) {
|
|
504
|
+
if (query.number === 0) {
|
|
505
|
+
return this.getGenesisBlock();
|
|
506
|
+
}
|
|
507
|
+
return this.l2Blocks[query.number - 1];
|
|
508
|
+
}
|
|
509
|
+
if ('hash' in query) {
|
|
510
|
+
const genesis = this.getGenesisBlock();
|
|
511
|
+
if ((await genesis.hash()).equals(query.hash)) {
|
|
512
|
+
return genesis;
|
|
513
|
+
}
|
|
514
|
+
for (const b of this.l2Blocks) {
|
|
515
|
+
const hash = await b.hash();
|
|
516
|
+
if (hash.equals(query.hash)) {
|
|
517
|
+
return b;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return undefined;
|
|
521
|
+
}
|
|
522
|
+
if ('archive' in query) {
|
|
523
|
+
const genesis = this.getGenesisBlock();
|
|
524
|
+
if (genesis.archive.root.equals(query.archive)) {
|
|
525
|
+
return genesis;
|
|
526
|
+
}
|
|
527
|
+
return this.l2Blocks.find(b => b.archive.root.equals(query.archive));
|
|
528
|
+
}
|
|
529
|
+
const number = this.resolveBlockTag(query.tag);
|
|
530
|
+
if (number === 0) {
|
|
531
|
+
return this.getGenesisBlock();
|
|
532
|
+
}
|
|
533
|
+
return this.l2Blocks[number - 1];
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private resolveBlockTag(tag: BlockTag): number {
|
|
537
|
+
switch (tag) {
|
|
538
|
+
case 'latest':
|
|
539
|
+
case 'proposed':
|
|
540
|
+
return this.l2Blocks.length;
|
|
541
|
+
case 'checkpointed':
|
|
542
|
+
return this.checkpointedBlockNumber;
|
|
543
|
+
case 'proven':
|
|
544
|
+
return this.provenBlockNumber;
|
|
545
|
+
case 'finalized':
|
|
546
|
+
return this.finalizedBlockNumber;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
getBlocks(query: BlocksQuery): Promise<L2Block[]> {
|
|
551
|
+
let blocks: L2Block[];
|
|
552
|
+
if ('from' in query) {
|
|
553
|
+
blocks = this.l2Blocks.slice(query.from - 1, query.from - 1 + query.limit);
|
|
554
|
+
} else {
|
|
555
|
+
const epochCheckpoints = this.getCheckpointsInEpoch(query.epoch);
|
|
556
|
+
blocks = epochCheckpoints.flatMap(c => c.blocks);
|
|
557
|
+
}
|
|
558
|
+
if (query.onlyCheckpointed) {
|
|
559
|
+
blocks = blocks.filter(b => b.header.globalVariables.blockNumber <= this.checkpointedBlockNumber);
|
|
560
|
+
}
|
|
561
|
+
return Promise.resolve(blocks);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async getBlockData(query: BlockQuery): Promise<BlockData | undefined> {
|
|
565
|
+
const block = await this.getBlock(query);
|
|
566
|
+
if (!block) {
|
|
567
|
+
return undefined;
|
|
568
|
+
}
|
|
569
|
+
return {
|
|
570
|
+
header: block.header,
|
|
571
|
+
archive: block.archive,
|
|
572
|
+
blockHash: await block.hash(),
|
|
573
|
+
checkpointNumber: block.checkpointNumber,
|
|
574
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
async getBlocksData(query: BlocksQuery): Promise<BlockData[]> {
|
|
579
|
+
const blocks = await this.getBlocks(query);
|
|
580
|
+
return Promise.all(
|
|
581
|
+
blocks.map(async block => ({
|
|
582
|
+
header: block.header,
|
|
583
|
+
archive: block.archive,
|
|
584
|
+
blockHash: await block.hash(),
|
|
585
|
+
checkpointNumber: block.checkpointNumber,
|
|
586
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
587
|
+
})),
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
553
591
|
isPendingChainInvalid(): Promise<boolean> {
|
|
554
592
|
return Promise.resolve(false);
|
|
555
593
|
}
|
|
@@ -558,11 +596,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
558
596
|
return Promise.resolve({ valid: true });
|
|
559
597
|
}
|
|
560
598
|
|
|
561
|
-
|
|
562
|
-
return Promise.resolve(undefined);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
getProposedCheckpointOnly(): Promise<ProposedCheckpointData | undefined> {
|
|
599
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
566
600
|
return Promise.resolve(undefined);
|
|
567
601
|
}
|
|
568
602
|
|
|
@@ -578,22 +612,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
578
612
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
579
613
|
}
|
|
580
614
|
|
|
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
615
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
598
616
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
599
617
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|