@aztec/archiver 0.0.1-commit.181e2d196 → 0.0.1-commit.189eedb3
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 +55 -18
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +276 -79
- 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 +55 -9
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +81 -14
- package/dest/factory.d.ts +14 -9
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +51 -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 +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 +73 -49
- 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 +42 -17
- package/dest/modules/data_store_updater.d.ts.map +1 -1
- package/dest/modules/data_store_updater.js +191 -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 -6
- package/dest/modules/l1_synchronizer.d.ts.map +1 -1
- package/dest/modules/l1_synchronizer.js +432 -205
- 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 +174 -76
- package/dest/store/block_store.d.ts.map +1 -1
- package/dest/store/block_store.js +692 -277
- 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 +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 +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 +54 -52
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +248 -182
- 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 +13 -1
- package/dest/test/noop_l1_archiver.d.ts +13 -6
- package/dest/test/noop_l1_archiver.d.ts.map +1 -1
- package/dest/test/noop_l1_archiver.js +27 -10
- package/package.json +14 -14
- package/src/archiver.ts +347 -88
- package/src/config.ts +24 -11
- package/src/errors.ts +122 -21
- package/src/factory.ts +58 -31
- 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 +343 -176
- package/src/modules/data_store_updater.ts +224 -154
- package/src/modules/instrumentation.ts +28 -8
- package/src/modules/l1_synchronizer.ts +572 -248
- package/src/modules/outbox_trees_resolver.ts +199 -0
- package/src/modules/validation.ts +10 -9
- package/src/store/block_store.ts +858 -333
- 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 +60 -10
- 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 +306 -227
- package/src/test/mock_structs.ts +20 -6
- package/src/test/noop_l1_archiver.ts +49 -10
- 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
|
/**
|
|
@@ -34,14 +55,79 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
34
55
|
private provenBlockNumber: number = 0;
|
|
35
56
|
private finalizedBlockNumber: number = 0;
|
|
36
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;
|
|
37
64
|
|
|
38
65
|
private log = createLogger('archiver:mock_l2_block_source');
|
|
39
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
|
+
|
|
40
120
|
/** Creates blocks grouped into single-block checkpoints. */
|
|
41
121
|
public async createBlocks(numBlocks: number) {
|
|
42
122
|
await this.createCheckpoints(numBlocks, 1);
|
|
43
123
|
}
|
|
44
124
|
|
|
125
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
126
|
+
return Promise.resolve(
|
|
127
|
+
this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
45
131
|
/** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */
|
|
46
132
|
public async createCheckpoints(numCheckpoints: number, blocksPerCheckpoint: number = 1) {
|
|
47
133
|
for (let c = 0; c < numCheckpoints; c++) {
|
|
@@ -78,6 +164,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
78
164
|
});
|
|
79
165
|
// Keep tip numbers consistent with remaining blocks.
|
|
80
166
|
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
167
|
+
this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
|
|
81
168
|
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
82
169
|
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
83
170
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
@@ -94,9 +181,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
94
181
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
95
182
|
}
|
|
96
183
|
|
|
184
|
+
public setProposedCheckpointBlockNumber(blockNumber: number) {
|
|
185
|
+
this.proposedCheckpointBlockNumber = blockNumber;
|
|
186
|
+
}
|
|
187
|
+
|
|
97
188
|
public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
|
|
98
189
|
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
99
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
|
+
}
|
|
100
195
|
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
101
196
|
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
102
197
|
const newCheckpoints: Checkpoint[] = [];
|
|
@@ -144,80 +239,36 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
144
239
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
145
240
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
146
241
|
*/
|
|
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);
|
|
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);
|
|
166
247
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return Promise.resolve(undefined);
|
|
248
|
+
if ('number' in query) {
|
|
249
|
+
return query.number;
|
|
170
250
|
}
|
|
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
|
-
}
|
|
251
|
+
if ('tag' in query) {
|
|
252
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
185
253
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Gets an l2 block.
|
|
191
|
-
* @param number - The block number to return (inclusive).
|
|
192
|
-
* @returns The requested L2 block.
|
|
193
|
-
*/
|
|
194
|
-
public getBlock(number: number): Promise<L2Block | undefined> {
|
|
195
|
-
const block = this.l2Blocks[number - 1];
|
|
196
|
-
return Promise.resolve(block);
|
|
254
|
+
const block = await this.getBlock(query);
|
|
255
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
197
256
|
}
|
|
198
257
|
|
|
199
|
-
|
|
200
|
-
|
|
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);
|
|
258
|
+
public getProposedCheckpointL2BlockNumber() {
|
|
259
|
+
return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
|
|
207
260
|
}
|
|
208
261
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
public getBlocks(from: number, limit: number): Promise<L2Block[]> {
|
|
216
|
-
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), []));
|
|
217
268
|
}
|
|
218
269
|
|
|
219
|
-
public getCheckpoints(
|
|
220
|
-
const checkpoints = this.
|
|
270
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
271
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
221
272
|
return Promise.resolve(
|
|
222
273
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
223
274
|
);
|
|
@@ -228,115 +279,65 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
228
279
|
return Promise.resolve(checkpoint);
|
|
229
280
|
}
|
|
230
281
|
|
|
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) {
|
|
282
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
283
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
284
|
+
if (!checkpoint) {
|
|
244
285
|
return Promise.resolve(undefined);
|
|
245
286
|
}
|
|
246
|
-
return Promise.resolve(this.
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
250
|
-
for (const block of this.l2Blocks) {
|
|
251
|
-
const hash = await block.hash();
|
|
252
|
-
if (hash.equals(blockHash)) {
|
|
253
|
-
return block;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return undefined;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
public getL2BlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
260
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
261
|
-
return Promise.resolve(block);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
public async getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
265
|
-
for (const block of this.l2Blocks) {
|
|
266
|
-
const hash = await block.hash();
|
|
267
|
-
if (hash.equals(blockHash)) {
|
|
268
|
-
return block.header;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return undefined;
|
|
287
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
272
288
|
}
|
|
273
289
|
|
|
274
|
-
public
|
|
275
|
-
const
|
|
276
|
-
return Promise.resolve(
|
|
290
|
+
public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
291
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
292
|
+
return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
|
|
277
293
|
}
|
|
278
294
|
|
|
279
|
-
|
|
280
|
-
const block = this.l2Blocks[number - 1];
|
|
281
|
-
if (!block) {
|
|
282
|
-
return undefined;
|
|
283
|
-
}
|
|
295
|
+
private checkpointToData(checkpoint: Checkpoint): CheckpointData {
|
|
284
296
|
return {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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),
|
|
290
308
|
};
|
|
291
309
|
}
|
|
292
310
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
+
}
|
|
297
333
|
}
|
|
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
|
}
|
|
334
335
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
);
|
|
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);
|
|
340
341
|
}
|
|
341
342
|
|
|
342
343
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -344,11 +345,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
344
345
|
return Promise.resolve(blocks);
|
|
345
346
|
}
|
|
346
347
|
|
|
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
348
|
/**
|
|
353
349
|
* Gets a tx effect.
|
|
354
350
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -366,86 +362,88 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
366
362
|
data: txEffect,
|
|
367
363
|
l2BlockNumber: block.number,
|
|
368
364
|
l2BlockHash: await block.hash(),
|
|
369
|
-
txIndexInBlock: block.body.txEffects.
|
|
365
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
366
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
370
367
|
};
|
|
371
368
|
}
|
|
372
369
|
|
|
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;
|
|
370
|
+
public getL2ToL1MembershipWitness(): Promise<undefined> {
|
|
371
|
+
// Mock does not back the L2-to-L1 message witness flow.
|
|
372
|
+
return Promise.resolve(undefined);
|
|
396
373
|
}
|
|
397
374
|
|
|
398
375
|
async getL2Tips(): Promise<L2Tips> {
|
|
399
|
-
const [latest, proven, finalized, checkpointed] = [
|
|
376
|
+
const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
|
|
400
377
|
await this.getBlockNumber(),
|
|
401
|
-
|
|
378
|
+
this.provenBlockNumber,
|
|
402
379
|
this.finalizedBlockNumber,
|
|
403
380
|
this.checkpointedBlockNumber,
|
|
381
|
+
await this.getProposedCheckpointL2BlockNumber(),
|
|
404
382
|
] as const;
|
|
405
383
|
|
|
406
384
|
const latestBlock = this.l2Blocks[latest - 1];
|
|
407
385
|
const provenBlock = this.l2Blocks[proven - 1];
|
|
408
386
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
409
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
|
+
};
|
|
410
399
|
|
|
411
400
|
const latestBlockId = {
|
|
412
401
|
number: BlockNumber(latest),
|
|
413
|
-
hash:
|
|
402
|
+
hash: await tipHash(latestBlock, latest),
|
|
414
403
|
};
|
|
415
404
|
const provenBlockId = {
|
|
416
405
|
number: BlockNumber(proven),
|
|
417
|
-
hash:
|
|
406
|
+
hash: await tipHash(provenBlock, proven),
|
|
418
407
|
};
|
|
419
408
|
const finalizedBlockId = {
|
|
420
409
|
number: BlockNumber(finalized),
|
|
421
|
-
hash:
|
|
410
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
422
411
|
};
|
|
423
412
|
const checkpointedBlockId = {
|
|
424
413
|
number: BlockNumber(checkpointed),
|
|
425
|
-
hash:
|
|
414
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
415
|
+
};
|
|
416
|
+
const proposedCheckpointBlockId = {
|
|
417
|
+
number: BlockNumber(proposedCheckpoint),
|
|
418
|
+
hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint),
|
|
426
419
|
};
|
|
427
420
|
|
|
428
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
+
};
|
|
435
432
|
|
|
436
433
|
return {
|
|
437
434
|
proposed: latestBlockId,
|
|
438
435
|
checkpointed: makeTipId(checkpointedBlockId),
|
|
439
436
|
proven: makeTipId(provenBlockId),
|
|
440
437
|
finalized: makeTipId(finalizedBlockId),
|
|
438
|
+
proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
|
|
441
439
|
};
|
|
442
440
|
}
|
|
443
441
|
|
|
444
|
-
|
|
442
|
+
getSyncedL2EpochNumber(): Promise<EpochNumber> {
|
|
445
443
|
throw new Error('Method not implemented.');
|
|
446
444
|
}
|
|
447
445
|
|
|
448
|
-
|
|
446
|
+
getSyncedL2SlotNumber(): Promise<SlotNumber> {
|
|
449
447
|
throw new Error('Method not implemented.');
|
|
450
448
|
}
|
|
451
449
|
|
|
@@ -457,8 +455,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
457
455
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
458
456
|
}
|
|
459
457
|
|
|
458
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
459
|
+
return Promise.resolve(false);
|
|
460
|
+
}
|
|
461
|
+
|
|
460
462
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
461
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
463
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
462
464
|
}
|
|
463
465
|
|
|
464
466
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -511,6 +513,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
511
513
|
return Promise.resolve();
|
|
512
514
|
}
|
|
513
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
|
+
|
|
514
605
|
isPendingChainInvalid(): Promise<boolean> {
|
|
515
606
|
return Promise.resolve(false);
|
|
516
607
|
}
|
|
@@ -519,6 +610,10 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
519
610
|
return Promise.resolve({ valid: true });
|
|
520
611
|
}
|
|
521
612
|
|
|
613
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
614
|
+
return Promise.resolve(undefined);
|
|
615
|
+
}
|
|
616
|
+
|
|
522
617
|
/** Returns checkpoints whose slot falls within the given epoch. */
|
|
523
618
|
private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
|
|
524
619
|
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
@@ -531,22 +626,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
531
626
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
532
627
|
}
|
|
533
628
|
|
|
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
629
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
551
630
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
552
631
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|