@aztec/archiver 0.0.1-commit.04852196a → 0.0.1-commit.04d373f
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 +36 -19
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +250 -79
- package/dest/config.d.ts +6 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +23 -15
- 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 +12 -8
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +42 -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 +70 -46
- package/dest/modules/data_source_base.d.ts.map +1 -1
- package/dest/modules/data_source_base.js +270 -135
- package/dest/modules/data_store_updater.d.ts +39 -17
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +183 -122
- 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 +12 -7
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +430 -205
- 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 +174 -70
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +696 -250
- 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 +20 -1
- package/dest/test/fake_l1_state.d.ts.map +1 -1
- package/dest/test/fake_l1_state.js +114 -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 -46
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +243 -170
- package/dest/test/noop_l1_archiver.d.ts +12 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +26 -9
- package/package.json +14 -14
- package/src/archiver.ts +301 -86
- package/src/config.ts +32 -12
- package/src/errors.ts +122 -21
- package/src/factory.ts +50 -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 +336 -171
- package/src/modules/data_store_updater.ts +219 -154
- package/src/modules/instrumentation.ts +28 -8
- package/src/modules/l1_synchronizer.ts +566 -248
- package/src/modules/validation.ts +10 -9
- package/src/store/block_store.ts +865 -290
- 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 +142 -29
- package/src/test/mock_l1_to_l2_message_source.ts +1 -0
- package/src/test/mock_l2_block_source.ts +303 -205
- package/src/test/noop_l1_archiver.ts +39 -9
- 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,39 @@ 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
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
EmptyL1RollupConstants,
|
|
43
|
+
type L1RollupConstants,
|
|
44
|
+
getEpochAtSlot,
|
|
45
|
+
getSlotRangeForEpoch,
|
|
46
|
+
} from '@aztec/stdlib/epoch-helpers';
|
|
22
47
|
import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
|
|
23
48
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
24
|
-
import {
|
|
49
|
+
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
50
|
+
import { BlockHeader, TxExecutionResult, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
25
51
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
26
52
|
|
|
27
53
|
/**
|
|
@@ -34,9 +60,68 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
34
60
|
private provenBlockNumber: number = 0;
|
|
35
61
|
private finalizedBlockNumber: number = 0;
|
|
36
62
|
private checkpointedBlockNumber: number = 0;
|
|
63
|
+
private proposedCheckpointBlockNumber: number = 0;
|
|
64
|
+
|
|
65
|
+
private initialHeader: BlockHeader = BlockHeader.empty();
|
|
66
|
+
private initialHeaderHash: BlockHash = GENESIS_BLOCK_HEADER_HASH;
|
|
67
|
+
private genesisArchiveRoot?: Fr;
|
|
68
|
+
private genesisBlock?: L2Block;
|
|
37
69
|
|
|
38
70
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
39
71
|
|
|
72
|
+
/** Returns the initial header used to synthesize block 0. */
|
|
73
|
+
public getInitialHeader(): BlockHeader {
|
|
74
|
+
return this.initialHeader;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Sets the initial header used to synthesize block 0. Tests that wire up a real
|
|
79
|
+
* world-state should call this with `worldState.getInitialHeader()` so the L2BlockStream
|
|
80
|
+
* agrees on the genesis hash on both sides. Precomputes and caches the header hash so
|
|
81
|
+
* `getGenesisBlockHash()` can return synchronously.
|
|
82
|
+
*/
|
|
83
|
+
public async setInitialHeader(header: BlockHeader): Promise<void> {
|
|
84
|
+
this.initialHeader = header;
|
|
85
|
+
this.initialHeaderHash = await header.hash();
|
|
86
|
+
this.genesisBlock = undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns the precomputed hash of the genesis block header. Defaults to the static
|
|
91
|
+
* {@link GENESIS_BLOCK_HEADER_HASH} unless {@link setInitialHeader} has been called with a
|
|
92
|
+
* custom header.
|
|
93
|
+
*/
|
|
94
|
+
public getGenesisBlockHash(): BlockHash {
|
|
95
|
+
return this.initialHeaderHash;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Sets the post-genesis archive root used to synthesize block 0. Mirrors the real archiver,
|
|
100
|
+
* whose synthetic block 0 carries `new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1)` rather
|
|
101
|
+
* than `AppendOnlyTreeSnapshot.empty()`. Tests wiring up a real world-state should set this so
|
|
102
|
+
* archive-based block lookups against the mock match production semantics.
|
|
103
|
+
*/
|
|
104
|
+
public setGenesisArchiveRoot(root: Fr): void {
|
|
105
|
+
this.genesisArchiveRoot = root;
|
|
106
|
+
this.genesisBlock = undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private getGenesisBlock(): L2Block {
|
|
110
|
+
if (this.genesisBlock) {
|
|
111
|
+
return this.genesisBlock;
|
|
112
|
+
}
|
|
113
|
+
const archive = this.genesisArchiveRoot
|
|
114
|
+
? new AppendOnlyTreeSnapshot(this.genesisArchiveRoot, 1)
|
|
115
|
+
: AppendOnlyTreeSnapshot.empty();
|
|
116
|
+
return (this.genesisBlock = new L2Block(
|
|
117
|
+
archive,
|
|
118
|
+
this.initialHeader,
|
|
119
|
+
Body.empty(),
|
|
120
|
+
CheckpointNumber.ZERO,
|
|
121
|
+
IndexWithinCheckpoint(0),
|
|
122
|
+
));
|
|
123
|
+
}
|
|
124
|
+
|
|
40
125
|
/** Creates blocks grouped into single-block checkpoints. */
|
|
41
126
|
public async createBlocks(numBlocks: number) {
|
|
42
127
|
await this.createCheckpoints(numBlocks, 1);
|
|
@@ -84,6 +169,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
84
169
|
});
|
|
85
170
|
// Keep tip numbers consistent with remaining blocks.
|
|
86
171
|
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
172
|
+
this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
|
|
87
173
|
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
88
174
|
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
89
175
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
@@ -100,9 +186,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
100
186
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
101
187
|
}
|
|
102
188
|
|
|
189
|
+
public setProposedCheckpointBlockNumber(blockNumber: number) {
|
|
190
|
+
this.proposedCheckpointBlockNumber = blockNumber;
|
|
191
|
+
}
|
|
192
|
+
|
|
103
193
|
public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
|
|
104
194
|
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
105
195
|
this.checkpointedBlockNumber = checkpointedBlockNumber;
|
|
196
|
+
// Proposed checkpoint is always at least as advanced as checkpointed
|
|
197
|
+
if (this.proposedCheckpointBlockNumber < checkpointedBlockNumber) {
|
|
198
|
+
this.proposedCheckpointBlockNumber = checkpointedBlockNumber;
|
|
199
|
+
}
|
|
106
200
|
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
107
201
|
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
108
202
|
const newCheckpoints: Checkpoint[] = [];
|
|
@@ -150,80 +244,36 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
150
244
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
151
245
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
152
246
|
*/
|
|
153
|
-
public getBlockNumber()
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return Promise.resolve(BlockNumber(this.provenBlockNumber));
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
public getCheckpointedL2BlockNumber() {
|
|
162
|
-
return Promise.resolve(BlockNumber(this.checkpointedBlockNumber));
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
public getFinalizedL2BlockNumber() {
|
|
166
|
-
return Promise.resolve(BlockNumber(this.finalizedBlockNumber));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
170
|
-
if (number > this.checkpointedBlockNumber) {
|
|
171
|
-
return Promise.resolve(undefined);
|
|
247
|
+
public getBlockNumber(): Promise<BlockNumber>;
|
|
248
|
+
public getBlockNumber(query: BlockQuery): Promise<BlockNumber | undefined>;
|
|
249
|
+
public async getBlockNumber(query?: BlockQuery): Promise<BlockNumber | undefined> {
|
|
250
|
+
if (!query) {
|
|
251
|
+
return BlockNumber(this.l2Blocks.length);
|
|
172
252
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return Promise.resolve(undefined);
|
|
253
|
+
if ('number' in query) {
|
|
254
|
+
return query.number;
|
|
176
255
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
public async getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
181
|
-
const result: CheckpointedL2Block[] = [];
|
|
182
|
-
for (let i = 0; i < limit; i++) {
|
|
183
|
-
const blockNum = from + i;
|
|
184
|
-
if (blockNum > this.checkpointedBlockNumber) {
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
const block = await this.getCheckpointedBlock(BlockNumber(blockNum));
|
|
188
|
-
if (block) {
|
|
189
|
-
result.push(block);
|
|
190
|
-
}
|
|
256
|
+
if ('tag' in query) {
|
|
257
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
191
258
|
}
|
|
192
|
-
|
|
259
|
+
const block = await this.getBlock(query);
|
|
260
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
193
261
|
}
|
|
194
262
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
* @param number - The block number to return (inclusive).
|
|
198
|
-
* @returns The requested L2 block.
|
|
199
|
-
*/
|
|
200
|
-
public getBlock(number: number): Promise<L2Block | undefined> {
|
|
201
|
-
const block = this.l2Blocks[number - 1];
|
|
202
|
-
return Promise.resolve(block);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Gets an L2 block (new format).
|
|
207
|
-
* @param number - The block number to return.
|
|
208
|
-
* @returns The requested L2 block.
|
|
209
|
-
*/
|
|
210
|
-
public getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
211
|
-
const block = this.l2Blocks[number - 1];
|
|
212
|
-
return Promise.resolve(block);
|
|
263
|
+
public getProposedCheckpointL2BlockNumber() {
|
|
264
|
+
return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
|
|
213
265
|
}
|
|
214
266
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
public getBlocks(from: number, limit: number): Promise<L2Block[]> {
|
|
222
|
-
return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit));
|
|
267
|
+
public getCheckpoint(query: CheckpointQuery): Promise<PublishedCheckpoint | undefined> {
|
|
268
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
269
|
+
if (!checkpoint) {
|
|
270
|
+
return Promise.resolve(undefined);
|
|
271
|
+
}
|
|
272
|
+
return Promise.resolve(new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), []));
|
|
223
273
|
}
|
|
224
274
|
|
|
225
|
-
public getCheckpoints(
|
|
226
|
-
const checkpoints = this.
|
|
275
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
276
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
227
277
|
return Promise.resolve(
|
|
228
278
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
229
279
|
);
|
|
@@ -234,115 +284,65 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
234
284
|
return Promise.resolve(checkpoint);
|
|
235
285
|
}
|
|
236
286
|
|
|
237
|
-
public
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (hash.equals(blockHash)) {
|
|
241
|
-
return this.toCheckpointedBlock(block);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return undefined;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
248
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
249
|
-
if (!block) {
|
|
287
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
288
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
289
|
+
if (!checkpoint) {
|
|
250
290
|
return Promise.resolve(undefined);
|
|
251
291
|
}
|
|
252
|
-
return Promise.resolve(this.
|
|
292
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
253
293
|
}
|
|
254
294
|
|
|
255
|
-
public
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if (hash.equals(blockHash)) {
|
|
259
|
-
return block;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return undefined;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
public getL2BlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
266
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
267
|
-
return Promise.resolve(block);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
public async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
271
|
-
for (const block of this.l2Blocks) {
|
|
272
|
-
const hash = await block.hash();
|
|
273
|
-
if (hash.equals(blockHash)) {
|
|
274
|
-
return block.header;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return undefined;
|
|
295
|
+
public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
296
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
297
|
+
return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
|
|
278
298
|
}
|
|
279
299
|
|
|
280
|
-
|
|
281
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
282
|
-
return Promise.resolve(block?.header);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
public async getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
286
|
-
const block = this.l2Blocks[number - 1];
|
|
287
|
-
if (!block) {
|
|
288
|
-
return undefined;
|
|
289
|
-
}
|
|
300
|
+
private checkpointToData(checkpoint: Checkpoint): CheckpointData {
|
|
290
301
|
return {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
302
|
+
checkpointNumber: checkpoint.number,
|
|
303
|
+
header: checkpoint.header,
|
|
304
|
+
archive: checkpoint.archive,
|
|
305
|
+
checkpointOutHash: computeCheckpointOutHash(
|
|
306
|
+
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
307
|
+
),
|
|
308
|
+
startBlock: checkpoint.blocks[0].number,
|
|
309
|
+
blockCount: checkpoint.blocks.length,
|
|
310
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
|
|
311
|
+
attestations: [],
|
|
312
|
+
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
296
313
|
};
|
|
297
314
|
}
|
|
298
315
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
private resolveCheckpointQuery(query: CheckpointQuery): Checkpoint | undefined {
|
|
317
|
+
if ('number' in query) {
|
|
318
|
+
return this.checkpointList[query.number - 1];
|
|
319
|
+
}
|
|
320
|
+
if ('slot' in query) {
|
|
321
|
+
return this.checkpointList.find(c => c.header.slotNumber === query.slot);
|
|
322
|
+
}
|
|
323
|
+
switch (query.tag) {
|
|
324
|
+
case 'checkpointed':
|
|
325
|
+
return this.checkpointList[this.checkpointList.length - 1];
|
|
326
|
+
case 'proven': {
|
|
327
|
+
const provenCheckpoint = this.checkpointList.filter(c =>
|
|
328
|
+
c.blocks.some(b => b.number <= this.provenBlockNumber),
|
|
329
|
+
);
|
|
330
|
+
return provenCheckpoint.at(-1);
|
|
331
|
+
}
|
|
332
|
+
case 'finalized': {
|
|
333
|
+
const finalizedCheckpoint = this.checkpointList.filter(c =>
|
|
334
|
+
c.blocks.some(b => b.number <= this.finalizedBlockNumber),
|
|
335
|
+
);
|
|
336
|
+
return finalizedCheckpoint.at(-1);
|
|
337
|
+
}
|
|
303
338
|
}
|
|
304
|
-
return {
|
|
305
|
-
header: block.header,
|
|
306
|
-
archive: block.archive,
|
|
307
|
-
blockHash: await block.hash(),
|
|
308
|
-
checkpointNumber: block.checkpointNumber,
|
|
309
|
-
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
|
|
314
|
-
return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
318
|
-
return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
322
|
-
const checkpoints = this.getCheckpointsInEpoch(epochNumber);
|
|
323
|
-
return Promise.resolve(
|
|
324
|
-
checkpoints.map(
|
|
325
|
-
(checkpoint): CheckpointData => ({
|
|
326
|
-
checkpointNumber: checkpoint.number,
|
|
327
|
-
header: checkpoint.header,
|
|
328
|
-
archive: checkpoint.archive,
|
|
329
|
-
checkpointOutHash: computeCheckpointOutHash(
|
|
330
|
-
checkpoint.blocks.map(b => b.body.txEffects.map(tx => tx.l2ToL1Msgs)),
|
|
331
|
-
),
|
|
332
|
-
startBlock: checkpoint.blocks[0].number,
|
|
333
|
-
blockCount: checkpoint.blocks.length,
|
|
334
|
-
attestations: [],
|
|
335
|
-
l1: this.mockL1DataForCheckpoint(checkpoint),
|
|
336
|
-
}),
|
|
337
|
-
),
|
|
338
|
-
);
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
);
|
|
341
|
+
private resolveCheckpointsQuery(query: CheckpointsQuery): Checkpoint[] {
|
|
342
|
+
if ('from' in query) {
|
|
343
|
+
return this.checkpointList.slice(query.from - 1, query.from - 1 + query.limit);
|
|
344
|
+
}
|
|
345
|
+
return this.getCheckpointsInEpoch(query.epoch);
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -350,11 +350,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
350
350
|
return Promise.resolve(blocks);
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
354
|
-
const checkpointedBlocks = await this.getCheckpointedBlocksForEpoch(epochNumber);
|
|
355
|
-
return checkpointedBlocks.map(b => b.block.header);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
353
|
/**
|
|
359
354
|
* Gets a tx effect.
|
|
360
355
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -372,7 +367,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
372
367
|
data: txEffect,
|
|
373
368
|
l2BlockNumber: block.number,
|
|
374
369
|
l2BlockHash: await block.hash(),
|
|
375
|
-
txIndexInBlock: block.body.txEffects.
|
|
370
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
376
371
|
};
|
|
377
372
|
}
|
|
378
373
|
|
|
@@ -394,6 +389,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
394
389
|
txEffect.transactionFee.toBigInt(),
|
|
395
390
|
await block.hash(),
|
|
396
391
|
block.number,
|
|
392
|
+
getEpochAtSlot(block.slot, EmptyL1RollupConstants),
|
|
397
393
|
);
|
|
398
394
|
}
|
|
399
395
|
}
|
|
@@ -402,56 +398,77 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
402
398
|
}
|
|
403
399
|
|
|
404
400
|
async getL2Tips(): Promise<L2Tips> {
|
|
405
|
-
const [latest, proven, finalized, checkpointed] = [
|
|
401
|
+
const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
|
|
406
402
|
await this.getBlockNumber(),
|
|
407
|
-
|
|
403
|
+
this.provenBlockNumber,
|
|
408
404
|
this.finalizedBlockNumber,
|
|
409
405
|
this.checkpointedBlockNumber,
|
|
406
|
+
await this.getProposedCheckpointL2BlockNumber(),
|
|
410
407
|
] as const;
|
|
411
408
|
|
|
412
409
|
const latestBlock = this.l2Blocks[latest - 1];
|
|
413
410
|
const provenBlock = this.l2Blocks[proven - 1];
|
|
414
411
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
415
412
|
const checkpointedBlock = this.l2Blocks[checkpointed - 1];
|
|
413
|
+
const proposedCheckpointBlock = this.l2Blocks[proposedCheckpoint - 1];
|
|
414
|
+
|
|
415
|
+
// For genesis tips (block number 0) report the dynamic initial header hash so consumers
|
|
416
|
+
// running L2BlockStream against this mock agree at block 0 with their local tip store.
|
|
417
|
+
const genesisHash = (await this.initialHeader.hash()).toString();
|
|
418
|
+
const tipHash = async (block: L2Block | undefined, number: number): Promise<string> => {
|
|
419
|
+
if (block) {
|
|
420
|
+
return (await block.hash()).toString();
|
|
421
|
+
}
|
|
422
|
+
return number === 0 ? genesisHash : '';
|
|
423
|
+
};
|
|
416
424
|
|
|
417
425
|
const latestBlockId = {
|
|
418
426
|
number: BlockNumber(latest),
|
|
419
|
-
hash:
|
|
427
|
+
hash: await tipHash(latestBlock, latest),
|
|
420
428
|
};
|
|
421
429
|
const provenBlockId = {
|
|
422
430
|
number: BlockNumber(proven),
|
|
423
|
-
hash:
|
|
431
|
+
hash: await tipHash(provenBlock, proven),
|
|
424
432
|
};
|
|
425
433
|
const finalizedBlockId = {
|
|
426
434
|
number: BlockNumber(finalized),
|
|
427
|
-
hash:
|
|
435
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
428
436
|
};
|
|
429
437
|
const checkpointedBlockId = {
|
|
430
438
|
number: BlockNumber(checkpointed),
|
|
431
|
-
hash:
|
|
439
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
440
|
+
};
|
|
441
|
+
const proposedCheckpointBlockId = {
|
|
442
|
+
number: BlockNumber(proposedCheckpoint),
|
|
443
|
+
hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint),
|
|
432
444
|
};
|
|
433
445
|
|
|
434
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
446
|
+
const makeTipId = (blockId: typeof latestBlockId) => {
|
|
447
|
+
const checkpointNumber = this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0);
|
|
448
|
+
// Match production semantics: checkpoint 0 is fully synthetic (no real checkpoint header
|
|
449
|
+
// exists at 0), so its hash stays at the protocol constant `GENESIS_CHECKPOINT_HEADER_HASH`
|
|
450
|
+
// even though the block-0 hash is dynamic. See L2TipsCache for the production path.
|
|
451
|
+
const hash = checkpointNumber === 0 ? GENESIS_CHECKPOINT_HEADER_HASH.toString() : blockId.hash;
|
|
452
|
+
return {
|
|
453
|
+
block: blockId,
|
|
454
|
+
checkpoint: { number: checkpointNumber, hash },
|
|
455
|
+
};
|
|
456
|
+
};
|
|
441
457
|
|
|
442
458
|
return {
|
|
443
459
|
proposed: latestBlockId,
|
|
444
460
|
checkpointed: makeTipId(checkpointedBlockId),
|
|
445
461
|
proven: makeTipId(provenBlockId),
|
|
446
462
|
finalized: makeTipId(finalizedBlockId),
|
|
463
|
+
proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
|
|
447
464
|
};
|
|
448
465
|
}
|
|
449
466
|
|
|
450
|
-
|
|
467
|
+
getSyncedL2EpochNumber(): Promise<EpochNumber> {
|
|
451
468
|
throw new Error('Method not implemented.');
|
|
452
469
|
}
|
|
453
470
|
|
|
454
|
-
|
|
471
|
+
getSyncedL2SlotNumber(): Promise<SlotNumber> {
|
|
455
472
|
throw new Error('Method not implemented.');
|
|
456
473
|
}
|
|
457
474
|
|
|
@@ -463,8 +480,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
463
480
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
464
481
|
}
|
|
465
482
|
|
|
483
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
484
|
+
return Promise.resolve(false);
|
|
485
|
+
}
|
|
486
|
+
|
|
466
487
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
467
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
488
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
468
489
|
}
|
|
469
490
|
|
|
470
491
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -517,6 +538,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
517
538
|
return Promise.resolve();
|
|
518
539
|
}
|
|
519
540
|
|
|
541
|
+
async getBlock(query: BlockQuery): Promise<L2Block | undefined> {
|
|
542
|
+
if ('number' in query) {
|
|
543
|
+
if (query.number === 0) {
|
|
544
|
+
return this.getGenesisBlock();
|
|
545
|
+
}
|
|
546
|
+
return this.l2Blocks[query.number - 1];
|
|
547
|
+
}
|
|
548
|
+
if ('hash' in query) {
|
|
549
|
+
const genesis = this.getGenesisBlock();
|
|
550
|
+
if ((await genesis.hash()).equals(query.hash)) {
|
|
551
|
+
return genesis;
|
|
552
|
+
}
|
|
553
|
+
for (const b of this.l2Blocks) {
|
|
554
|
+
const hash = await b.hash();
|
|
555
|
+
if (hash.equals(query.hash)) {
|
|
556
|
+
return b;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return undefined;
|
|
560
|
+
}
|
|
561
|
+
if ('archive' in query) {
|
|
562
|
+
const genesis = this.getGenesisBlock();
|
|
563
|
+
if (genesis.archive.root.equals(query.archive)) {
|
|
564
|
+
return genesis;
|
|
565
|
+
}
|
|
566
|
+
return this.l2Blocks.find(b => b.archive.root.equals(query.archive));
|
|
567
|
+
}
|
|
568
|
+
const number = this.resolveBlockTag(query.tag);
|
|
569
|
+
if (number === 0) {
|
|
570
|
+
return this.getGenesisBlock();
|
|
571
|
+
}
|
|
572
|
+
return this.l2Blocks[number - 1];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
private resolveBlockTag(tag: BlockTag): number {
|
|
576
|
+
switch (tag) {
|
|
577
|
+
case 'latest':
|
|
578
|
+
case 'proposed':
|
|
579
|
+
return this.l2Blocks.length;
|
|
580
|
+
case 'checkpointed':
|
|
581
|
+
return this.checkpointedBlockNumber;
|
|
582
|
+
case 'proven':
|
|
583
|
+
return this.provenBlockNumber;
|
|
584
|
+
case 'finalized':
|
|
585
|
+
return this.finalizedBlockNumber;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
getBlocks(query: BlocksQuery): Promise<L2Block[]> {
|
|
590
|
+
let blocks: L2Block[];
|
|
591
|
+
if ('from' in query) {
|
|
592
|
+
blocks = this.l2Blocks.slice(query.from - 1, query.from - 1 + query.limit);
|
|
593
|
+
} else {
|
|
594
|
+
const epochCheckpoints = this.getCheckpointsInEpoch(query.epoch);
|
|
595
|
+
blocks = epochCheckpoints.flatMap(c => c.blocks);
|
|
596
|
+
}
|
|
597
|
+
if (query.onlyCheckpointed) {
|
|
598
|
+
blocks = blocks.filter(b => b.header.globalVariables.blockNumber <= this.checkpointedBlockNumber);
|
|
599
|
+
}
|
|
600
|
+
return Promise.resolve(blocks);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async getBlockData(query: BlockQuery): Promise<BlockData | undefined> {
|
|
604
|
+
const block = await this.getBlock(query);
|
|
605
|
+
if (!block) {
|
|
606
|
+
return undefined;
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
header: block.header,
|
|
610
|
+
archive: block.archive,
|
|
611
|
+
blockHash: await block.hash(),
|
|
612
|
+
checkpointNumber: block.checkpointNumber,
|
|
613
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
async getBlocksData(query: BlocksQuery): Promise<BlockData[]> {
|
|
618
|
+
const blocks = await this.getBlocks(query);
|
|
619
|
+
return Promise.all(
|
|
620
|
+
blocks.map(async block => ({
|
|
621
|
+
header: block.header,
|
|
622
|
+
archive: block.archive,
|
|
623
|
+
blockHash: await block.hash(),
|
|
624
|
+
checkpointNumber: block.checkpointNumber,
|
|
625
|
+
indexWithinCheckpoint: block.indexWithinCheckpoint,
|
|
626
|
+
})),
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
|
|
520
630
|
isPendingChainInvalid(): Promise<boolean> {
|
|
521
631
|
return Promise.resolve(false);
|
|
522
632
|
}
|
|
@@ -525,6 +635,10 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
525
635
|
return Promise.resolve({ valid: true });
|
|
526
636
|
}
|
|
527
637
|
|
|
638
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
639
|
+
return Promise.resolve(undefined);
|
|
640
|
+
}
|
|
641
|
+
|
|
528
642
|
/** Returns checkpoints whose slot falls within the given epoch. */
|
|
529
643
|
private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
|
|
530
644
|
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
@@ -537,22 +651,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
537
651
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
538
652
|
}
|
|
539
653
|
|
|
540
|
-
/** Creates a CheckpointedL2Block from a block using stored checkpoint info. */
|
|
541
|
-
private toCheckpointedBlock(block: L2Block): CheckpointedL2Block {
|
|
542
|
-
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === block.number));
|
|
543
|
-
const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
|
|
544
|
-
return new CheckpointedL2Block(
|
|
545
|
-
checkpointNumber,
|
|
546
|
-
block,
|
|
547
|
-
new L1PublishedData(
|
|
548
|
-
BigInt(block.number),
|
|
549
|
-
BigInt(block.number),
|
|
550
|
-
`0x${block.number.toString(16).padStart(64, '0')}`,
|
|
551
|
-
),
|
|
552
|
-
[],
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
654
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
557
655
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
558
656
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|