@aztec/archiver 0.0.1-commit.f504929 → 0.0.1-commit.f5a9928
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 +19 -13
- package/dest/archiver.d.ts +73 -18
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +321 -81
- package/dest/config.d.ts +7 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +43 -14
- package/dest/errors.d.ts +55 -9
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +81 -14
- package/dest/factory.d.ts +20 -9
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +85 -37
- 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 +22 -11
- package/dest/l1/data_retrieval.d.ts +25 -11
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +25 -32
- 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 +73 -50
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +250 -144
- package/dest/modules/data_store_updater.d.ts +42 -17
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +198 -123
- 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 +14 -8
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +477 -213
- package/dest/modules/outbox_trees_resolver.d.ts +64 -0
- package/dest/modules/outbox_trees_resolver.d.ts.map +1 -0
- package/dest/modules/outbox_trees_resolver.js +184 -0
- package/dest/modules/validation.d.ts +30 -7
- package/dest/modules/validation.d.ts.map +1 -1
- package/dest/modules/validation.js +35 -17
- package/dest/store/block_store.d.ts +186 -78
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +763 -290
- package/dest/store/contract_class_store.d.ts +17 -4
- package/dest/store/contract_class_store.d.ts.map +1 -1
- package/dest/store/contract_class_store.js +42 -68
- 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 +58 -6
- 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 -7
- package/dest/store/l2_tips_cache.d.ts.map +1 -1
- package/dest/store/l2_tips_cache.js +13 -76
- package/dest/store/log_store.d.ts +42 -37
- package/dest/store/log_store.d.ts.map +1 -1
- package/dest/store/log_store.js +262 -408
- 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 +11 -1
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +51 -9
- package/dest/test/fake_l1_state.d.ts +20 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +117 -21
- package/dest/test/mock_l2_block_source.d.ts +51 -52
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +232 -180
- package/dest/test/mock_structs.d.ts +4 -1
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +15 -3
- package/dest/test/noop_l1_archiver.d.ts +17 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +31 -11
- package/package.json +15 -14
- package/src/archiver.ts +415 -90
- package/src/config.ts +51 -13
- package/src/errors.ts +122 -21
- package/src/factory.ts +99 -30
- package/src/index.ts +18 -2
- package/src/l1/calldata_retriever.ts +29 -11
- package/src/l1/data_retrieval.ts +44 -46
- 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 +327 -189
- package/src/modules/data_store_updater.ts +235 -155
- package/src/modules/instrumentation.ts +43 -10
- package/src/modules/l1_synchronizer.ts +646 -259
- package/src/modules/outbox_trees_resolver.ts +220 -0
- package/src/modules/validation.ts +80 -23
- package/src/store/block_store.ts +930 -348
- package/src/store/contract_class_store.ts +49 -103
- package/src/store/contract_instance_store.ts +74 -11
- 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 -70
- package/src/store/log_store.ts +302 -559
- package/src/store/log_store_codec.ts +143 -0
- package/src/store/message_store.ts +60 -10
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +145 -32
- package/src/test/mock_l2_block_source.ts +292 -227
- package/src/test/mock_structs.ts +25 -8
- package/src/test/noop_l1_archiver.ts +61 -12
- package/dest/store/kv_archiver_store.d.ts +0 -354
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -464
- package/src/store/kv_archiver_store.ts +0 -671
|
@@ -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,19 +15,34 @@ 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
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
Checkpoint,
|
|
35
|
+
type CheckpointData,
|
|
36
|
+
L1PublishedData,
|
|
37
|
+
type ProposedCheckpointData,
|
|
38
|
+
PublishedCheckpoint,
|
|
39
|
+
} from '@aztec/stdlib/checkpoint';
|
|
20
40
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
21
41
|
import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
22
42
|
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
23
43
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
24
|
-
import {
|
|
44
|
+
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
45
|
+
import { BlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
25
46
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
26
47
|
|
|
27
48
|
/**
|
|
@@ -35,13 +56,77 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
35
56
|
private finalizedBlockNumber: number = 0;
|
|
36
57
|
private checkpointedBlockNumber: number = 0;
|
|
37
58
|
|
|
59
|
+
private initialHeader: BlockHeader = BlockHeader.empty();
|
|
60
|
+
private initialHeaderHash: BlockHash = GENESIS_BLOCK_HEADER_HASH;
|
|
61
|
+
private genesisArchiveRoot?: Fr;
|
|
62
|
+
private genesisBlock?: L2Block;
|
|
63
|
+
|
|
38
64
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
39
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
|
+
|
|
40
119
|
/** Creates blocks grouped into single-block checkpoints. */
|
|
41
120
|
public async createBlocks(numBlocks: number) {
|
|
42
121
|
await this.createCheckpoints(numBlocks, 1);
|
|
43
122
|
}
|
|
44
123
|
|
|
124
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
125
|
+
return Promise.resolve(
|
|
126
|
+
this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
45
130
|
/** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */
|
|
46
131
|
public async createCheckpoints(numCheckpoints: number, blocksPerCheckpoint: number = 1) {
|
|
47
132
|
for (let c = 0; c < numCheckpoints; c++) {
|
|
@@ -144,80 +229,32 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
144
229
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
145
230
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
146
231
|
*/
|
|
147
|
-
public getBlockNumber()
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return Promise.resolve(BlockNumber(this.provenBlockNumber));
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
public getCheckpointedL2BlockNumber() {
|
|
156
|
-
return Promise.resolve(BlockNumber(this.checkpointedBlockNumber));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
public getFinalizedL2BlockNumber() {
|
|
160
|
-
return Promise.resolve(BlockNumber(this.finalizedBlockNumber));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
164
|
-
if (number > this.checkpointedBlockNumber) {
|
|
165
|
-
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);
|
|
166
237
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return Promise.resolve(undefined);
|
|
238
|
+
if ('number' in query) {
|
|
239
|
+
return query.number;
|
|
170
240
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
public async getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
175
|
-
const result: CheckpointedL2Block[] = [];
|
|
176
|
-
for (let i = 0; i < limit; i++) {
|
|
177
|
-
const blockNum = from + i;
|
|
178
|
-
if (blockNum > this.checkpointedBlockNumber) {
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
const block = await this.getCheckpointedBlock(BlockNumber(blockNum));
|
|
182
|
-
if (block) {
|
|
183
|
-
result.push(block);
|
|
184
|
-
}
|
|
241
|
+
if ('tag' in query) {
|
|
242
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
185
243
|
}
|
|
186
|
-
|
|
244
|
+
const block = await this.getBlock(query);
|
|
245
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
187
246
|
}
|
|
188
247
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const block = this.l2Blocks[number - 1];
|
|
196
|
-
return Promise.resolve(block);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Gets an L2 block (new format).
|
|
201
|
-
* @param number - The block number to return.
|
|
202
|
-
* @returns The requested L2 block.
|
|
203
|
-
*/
|
|
204
|
-
public getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
205
|
-
const block = this.l2Blocks[number - 1];
|
|
206
|
-
return Promise.resolve(block);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
211
|
-
* @param from - Number of the first block to return (inclusive).
|
|
212
|
-
* @param limit - The maximum number of blocks to return.
|
|
213
|
-
* @returns The requested mocked L2 blocks.
|
|
214
|
-
*/
|
|
215
|
-
public getBlocks(from: number, limit: number): Promise<L2Block[]> {
|
|
216
|
-
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), []));
|
|
217
254
|
}
|
|
218
255
|
|
|
219
|
-
public getCheckpoints(
|
|
220
|
-
const checkpoints = this.
|
|
256
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
257
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
221
258
|
return Promise.resolve(
|
|
222
259
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
223
260
|
);
|
|
@@ -228,115 +265,72 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
228
265
|
return Promise.resolve(checkpoint);
|
|
229
266
|
}
|
|
230
267
|
|
|
231
|
-
public
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (hash.equals(blockHash)) {
|
|
235
|
-
return this.toCheckpointedBlock(block);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return undefined;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
242
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
243
|
-
if (!block) {
|
|
268
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
269
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
270
|
+
if (!checkpoint) {
|
|
244
271
|
return Promise.resolve(undefined);
|
|
245
272
|
}
|
|
246
|
-
return Promise.resolve(this.
|
|
273
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
247
274
|
}
|
|
248
275
|
|
|
249
|
-
public
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (hash.equals(blockHash)) {
|
|
253
|
-
return block;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
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)));
|
|
257
279
|
}
|
|
258
280
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
+
};
|
|
262
295
|
}
|
|
263
296
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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);
|
|
269
318
|
}
|
|
270
319
|
}
|
|
271
|
-
return undefined;
|
|
272
320
|
}
|
|
273
321
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
public async getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
280
|
-
const block = this.l2Blocks[number - 1];
|
|
281
|
-
if (!block) {
|
|
282
|
-
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);
|
|
283
325
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
public async getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
294
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
295
|
-
if (!block) {
|
|
296
|
-
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);
|
|
297
332
|
}
|
|
298
|
-
return
|
|
299
|
-
header: block.header,
|
|
300
|
-
archive: block.archive,
|
|
301
|
-
blockHash: await block.hash(),
|
|
302
|
-
checkpointNumber: block.checkpointNumber,
|
|
303
|
-
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
|
|
308
|
-
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
312
|
-
return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
316
|
-
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
317
|
-
return Promise.resolve(
|
|
318
|
-
checkpoints.map(
|
|
319
|
-
(checkpoint): CheckpointData => ({
|
|
320
|
-
checkpointNumber: checkpoint.number,
|
|
321
|
-
header: checkpoint.header,
|
|
322
|
-
archive: checkpoint.archive,
|
|
323
|
-
checkpointOutHash: computeCheckpointOutHash(
|
|
324
|
-
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
325
|
-
),
|
|
326
|
-
startBlock: checkpoint.blocks[0].number,
|
|
327
|
-
blockCount: checkpoint.blocks.length,
|
|
328
|
-
attestations: [],
|
|
329
|
-
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
330
|
-
}),
|
|
331
|
-
),
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
336
|
-
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
337
|
-
return Promise.resolve(
|
|
338
|
-
checkpoints.flatMap(checkpoint => checkpoint.blocks.map(block => this.toCheckpointedBlock(block))),
|
|
339
|
-
);
|
|
333
|
+
return this.getCheckpointsInEpoch(query.epoch);
|
|
340
334
|
}
|
|
341
335
|
|
|
342
336
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -344,11 +338,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
344
338
|
return Promise.resolve(blocks);
|
|
345
339
|
}
|
|
346
340
|
|
|
347
|
-
async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
348
|
-
const checkpointedBlocks = await this.getCheckpointedBlocksForEpoch(epochNumber);
|
|
349
|
-
return checkpointedBlocks.map(b => b.block.header);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
341
|
/**
|
|
353
342
|
* Gets a tx effect.
|
|
354
343
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -366,39 +355,20 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
366
355
|
data: txEffect,
|
|
367
356
|
l2BlockNumber: block.number,
|
|
368
357
|
l2BlockHash: await block.hash(),
|
|
369
|
-
txIndexInBlock: block.body.txEffects.
|
|
358
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
359
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
370
360
|
};
|
|
371
361
|
}
|
|
372
362
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
* @returns The requested tx receipt (or undefined if not found).
|
|
377
|
-
*/
|
|
378
|
-
public async getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
379
|
-
for (const block of this.l2Blocks) {
|
|
380
|
-
for (const txEffect of block.body.txEffects) {
|
|
381
|
-
if (txEffect.txHash.equals(txHash)) {
|
|
382
|
-
// In mock, assume all txs are checkpointed with successful execution
|
|
383
|
-
return new TxReceipt(
|
|
384
|
-
txHash,
|
|
385
|
-
TxStatus.CHECKPOINTED,
|
|
386
|
-
TxExecutionResult.SUCCESS,
|
|
387
|
-
undefined,
|
|
388
|
-
txEffect.transactionFee.toBigInt(),
|
|
389
|
-
await block.hash(),
|
|
390
|
-
block.number,
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
return undefined;
|
|
363
|
+
public getL2ToL1MembershipWitness(): Promise<undefined> {
|
|
364
|
+
// Mock does not back the L2-to-L1 message witness flow.
|
|
365
|
+
return Promise.resolve(undefined);
|
|
396
366
|
}
|
|
397
367
|
|
|
398
368
|
async getL2Tips(): Promise<L2Tips> {
|
|
399
369
|
const [latest, proven, finalized, checkpointed] = [
|
|
400
370
|
await this.getBlockNumber(),
|
|
401
|
-
|
|
371
|
+
this.provenBlockNumber,
|
|
402
372
|
this.finalizedBlockNumber,
|
|
403
373
|
this.checkpointedBlockNumber,
|
|
404
374
|
] as const;
|
|
@@ -408,30 +378,44 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
408
378
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
409
379
|
const checkpointedBlock = this.l2Blocks[checkpointed - 1];
|
|
410
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
|
+
};
|
|
390
|
+
|
|
411
391
|
const latestBlockId = {
|
|
412
392
|
number: BlockNumber(latest),
|
|
413
|
-
hash:
|
|
393
|
+
hash: await tipHash(latestBlock, latest),
|
|
414
394
|
};
|
|
415
395
|
const provenBlockId = {
|
|
416
396
|
number: BlockNumber(proven),
|
|
417
|
-
hash:
|
|
397
|
+
hash: await tipHash(provenBlock, proven),
|
|
418
398
|
};
|
|
419
399
|
const finalizedBlockId = {
|
|
420
400
|
number: BlockNumber(finalized),
|
|
421
|
-
hash:
|
|
401
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
422
402
|
};
|
|
423
403
|
const checkpointedBlockId = {
|
|
424
404
|
number: BlockNumber(checkpointed),
|
|
425
|
-
hash:
|
|
405
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
426
406
|
};
|
|
427
407
|
|
|
428
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
+
};
|
|
435
419
|
|
|
436
420
|
return {
|
|
437
421
|
proposed: latestBlockId,
|
|
@@ -441,11 +425,11 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
441
425
|
};
|
|
442
426
|
}
|
|
443
427
|
|
|
444
|
-
|
|
428
|
+
getSyncedL2EpochNumber(): Promise<EpochNumber> {
|
|
445
429
|
throw new Error('Method not implemented.');
|
|
446
430
|
}
|
|
447
431
|
|
|
448
|
-
|
|
432
|
+
getSyncedL2SlotNumber(): Promise<SlotNumber> {
|
|
449
433
|
throw new Error('Method not implemented.');
|
|
450
434
|
}
|
|
451
435
|
|
|
@@ -457,8 +441,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
457
441
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
458
442
|
}
|
|
459
443
|
|
|
444
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
445
|
+
return Promise.resolve(false);
|
|
446
|
+
}
|
|
447
|
+
|
|
460
448
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
461
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
449
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
462
450
|
}
|
|
463
451
|
|
|
464
452
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -511,6 +499,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
511
499
|
return Promise.resolve();
|
|
512
500
|
}
|
|
513
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
|
+
|
|
514
591
|
isPendingChainInvalid(): Promise<boolean> {
|
|
515
592
|
return Promise.resolve(false);
|
|
516
593
|
}
|
|
@@ -519,6 +596,10 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
519
596
|
return Promise.resolve({ valid: true });
|
|
520
597
|
}
|
|
521
598
|
|
|
599
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
600
|
+
return Promise.resolve(undefined);
|
|
601
|
+
}
|
|
602
|
+
|
|
522
603
|
/** Returns checkpoints whose slot falls within the given epoch. */
|
|
523
604
|
private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
|
|
524
605
|
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
@@ -531,22 +612,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
531
612
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
532
613
|
}
|
|
533
614
|
|
|
534
|
-
/** Creates a CheckpointedL2Block from a block using stored checkpoint info. */
|
|
535
|
-
private toCheckpointedBlock(block: L2Block): CheckpointedL2Block {
|
|
536
|
-
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === block.number));
|
|
537
|
-
const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
|
|
538
|
-
return new CheckpointedL2Block(
|
|
539
|
-
checkpointNumber,
|
|
540
|
-
block,
|
|
541
|
-
new L1PublishedData(
|
|
542
|
-
BigInt(block.number),
|
|
543
|
-
BigInt(block.number),
|
|
544
|
-
`0x${block.number.toString(16).padStart(64, '0')}`,
|
|
545
|
-
),
|
|
546
|
-
[],
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
615
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
551
616
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
552
617
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|