@aztec/archiver 0.0.1-commit.96dac018d → 0.0.1-commit.993d240
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 -17
- package/dest/archiver.d.ts.map +1 -1
- package/dest/archiver.js +257 -75
- 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 +13 -9
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +47 -35
- 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 +24 -12
- package/dest/l1/data_retrieval.d.ts.map +1 -1
- package/dest/l1/data_retrieval.js +36 -37
- 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 +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/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 +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 +52 -46
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +246 -170
- 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 +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 +313 -75
- package/src/config.ts +32 -12
- package/src/errors.ts +122 -21
- package/src/factory.ts +54 -29
- package/src/index.ts +18 -2
- package/src/l1/calldata_retriever.ts +16 -5
- package/src/l1/data_retrieval.ts +52 -53
- 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 +224 -154
- package/src/modules/instrumentation.ts +28 -8
- package/src/modules/l1_synchronizer.ts +572 -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 +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 +309 -205
- package/src/test/mock_structs.ts +20 -6
- 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,14 +60,79 @@ 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);
|
|
43
128
|
}
|
|
44
129
|
|
|
130
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
131
|
+
return Promise.resolve(
|
|
132
|
+
this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
45
136
|
/** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */
|
|
46
137
|
public async createCheckpoints(numCheckpoints: number, blocksPerCheckpoint: number = 1) {
|
|
47
138
|
for (let c = 0; c < numCheckpoints; c++) {
|
|
@@ -78,6 +169,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
78
169
|
});
|
|
79
170
|
// Keep tip numbers consistent with remaining blocks.
|
|
80
171
|
this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
|
|
172
|
+
this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
|
|
81
173
|
this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
|
|
82
174
|
this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
|
|
83
175
|
this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
|
|
@@ -94,9 +186,17 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
94
186
|
this.finalizedBlockNumber = finalizedBlockNumber;
|
|
95
187
|
}
|
|
96
188
|
|
|
189
|
+
public setProposedCheckpointBlockNumber(blockNumber: number) {
|
|
190
|
+
this.proposedCheckpointBlockNumber = blockNumber;
|
|
191
|
+
}
|
|
192
|
+
|
|
97
193
|
public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
|
|
98
194
|
const prevCheckpointed = this.checkpointedBlockNumber;
|
|
99
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
|
+
}
|
|
100
200
|
// Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
|
|
101
201
|
// This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
|
|
102
202
|
const newCheckpoints: Checkpoint[] = [];
|
|
@@ -144,80 +244,36 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
144
244
|
* Gets the number of the latest L2 block processed by the block source implementation.
|
|
145
245
|
* @returns In this mock instance, returns the number of L2 blocks that we've mocked.
|
|
146
246
|
*/
|
|
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);
|
|
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);
|
|
166
252
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return Promise.resolve(undefined);
|
|
253
|
+
if ('number' in query) {
|
|
254
|
+
return query.number;
|
|
170
255
|
}
|
|
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
|
-
}
|
|
256
|
+
if ('tag' in query) {
|
|
257
|
+
return BlockNumber(this.resolveBlockTag(query.tag));
|
|
185
258
|
}
|
|
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);
|
|
259
|
+
const block = await this.getBlock(query);
|
|
260
|
+
return block ? block.header.globalVariables.blockNumber : undefined;
|
|
197
261
|
}
|
|
198
262
|
|
|
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);
|
|
263
|
+
public getProposedCheckpointL2BlockNumber() {
|
|
264
|
+
return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
|
|
207
265
|
}
|
|
208
266
|
|
|
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));
|
|
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), []));
|
|
217
273
|
}
|
|
218
274
|
|
|
219
|
-
public getCheckpoints(
|
|
220
|
-
const checkpoints = this.
|
|
275
|
+
public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
|
|
276
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
221
277
|
return Promise.resolve(
|
|
222
278
|
checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
|
|
223
279
|
);
|
|
@@ -228,115 +284,65 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
228
284
|
return Promise.resolve(checkpoint);
|
|
229
285
|
}
|
|
230
286
|
|
|
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) {
|
|
287
|
+
public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
|
|
288
|
+
const checkpoint = this.resolveCheckpointQuery(query);
|
|
289
|
+
if (!checkpoint) {
|
|
244
290
|
return Promise.resolve(undefined);
|
|
245
291
|
}
|
|
246
|
-
return Promise.resolve(this.
|
|
292
|
+
return Promise.resolve(this.checkpointToData(checkpoint));
|
|
247
293
|
}
|
|
248
294
|
|
|
249
|
-
public
|
|
250
|
-
|
|
251
|
-
|
|
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;
|
|
295
|
+
public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
|
|
296
|
+
const checkpoints = this.resolveCheckpointsQuery(query);
|
|
297
|
+
return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
|
|
272
298
|
}
|
|
273
299
|
|
|
274
|
-
|
|
275
|
-
const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
|
|
276
|
-
return Promise.resolve(block?.header);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
public async getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
280
|
-
const block = this.l2Blocks[number - 1];
|
|
281
|
-
if (!block) {
|
|
282
|
-
return undefined;
|
|
283
|
-
}
|
|
300
|
+
private checkpointToData(checkpoint: Checkpoint): CheckpointData {
|
|
284
301
|
return {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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),
|
|
290
313
|
};
|
|
291
314
|
}
|
|
292
315
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
+
}
|
|
297
338
|
}
|
|
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
339
|
}
|
|
334
340
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
);
|
|
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);
|
|
340
346
|
}
|
|
341
347
|
|
|
342
348
|
getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
@@ -344,11 +350,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
344
350
|
return Promise.resolve(blocks);
|
|
345
351
|
}
|
|
346
352
|
|
|
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
353
|
/**
|
|
353
354
|
* Gets a tx effect.
|
|
354
355
|
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
@@ -366,7 +367,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
366
367
|
data: txEffect,
|
|
367
368
|
l2BlockNumber: block.number,
|
|
368
369
|
l2BlockHash: await block.hash(),
|
|
369
|
-
txIndexInBlock: block.body.txEffects.
|
|
370
|
+
txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
|
|
370
371
|
};
|
|
371
372
|
}
|
|
372
373
|
|
|
@@ -388,6 +389,7 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
388
389
|
txEffect.transactionFee.toBigInt(),
|
|
389
390
|
await block.hash(),
|
|
390
391
|
block.number,
|
|
392
|
+
getEpochAtSlot(block.slot, EmptyL1RollupConstants),
|
|
391
393
|
);
|
|
392
394
|
}
|
|
393
395
|
}
|
|
@@ -396,56 +398,77 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
async getL2Tips(): Promise<L2Tips> {
|
|
399
|
-
const [latest, proven, finalized, checkpointed] = [
|
|
401
|
+
const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
|
|
400
402
|
await this.getBlockNumber(),
|
|
401
|
-
|
|
403
|
+
this.provenBlockNumber,
|
|
402
404
|
this.finalizedBlockNumber,
|
|
403
405
|
this.checkpointedBlockNumber,
|
|
406
|
+
await this.getProposedCheckpointL2BlockNumber(),
|
|
404
407
|
] as const;
|
|
405
408
|
|
|
406
409
|
const latestBlock = this.l2Blocks[latest - 1];
|
|
407
410
|
const provenBlock = this.l2Blocks[proven - 1];
|
|
408
411
|
const finalizedBlock = this.l2Blocks[finalized - 1];
|
|
409
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
|
+
};
|
|
410
424
|
|
|
411
425
|
const latestBlockId = {
|
|
412
426
|
number: BlockNumber(latest),
|
|
413
|
-
hash:
|
|
427
|
+
hash: await tipHash(latestBlock, latest),
|
|
414
428
|
};
|
|
415
429
|
const provenBlockId = {
|
|
416
430
|
number: BlockNumber(proven),
|
|
417
|
-
hash:
|
|
431
|
+
hash: await tipHash(provenBlock, proven),
|
|
418
432
|
};
|
|
419
433
|
const finalizedBlockId = {
|
|
420
434
|
number: BlockNumber(finalized),
|
|
421
|
-
hash:
|
|
435
|
+
hash: await tipHash(finalizedBlock, finalized),
|
|
422
436
|
};
|
|
423
437
|
const checkpointedBlockId = {
|
|
424
438
|
number: BlockNumber(checkpointed),
|
|
425
|
-
hash:
|
|
439
|
+
hash: await tipHash(checkpointedBlock, checkpointed),
|
|
440
|
+
};
|
|
441
|
+
const proposedCheckpointBlockId = {
|
|
442
|
+
number: BlockNumber(proposedCheckpoint),
|
|
443
|
+
hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint),
|
|
426
444
|
};
|
|
427
445
|
|
|
428
|
-
const makeTipId = (blockId: typeof latestBlockId) =>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
+
};
|
|
435
457
|
|
|
436
458
|
return {
|
|
437
459
|
proposed: latestBlockId,
|
|
438
460
|
checkpointed: makeTipId(checkpointedBlockId),
|
|
439
461
|
proven: makeTipId(provenBlockId),
|
|
440
462
|
finalized: makeTipId(finalizedBlockId),
|
|
463
|
+
proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
|
|
441
464
|
};
|
|
442
465
|
}
|
|
443
466
|
|
|
444
|
-
|
|
467
|
+
getSyncedL2EpochNumber(): Promise<EpochNumber> {
|
|
445
468
|
throw new Error('Method not implemented.');
|
|
446
469
|
}
|
|
447
470
|
|
|
448
|
-
|
|
471
|
+
getSyncedL2SlotNumber(): Promise<SlotNumber> {
|
|
449
472
|
throw new Error('Method not implemented.');
|
|
450
473
|
}
|
|
451
474
|
|
|
@@ -457,8 +480,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
457
480
|
return Promise.resolve(EmptyL1RollupConstants);
|
|
458
481
|
}
|
|
459
482
|
|
|
483
|
+
isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
|
|
484
|
+
return Promise.resolve(false);
|
|
485
|
+
}
|
|
486
|
+
|
|
460
487
|
getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
|
|
461
|
-
return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
488
|
+
return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
|
|
462
489
|
}
|
|
463
490
|
|
|
464
491
|
getL1Timestamp(): Promise<bigint> {
|
|
@@ -511,6 +538,95 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
511
538
|
return Promise.resolve();
|
|
512
539
|
}
|
|
513
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
|
+
|
|
514
630
|
isPendingChainInvalid(): Promise<boolean> {
|
|
515
631
|
return Promise.resolve(false);
|
|
516
632
|
}
|
|
@@ -519,6 +635,10 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
519
635
|
return Promise.resolve({ valid: true });
|
|
520
636
|
}
|
|
521
637
|
|
|
638
|
+
getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
|
|
639
|
+
return Promise.resolve(undefined);
|
|
640
|
+
}
|
|
641
|
+
|
|
522
642
|
/** Returns checkpoints whose slot falls within the given epoch. */
|
|
523
643
|
private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
|
|
524
644
|
const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
|
|
@@ -531,22 +651,6 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
|
|
|
531
651
|
return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
|
|
532
652
|
}
|
|
533
653
|
|
|
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
654
|
/** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
|
|
551
655
|
private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
|
|
552
656
|
const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
|