@aztec/archiver 0.0.1-commit.b33fc05d0 → 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 +19 -11
- package/dest/archiver.d.ts +53 -16
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +248 -76
- package/dest/config.d.ts +4 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +21 -14
- package/dest/errors.d.ts +50 -2
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +74 -2
- package/dest/factory.d.ts +13 -7
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +46 -32
- 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 +2 -1
- package/dest/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/l1/calldata_retriever.js +15 -5
- package/dest/l1/data_retrieval.d.ts +19 -10
- 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 +40 -0
- package/dest/modules/data_source_base.d.ts +71 -47
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +269 -137
- package/dest/modules/data_store_updater.d.ts +30 -13
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +166 -116
- package/dest/modules/instrumentation.d.ts +7 -2
- package/dest/modules/instrumentation.d.ts.map +1 -1
- package/dest/modules/instrumentation.js +25 -7
- package/dest/modules/l1_synchronizer.d.ts +11 -6
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +414 -213
- 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 +6 -6
- package/dest/store/block_store.d.ts +165 -66
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +648 -233
- 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 +24 -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 +37 -2
- 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 +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 +11 -1
- package/dest/store/message_store.d.ts.map +1 -1
- package/dest/store/message_store.js +50 -8
- package/dest/test/fake_l1_state.d.ts +15 -3
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +88 -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 +2 -1
- package/dest/test/mock_l2_block_source.d.ts +51 -50
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +244 -181
- 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 +22 -9
- package/package.json +14 -14
- package/src/archiver.ts +315 -83
- package/src/config.ts +24 -11
- package/src/errors.ts +117 -2
- package/src/factory.ts +54 -28
- package/src/index.ts +18 -2
- package/src/l1/calldata_retriever.ts +16 -5
- package/src/l1/data_retrieval.ts +36 -45
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/modules/contract_data_source_adapter.ts +55 -0
- package/src/modules/data_source_base.ts +341 -174
- package/src/modules/data_store_updater.ts +201 -147
- package/src/modules/instrumentation.ts +28 -8
- package/src/modules/l1_synchronizer.ts +549 -254
- package/src/modules/outbox_trees_resolver.ts +199 -0
- package/src/modules/validation.ts +10 -9
- package/src/store/block_store.ts +807 -285
- package/src/store/contract_class_store.ts +31 -103
- package/src/store/contract_instance_store.ts +51 -5
- 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 +301 -559
- package/src/store/log_store_codec.ts +132 -0
- package/src/store/message_store.ts +59 -9
- package/src/structs/inbox_message.ts +1 -1
- package/src/test/fake_l1_state.ts +111 -29
- package/src/test/mock_l1_to_l2_message_source.ts +1 -0
- package/src/test/mock_l2_block_source.ts +299 -232
- package/src/test/noop_l1_archiver.ts +42 -9
- package/dest/store/kv_archiver_store.d.ts +0 -363
- package/dest/store/kv_archiver_store.d.ts.map +0 -1
- package/dest/store/kv_archiver_store.js +0 -476
- package/src/store/kv_archiver_store.ts +0 -689
|
@@ -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,24 +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 { Checkpoint, type CheckpointData, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
20
|
-
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
21
33
|
import {
|
|
22
|
-
|
|
23
|
-
type
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
Checkpoint,
|
|
35
|
+
type CheckpointData,
|
|
36
|
+
L1PublishedData,
|
|
37
|
+
type ProposedCheckpointData,
|
|
38
|
+
PublishedCheckpoint,
|
|
39
|
+
} from '@aztec/stdlib/checkpoint';
|
|
40
|
+
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
41
|
+
import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
27
42
|
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
28
43
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
29
|
-
import {
|
|
44
|
+
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
45
|
+
import { BlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
30
46
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
31
47
|
|
|
32
48
|
/**
|
|
@@ -39,9 +55,68 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
39
55
|
private provenBlockNumber: number = 0;
|
|
40
56
|
private finalizedBlockNumber: number = 0;
|
|
41
57
|
private checkpointedBlockNumber: number = 0;
|
|
58
|
+
private proposedCheckpointBlockNumber: number = 0;
|
|
59
|
+
|
|
60
|
+
private initialHeader: BlockHeader = BlockHeader.empty();
|
|
61
|
+
private initialHeaderHash: BlockHash = GENESIS_BLOCK_HEADER_HASH;
|
|
62
|
+
private genesisArchiveRoot?: Fr;
|
|
63
|
+
private genesisBlock?: L2Block;
|
|
42
64
|
|
|
43
65
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
44
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
|
+
|
|
45
120
|
/** Creates blocks grouped into single-block checkpoints. */
|
|
46
121
|
public async createBlocks(numBlocks: number) {
|
|
47
122
|
await this.createCheckpoints(numBlocks, 1);
|
|
@@ -89,6 +164,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
89
164
|
});
|
|
90
165
|
// Keep tip numbers consistent with remaining blocks.
|
|
91
166
|
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
167
|
+
this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
|
|
92
168
|
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
93
169
|
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
94
170
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
@@ -105,9 +181,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
105
181
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
106
182
|
}
|
|
107
183
|
|
|
184
|
+
public setProposedCheckpointBlockNumber(blockNumber: number) {
|
|
185
|
+
this.proposedCheckpointBlockNumber = blockNumber;
|
|
186
|
+
}
|
|
187
|
+
|
|
108
188
|
public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
|
|
109
189
|
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
110
190
|
this.checkpointedBlockNumber = checkpointedBlockNumber;
|
|
191
|
+
// Proposed checkpoint is always at least as advanced as checkpointed
|
|
192
|
+
if (this.proposedCheckpointBlockNumber < checkpointedBlockNumber) {
|
|
193
|
+
this.proposedCheckpointBlockNumber = checkpointedBlockNumber;
|
|
194
|
+
}
|
|
111
195
|
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
112
196
|
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
113
197
|
const newCheckpoints: Checkpoint[] = [];
|
|
@@ -155,80 +239,36 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
155
239
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
156
240
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
157
241
|
*/
|
|
158
|
-
public getBlockNumber()
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return Promise.resolve(BlockNumber(this.provenBlockNumber));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
public getCheckpointedL2BlockNumber() {
|
|
167
|
-
return Promise.resolve(BlockNumber(this.checkpointedBlockNumber));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
public getFinalizedL2BlockNumber() {
|
|
171
|
-
return Promise.resolve(BlockNumber(this.finalizedBlockNumber));
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
175
|
-
if (number > this.checkpointedBlockNumber) {
|
|
176
|
-
return Promise.resolve(undefined);
|
|
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);
|
|
177
247
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return Promise.resolve(undefined);
|
|
248
|
+
if ('number' in query) {
|
|
249
|
+
return query.number;
|
|
181
250
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
public async getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
186
|
-
const result: CheckpointedL2Block[] = [];
|
|
187
|
-
for (let i = 0; i < limit; i++) {
|
|
188
|
-
const blockNum = from + i;
|
|
189
|
-
if (blockNum > this.checkpointedBlockNumber) {
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
const block = await this.getCheckpointedBlock(BlockNumber(blockNum));
|
|
193
|
-
if (block) {
|
|
194
|
-
result.push(block);
|
|
195
|
-
}
|
|
251
|
+
if ('tag' in query) {
|
|
252
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
196
253
|
}
|
|
197
|
-
|
|
254
|
+
const block = await this.getBlock(query);
|
|
255
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
198
256
|
}
|
|
199
257
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
* @param number - The block number to return (inclusive).
|
|
203
|
-
* @returns The requested L2 block.
|
|
204
|
-
*/
|
|
205
|
-
public getBlock(number: number): Promise<L2Block | undefined> {
|
|
206
|
-
const block = this.l2Blocks[number - 1];
|
|
207
|
-
return Promise.resolve(block);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Gets an L2 block (new format).
|
|
212
|
-
* @param number - The block number to return.
|
|
213
|
-
* @returns The requested L2 block.
|
|
214
|
-
*/
|
|
215
|
-
public getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
216
|
-
const block = this.l2Blocks[number - 1];
|
|
217
|
-
return Promise.resolve(block);
|
|
258
|
+
public getProposedCheckpointL2BlockNumber() {
|
|
259
|
+
return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
|
|
218
260
|
}
|
|
219
261
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
public getBlocks(from: number, limit: number): Promise<L2Block[]> {
|
|
227
|
-
return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit));
|
|
262
|
+
public getCheckpoint(query: CheckpointQuery): Promise<PublishedCheckpoint | undefined> {
|
|
263
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
264
|
+
if (!checkpoint) {
|
|
265
|
+
return Promise.resolve(undefined);
|
|
266
|
+
}
|
|
267
|
+
return Promise.resolve(new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), []));
|
|
228
268
|
}
|
|
229
269
|
|
|
230
|
-
public getCheckpoints(
|
|
231
|
-
const checkpoints = this.
|
|
270
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
271
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
232
272
|
return Promise.resolve(
|
|
233
273
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
234
274
|
);
|
|
@@ -239,115 +279,65 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
239
279
|
return Promise.resolve(checkpoint);
|
|
240
280
|
}
|
|
241
281
|
|
|
242
|
-
public
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (hash.equals(blockHash)) {
|
|
246
|
-
return this.toCheckpointedBlock(block);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return undefined;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
253
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
254
|
-
if (!block) {
|
|
282
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
283
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
284
|
+
if (!checkpoint) {
|
|
255
285
|
return Promise.resolve(undefined);
|
|
256
286
|
}
|
|
257
|
-
return Promise.resolve(this.
|
|
287
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
258
288
|
}
|
|
259
289
|
|
|
260
|
-
public
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (hash.equals(blockHash)) {
|
|
264
|
-
return block;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return undefined;
|
|
290
|
+
public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
291
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
292
|
+
return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
|
|
268
293
|
}
|
|
269
294
|
|
|
270
|
-
|
|
271
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
272
|
-
return Promise.resolve(block);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
public async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
276
|
-
for (const block of this.l2Blocks) {
|
|
277
|
-
const hash = await block.hash();
|
|
278
|
-
if (hash.equals(blockHash)) {
|
|
279
|
-
return block.header;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return undefined;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
public getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
286
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
287
|
-
return Promise.resolve(block?.header);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
public async getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
291
|
-
const block = this.l2Blocks[number - 1];
|
|
292
|
-
if (!block) {
|
|
293
|
-
return undefined;
|
|
294
|
-
}
|
|
295
|
+
private checkpointToData(checkpoint: Checkpoint): CheckpointData {
|
|
295
296
|
return {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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),
|
|
301
308
|
};
|
|
302
309
|
}
|
|
303
310
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
+
}
|
|
308
333
|
}
|
|
309
|
-
return {
|
|
310
|
-
header: block.header,
|
|
311
|
-
archive: block.archive,
|
|
312
|
-
blockHash: await block.hash(),
|
|
313
|
-
checkpointNumber: block.checkpointNumber,
|
|
314
|
-
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
|
|
319
|
-
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
323
|
-
return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
327
|
-
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
328
|
-
return Promise.resolve(
|
|
329
|
-
checkpoints.map(
|
|
330
|
-
(checkpoint): CheckpointData => ({
|
|
331
|
-
checkpointNumber: checkpoint.number,
|
|
332
|
-
header: checkpoint.header,
|
|
333
|
-
archive: checkpoint.archive,
|
|
334
|
-
checkpointOutHash: computeCheckpointOutHash(
|
|
335
|
-
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
336
|
-
),
|
|
337
|
-
startBlock: checkpoint.blocks[0].number,
|
|
338
|
-
blockCount: checkpoint.blocks.length,
|
|
339
|
-
attestations: [],
|
|
340
|
-
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
341
|
-
}),
|
|
342
|
-
),
|
|
343
|
-
);
|
|
344
334
|
}
|
|
345
335
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
);
|
|
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);
|
|
351
341
|
}
|
|
352
342
|
|
|
353
343
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -355,11 +345,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
355
345
|
return Promise.resolve(blocks);
|
|
356
346
|
}
|
|
357
347
|
|
|
358
|
-
async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
359
|
-
const checkpointedBlocks = await this.getCheckpointedBlocksForEpoch(epochNumber);
|
|
360
|
-
return checkpointedBlocks.map(b => b.block.header);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
348
|
/**
|
|
364
349
|
* Gets a tx effect.
|
|
365
350
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -377,79 +362,80 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
377
362
|
data: txEffect,
|
|
378
363
|
l2BlockNumber: block.number,
|
|
379
364
|
l2BlockHash: await block.hash(),
|
|
380
|
-
txIndexInBlock: block.body.txEffects.
|
|
365
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
366
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
381
367
|
};
|
|
382
368
|
}
|
|
383
369
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
* @returns The requested tx receipt (or undefined if not found).
|
|
388
|
-
*/
|
|
389
|
-
public async getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
390
|
-
for (const block of this.l2Blocks) {
|
|
391
|
-
for (const txEffect of block.body.txEffects) {
|
|
392
|
-
if (txEffect.txHash.equals(txHash)) {
|
|
393
|
-
// In mock, assume all txs are checkpointed with successful execution
|
|
394
|
-
return new TxReceipt(
|
|
395
|
-
txHash,
|
|
396
|
-
TxStatus.CHECKPOINTED,
|
|
397
|
-
TxExecutionResult.SUCCESS,
|
|
398
|
-
undefined,
|
|
399
|
-
txEffect.transactionFee.toBigInt(),
|
|
400
|
-
await block.hash(),
|
|
401
|
-
block.number,
|
|
402
|
-
getEpochAtSlot(block.slot, EmptyL1RollupConstants),
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return undefined;
|
|
370
|
+
public getL2ToL1MembershipWitness(): Promise<undefined> {
|
|
371
|
+
// Mock does not back the L2-to-L1 message witness flow.
|
|
372
|
+
return Promise.resolve(undefined);
|
|
408
373
|
}
|
|
409
374
|
|
|
410
375
|
async getL2Tips(): Promise<L2Tips> {
|
|
411
|
-
const [latest, proven, finalized, checkpointed] = [
|
|
376
|
+
const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
|
|
412
377
|
await this.getBlockNumber(),
|
|
413
|
-
|
|
378
|
+
this.provenBlockNumber,
|
|
414
379
|
this.finalizedBlockNumber,
|
|
415
380
|
this.checkpointedBlockNumber,
|
|
381
|
+
await this.getProposedCheckpointL2BlockNumber(),
|
|
416
382
|
] as const;
|
|
417
383
|
|
|
418
384
|
const latestBlock = this.l2Blocks[latest - 1];
|
|
419
385
|
const provenBlock = this.l2Blocks[proven - 1];
|
|
420
386
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
421
387
|
const checkpointedBlock = this.l2Blocks[checkpointed - 1];
|
|
388
|
+
const proposedCheckpointBlock = this.l2Blocks[proposedCheckpoint - 1];
|
|
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
|
+
};
|
|
422
399
|
|
|
423
400
|
const latestBlockId = {
|
|
424
401
|
number: BlockNumber(latest),
|
|
425
|
-
hash:
|
|
402
|
+
hash: await tipHash(latestBlock, latest),
|
|
426
403
|
};
|
|
427
404
|
const provenBlockId = {
|
|
428
405
|
number: BlockNumber(proven),
|
|
429
|
-
hash:
|
|
406
|
+
hash: await tipHash(provenBlock, proven),
|
|
430
407
|
};
|
|
431
408
|
const finalizedBlockId = {
|
|
432
409
|
number: BlockNumber(finalized),
|
|
433
|
-
hash:
|
|
410
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
434
411
|
};
|
|
435
412
|
const checkpointedBlockId = {
|
|
436
413
|
number: BlockNumber(checkpointed),
|
|
437
|
-
hash:
|
|
414
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
415
|
+
};
|
|
416
|
+
const proposedCheckpointBlockId = {
|
|
417
|
+
number: BlockNumber(proposedCheckpoint),
|
|
418
|
+
hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint),
|
|
438
419
|
};
|
|
439
420
|
|
|
440
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
+
};
|
|
447
432
|
|
|
448
433
|
return {
|
|
449
434
|
proposed: latestBlockId,
|
|
450
435
|
checkpointed: makeTipId(checkpointedBlockId),
|
|
451
436
|
proven: makeTipId(provenBlockId),
|
|
452
437
|
finalized: makeTipId(finalizedBlockId),
|
|
438
|
+
proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
|
|
453
439
|
};
|
|
454
440
|
}
|
|
455
441
|
|
|
@@ -469,8 +455,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
469
455
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
470
456
|
}
|
|
471
457
|
|
|
458
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
459
|
+
return Promise.resolve(false);
|
|
460
|
+
}
|
|
461
|
+
|
|
472
462
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
473
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
463
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
474
464
|
}
|
|
475
465
|
|
|
476
466
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -523,6 +513,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
523
513
|
return Promise.resolve();
|
|
524
514
|
}
|
|
525
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
|
+
|
|
526
605
|
isPendingChainInvalid(): Promise<boolean> {
|
|
527
606
|
return Promise.resolve(false);
|
|
528
607
|
}
|
|
@@ -531,6 +610,10 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
531
610
|
return Promise.resolve({ valid: true });
|
|
532
611
|
}
|
|
533
612
|
|
|
613
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
614
|
+
return Promise.resolve(undefined);
|
|
615
|
+
}
|
|
616
|
+
|
|
534
617
|
/** Returns checkpoints whose slot falls within the given epoch. */
|
|
535
618
|
private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
|
|
536
619
|
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
@@ -543,22 +626,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
543
626
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
544
627
|
}
|
|
545
628
|
|
|
546
|
-
/** Creates a CheckpointedL2Block from a block using stored checkpoint info. */
|
|
547
|
-
private toCheckpointedBlock(block: L2Block): CheckpointedL2Block {
|
|
548
|
-
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === block.number));
|
|
549
|
-
const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
|
|
550
|
-
return new CheckpointedL2Block(
|
|
551
|
-
checkpointNumber,
|
|
552
|
-
block,
|
|
553
|
-
new L1PublishedData(
|
|
554
|
-
BigInt(block.number),
|
|
555
|
-
BigInt(block.number),
|
|
556
|
-
`0x${block.number.toString(16).padStart(64, '0')}`,
|
|
557
|
-
),
|
|
558
|
-
[],
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
629
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
563
630
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
564
631
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|