@aztec/archiver 0.0.1-commit.b33fc05d0 → 0.0.1-commit.b3d3157a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +19 -11
  2. package/dest/archiver.d.ts +53 -16
  3. package/dest/archiver.d.ts.map +1 -1
  4. package/dest/archiver.js +248 -76
  5. package/dest/config.d.ts +4 -1
  6. package/dest/config.d.ts.map +1 -1
  7. package/dest/config.js +21 -14
  8. package/dest/errors.d.ts +50 -2
  9. package/dest/errors.d.ts.map +1 -1
  10. package/dest/errors.js +74 -2
  11. package/dest/factory.d.ts +13 -7
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +46 -32
  14. package/dest/index.d.ts +11 -3
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +10 -2
  17. package/dest/l1/calldata_retriever.d.ts +2 -1
  18. package/dest/l1/calldata_retriever.d.ts.map +1 -1
  19. package/dest/l1/calldata_retriever.js +15 -5
  20. package/dest/l1/data_retrieval.d.ts +19 -10
  21. package/dest/l1/data_retrieval.d.ts.map +1 -1
  22. package/dest/l1/data_retrieval.js +25 -32
  23. package/dest/l1/trace_tx.d.ts +12 -66
  24. package/dest/l1/trace_tx.d.ts.map +1 -1
  25. package/dest/l1/validate_historical_logs.d.ts +23 -0
  26. package/dest/l1/validate_historical_logs.d.ts.map +1 -0
  27. package/dest/l1/validate_historical_logs.js +108 -0
  28. package/dest/modules/contract_data_source_adapter.d.ts +25 -0
  29. package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
  30. package/dest/modules/contract_data_source_adapter.js +40 -0
  31. package/dest/modules/data_source_base.d.ts +71 -47
  32. package/dest/modules/data_source_base.d.ts.map +1 -1
  33. package/dest/modules/data_source_base.js +269 -137
  34. package/dest/modules/data_store_updater.d.ts +30 -13
  35. package/dest/modules/data_store_updater.d.ts.map +1 -1
  36. package/dest/modules/data_store_updater.js +166 -116
  37. package/dest/modules/instrumentation.d.ts +7 -2
  38. package/dest/modules/instrumentation.d.ts.map +1 -1
  39. package/dest/modules/instrumentation.js +25 -7
  40. package/dest/modules/l1_synchronizer.d.ts +11 -6
  41. package/dest/modules/l1_synchronizer.d.ts.map +1 -1
  42. package/dest/modules/l1_synchronizer.js +414 -213
  43. package/dest/modules/outbox_trees_resolver.d.ts +62 -0
  44. package/dest/modules/outbox_trees_resolver.d.ts.map +1 -0
  45. package/dest/modules/outbox_trees_resolver.js +162 -0
  46. package/dest/modules/validation.d.ts +4 -3
  47. package/dest/modules/validation.d.ts.map +1 -1
  48. package/dest/modules/validation.js +6 -6
  49. package/dest/store/block_store.d.ts +165 -66
  50. package/dest/store/block_store.d.ts.map +1 -1
  51. package/dest/store/block_store.js +648 -233
  52. package/dest/store/contract_class_store.d.ts +17 -4
  53. package/dest/store/contract_class_store.d.ts.map +1 -1
  54. package/dest/store/contract_class_store.js +24 -68
  55. package/dest/store/contract_instance_store.d.ts +28 -1
  56. package/dest/store/contract_instance_store.d.ts.map +1 -1
  57. package/dest/store/contract_instance_store.js +37 -2
  58. package/dest/store/data_stores.d.ts +68 -0
  59. package/dest/store/data_stores.d.ts.map +1 -0
  60. package/dest/store/data_stores.js +54 -0
  61. package/dest/store/function_names_cache.d.ts +17 -0
  62. package/dest/store/function_names_cache.d.ts.map +1 -0
  63. package/dest/store/function_names_cache.js +30 -0
  64. package/dest/store/l2_tips_cache.d.ts +13 -7
  65. package/dest/store/l2_tips_cache.d.ts.map +1 -1
  66. package/dest/store/l2_tips_cache.js +13 -76
  67. package/dest/store/log_store.d.ts +42 -37
  68. package/dest/store/log_store.d.ts.map +1 -1
  69. package/dest/store/log_store.js +262 -408
  70. package/dest/store/log_store_codec.d.ts +70 -0
  71. package/dest/store/log_store_codec.d.ts.map +1 -0
  72. package/dest/store/log_store_codec.js +101 -0
  73. package/dest/store/message_store.d.ts +11 -1
  74. package/dest/store/message_store.d.ts.map +1 -1
  75. package/dest/store/message_store.js +50 -8
  76. package/dest/test/fake_l1_state.d.ts +15 -3
  77. package/dest/test/fake_l1_state.d.ts.map +1 -1
  78. package/dest/test/fake_l1_state.js +88 -18
  79. package/dest/test/mock_l1_to_l2_message_source.d.ts +1 -1
  80. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  81. package/dest/test/mock_l1_to_l2_message_source.js +2 -1
  82. package/dest/test/mock_l2_block_source.d.ts +51 -50
  83. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  84. package/dest/test/mock_l2_block_source.js +244 -181
  85. package/dest/test/noop_l1_archiver.d.ts +10 -6
  86. package/dest/test/noop_l1_archiver.d.ts.map +1 -1
  87. package/dest/test/noop_l1_archiver.js +22 -9
  88. package/package.json +14 -14
  89. package/src/archiver.ts +315 -83
  90. package/src/config.ts +24 -11
  91. package/src/errors.ts +117 -2
  92. package/src/factory.ts +54 -28
  93. package/src/index.ts +18 -2
  94. package/src/l1/calldata_retriever.ts +16 -5
  95. package/src/l1/data_retrieval.ts +36 -45
  96. package/src/l1/validate_historical_logs.ts +140 -0
  97. package/src/modules/contract_data_source_adapter.ts +55 -0
  98. package/src/modules/data_source_base.ts +341 -174
  99. package/src/modules/data_store_updater.ts +201 -147
  100. package/src/modules/instrumentation.ts +28 -8
  101. package/src/modules/l1_synchronizer.ts +549 -254
  102. package/src/modules/outbox_trees_resolver.ts +199 -0
  103. package/src/modules/validation.ts +10 -9
  104. package/src/store/block_store.ts +807 -285
  105. package/src/store/contract_class_store.ts +31 -103
  106. package/src/store/contract_instance_store.ts +51 -5
  107. package/src/store/data_stores.ts +104 -0
  108. package/src/store/function_names_cache.ts +37 -0
  109. package/src/store/l2_tips_cache.ts +16 -70
  110. package/src/store/log_store.ts +301 -559
  111. package/src/store/log_store_codec.ts +132 -0
  112. package/src/store/message_store.ts +59 -9
  113. package/src/structs/inbox_message.ts +1 -1
  114. package/src/test/fake_l1_state.ts +111 -29
  115. package/src/test/mock_l1_to_l2_message_source.ts +1 -0
  116. package/src/test/mock_l2_block_source.ts +299 -232
  117. package/src/test/noop_l1_archiver.ts +42 -9
  118. package/dest/store/kv_archiver_store.d.ts +0 -363
  119. package/dest/store/kv_archiver_store.d.ts.map +0 -1
  120. package/dest/store/kv_archiver_store.js +0 -476
  121. package/src/store/kv_archiver_store.ts +0 -689
@@ -1,16 +1,17 @@
1
1
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
2
2
  import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
3
- import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
4
4
  import { Buffer32 } from '@aztec/foundation/buffer';
5
5
  import { Fr } from '@aztec/foundation/curves/bn254';
6
6
  import { EthAddress } from '@aztec/foundation/eth-address';
7
7
  import { createLogger } from '@aztec/foundation/log';
8
- import { CheckpointedL2Block } from '@aztec/stdlib/block';
8
+ import { Body, GENESIS_BLOCK_HEADER_HASH, GENESIS_CHECKPOINT_HEADER_HASH, L2Block } from '@aztec/stdlib/block';
9
9
  import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
10
- import { EmptyL1RollupConstants, getEpochAtSlot, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
10
+ import { EmptyL1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
11
11
  import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
12
12
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
13
- import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
13
+ import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
14
+ import { BlockHeader } from '@aztec/stdlib/tx';
14
15
  /**
15
16
  * A mocked implementation of L2BlockSource to be used in tests.
16
17
  */ export class MockL2BlockSource {
@@ -19,7 +20,48 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
19
20
  provenBlockNumber = 0;
20
21
  finalizedBlockNumber = 0;
21
22
  checkpointedBlockNumber = 0;
23
+ proposedCheckpointBlockNumber = 0;
24
+ initialHeader = BlockHeader.empty();
25
+ initialHeaderHash = GENESIS_BLOCK_HEADER_HASH;
26
+ genesisArchiveRoot;
27
+ genesisBlock;
22
28
  log = createLogger('archiver:mock_l2_block_source');
29
+ /** Returns the initial header used to synthesize block 0. */ getInitialHeader() {
30
+ return this.initialHeader;
31
+ }
32
+ /**
33
+ * Sets the initial header used to synthesize block 0. Tests that wire up a real
34
+ * world-state should call this with `worldState.getInitialHeader()` so the L2BlockStream
35
+ * agrees on the genesis hash on both sides. Precomputes and caches the header hash so
36
+ * `getGenesisBlockHash()` can return synchronously.
37
+ */ async setInitialHeader(header) {
38
+ this.initialHeader = header;
39
+ this.initialHeaderHash = await header.hash();
40
+ this.genesisBlock = undefined;
41
+ }
42
+ /**
43
+ * Returns the precomputed hash of the genesis block header. Defaults to the static
44
+ * {@link GENESIS_BLOCK_HEADER_HASH} unless {@link setInitialHeader} has been called with a
45
+ * custom header.
46
+ */ getGenesisBlockHash() {
47
+ return this.initialHeaderHash;
48
+ }
49
+ /**
50
+ * Sets the post-genesis archive root used to synthesize block 0. Mirrors the real archiver,
51
+ * whose synthetic block 0 carries `new AppendOnlyTreeSnapshot(genesisArchiveRoot, 1)` rather
52
+ * than `AppendOnlyTreeSnapshot.empty()`. Tests wiring up a real world-state should set this so
53
+ * archive-based block lookups against the mock match production semantics.
54
+ */ setGenesisArchiveRoot(root) {
55
+ this.genesisArchiveRoot = root;
56
+ this.genesisBlock = undefined;
57
+ }
58
+ getGenesisBlock() {
59
+ if (this.genesisBlock) {
60
+ return this.genesisBlock;
61
+ }
62
+ const archive = this.genesisArchiveRoot ? new AppendOnlyTreeSnapshot(this.genesisArchiveRoot, 1) : AppendOnlyTreeSnapshot.empty();
63
+ return this.genesisBlock = new L2Block(archive, this.initialHeader, Body.empty(), CheckpointNumber.ZERO, IndexWithinCheckpoint(0));
64
+ }
23
65
  /** Creates blocks grouped into single-block checkpoints. */ async createBlocks(numBlocks) {
24
66
  await this.createCheckpoints(numBlocks, 1);
25
67
  }
@@ -56,6 +98,7 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
56
98
  });
57
99
  // Keep tip numbers consistent with remaining blocks.
58
100
  this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
101
+ this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
59
102
  this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
60
103
  this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
61
104
  this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
@@ -69,9 +112,16 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
69
112
  }
70
113
  this.finalizedBlockNumber = finalizedBlockNumber;
71
114
  }
115
+ setProposedCheckpointBlockNumber(blockNumber) {
116
+ this.proposedCheckpointBlockNumber = blockNumber;
117
+ }
72
118
  setCheckpointedBlockNumber(checkpointedBlockNumber) {
73
119
  const prevCheckpointed = this.checkpointedBlockNumber;
74
120
  this.checkpointedBlockNumber = checkpointedBlockNumber;
121
+ // Proposed checkpoint is always at least as advanced as checkpointed
122
+ if (this.proposedCheckpointBlockNumber < checkpointedBlockNumber) {
123
+ this.proposedCheckpointBlockNumber = checkpointedBlockNumber;
124
+ }
75
125
  // Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
76
126
  // This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
77
127
  const newCheckpoints = [];
@@ -109,176 +159,93 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
109
159
  */ getRegistryAddress() {
110
160
  return Promise.resolve(EthAddress.random());
111
161
  }
112
- /**
113
- * Gets the number of the latest L2 block processed by the block source implementation.
114
- * @returns In this mock instance, returns the number of L2 blocks that we've mocked.
115
- */ getBlockNumber() {
116
- return Promise.resolve(BlockNumber(this.l2Blocks.length));
117
- }
118
- getProvenBlockNumber() {
119
- return Promise.resolve(BlockNumber(this.provenBlockNumber));
120
- }
121
- getCheckpointedL2BlockNumber() {
122
- return Promise.resolve(BlockNumber(this.checkpointedBlockNumber));
123
- }
124
- getFinalizedL2BlockNumber() {
125
- return Promise.resolve(BlockNumber(this.finalizedBlockNumber));
126
- }
127
- getCheckpointedBlock(number) {
128
- if (number > this.checkpointedBlockNumber) {
129
- return Promise.resolve(undefined);
162
+ async getBlockNumber(query) {
163
+ if (!query) {
164
+ return BlockNumber(this.l2Blocks.length);
130
165
  }
131
- const block = this.l2Blocks[number - 1];
132
- if (!block) {
133
- return Promise.resolve(undefined);
166
+ if ('number' in query) {
167
+ return query.number;
134
168
  }
135
- return Promise.resolve(this.toCheckpointedBlock(block));
136
- }
137
- async getCheckpointedBlocks(from, limit) {
138
- const result = [];
139
- for(let i = 0; i < limit; i++){
140
- const blockNum = from + i;
141
- if (blockNum > this.checkpointedBlockNumber) {
142
- break;
143
- }
144
- const block = await this.getCheckpointedBlock(BlockNumber(blockNum));
145
- if (block) {
146
- result.push(block);
147
- }
169
+ if ('tag' in query) {
170
+ return BlockNumber(this.resolveBlockTag(query.tag));
148
171
  }
149
- return result;
172
+ const block = await this.getBlock(query);
173
+ return block ? block.header.globalVariables.blockNumber : undefined;
150
174
  }
151
- /**
152
- * Gets an l2 block.
153
- * @param number - The block number to return (inclusive).
154
- * @returns The requested L2 block.
155
- */ getBlock(number) {
156
- const block = this.l2Blocks[number - 1];
157
- return Promise.resolve(block);
175
+ getProposedCheckpointL2BlockNumber() {
176
+ return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
158
177
  }
159
- /**
160
- * Gets an L2 block (new format).
161
- * @param number - The block number to return.
162
- * @returns The requested L2 block.
163
- */ getL2Block(number) {
164
- const block = this.l2Blocks[number - 1];
165
- return Promise.resolve(block);
178
+ getCheckpoint(query) {
179
+ const checkpoint = this.resolveCheckpointQuery(query);
180
+ if (!checkpoint) {
181
+ return Promise.resolve(undefined);
182
+ }
183
+ return Promise.resolve(new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), []));
166
184
  }
167
- /**
168
- * Gets up to `limit` amount of L2 blocks starting from `from`.
169
- * @param from - Number of the first block to return (inclusive).
170
- * @param limit - The maximum number of blocks to return.
171
- * @returns The requested mocked L2 blocks.
172
- */ getBlocks(from, limit) {
173
- return Promise.resolve(this.l2Blocks.slice(from - 1, from - 1 + limit));
174
- }
175
- getCheckpoints(from, limit) {
176
- const checkpoints = this.checkpointList.slice(from - 1, from - 1 + limit);
185
+ getCheckpoints(query) {
186
+ const checkpoints = this.resolveCheckpointsQuery(query);
177
187
  return Promise.resolve(checkpoints.map((checkpoint)=>new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])));
178
188
  }
179
189
  getCheckpointByArchive(archive) {
180
190
  const checkpoint = this.checkpointList.find((c)=>c.archive.root.equals(archive));
181
191
  return Promise.resolve(checkpoint);
182
192
  }
183
- async getCheckpointedBlockByHash(blockHash) {
184
- for (const block of this.l2Blocks){
185
- const hash = await block.hash();
186
- if (hash.equals(blockHash)) {
187
- return this.toCheckpointedBlock(block);
188
- }
189
- }
190
- return undefined;
191
- }
192
- getCheckpointedBlockByArchive(archive) {
193
- const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
194
- if (!block) {
193
+ getCheckpointData(query) {
194
+ const checkpoint = this.resolveCheckpointQuery(query);
195
+ if (!checkpoint) {
195
196
  return Promise.resolve(undefined);
196
197
  }
197
- return Promise.resolve(this.toCheckpointedBlock(block));
198
- }
199
- async getL2BlockByHash(blockHash) {
200
- for (const block of this.l2Blocks){
201
- const hash = await block.hash();
202
- if (hash.equals(blockHash)) {
203
- return block;
204
- }
205
- }
206
- return undefined;
207
- }
208
- getL2BlockByArchive(archive) {
209
- const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
210
- return Promise.resolve(block);
211
- }
212
- async getBlockHeaderByHash(blockHash) {
213
- for (const block of this.l2Blocks){
214
- const hash = await block.hash();
215
- if (hash.equals(blockHash)) {
216
- return block.header;
217
- }
218
- }
219
- return undefined;
198
+ return Promise.resolve(this.checkpointToData(checkpoint));
220
199
  }
221
- getBlockHeaderByArchive(archive) {
222
- const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
223
- return Promise.resolve(block?.header);
200
+ getCheckpointsData(query) {
201
+ const checkpoints = this.resolveCheckpointsQuery(query);
202
+ return Promise.resolve(checkpoints.map((c)=>this.checkpointToData(c)));
224
203
  }
225
- async getBlockData(number) {
226
- const block = this.l2Blocks[number - 1];
227
- if (!block) {
228
- return undefined;
229
- }
204
+ checkpointToData(checkpoint) {
230
205
  return {
231
- header: block.header,
232
- archive: block.archive,
233
- blockHash: await block.hash(),
234
- checkpointNumber: block.checkpointNumber,
235
- indexWithinCheckpoint: block.indexWithinCheckpoint
206
+ checkpointNumber: checkpoint.number,
207
+ header: checkpoint.header,
208
+ archive: checkpoint.archive,
209
+ checkpointOutHash: computeCheckpointOutHash(checkpoint.blocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs))),
210
+ startBlock: checkpoint.blocks[0].number,
211
+ blockCount: checkpoint.blocks.length,
212
+ feeAssetPriceModifier: checkpoint.feeAssetPriceModifier,
213
+ attestations: [],
214
+ l1: this.mockL1DataForCheckpoint(checkpoint)
236
215
  };
237
216
  }
238
- async getBlockDataByArchive(archive) {
239
- const block = this.l2Blocks.find((b)=>b.archive.root.equals(archive));
240
- if (!block) {
241
- return undefined;
217
+ resolveCheckpointQuery(query) {
218
+ if ('number' in query) {
219
+ return this.checkpointList[query.number - 1];
220
+ }
221
+ if ('slot' in query) {
222
+ return this.checkpointList.find((c)=>c.header.slotNumber === query.slot);
223
+ }
224
+ switch(query.tag){
225
+ case 'checkpointed':
226
+ return this.checkpointList[this.checkpointList.length - 1];
227
+ case 'proven':
228
+ {
229
+ const provenCheckpoint = this.checkpointList.filter((c)=>c.blocks.some((b)=>b.number <= this.provenBlockNumber));
230
+ return provenCheckpoint.at(-1);
231
+ }
232
+ case 'finalized':
233
+ {
234
+ const finalizedCheckpoint = this.checkpointList.filter((c)=>c.blocks.some((b)=>b.number <= this.finalizedBlockNumber));
235
+ return finalizedCheckpoint.at(-1);
236
+ }
242
237
  }
243
- return {
244
- header: block.header,
245
- archive: block.archive,
246
- blockHash: await block.hash(),
247
- checkpointNumber: block.checkpointNumber,
248
- indexWithinCheckpoint: block.indexWithinCheckpoint
249
- };
250
- }
251
- getBlockHeader(number) {
252
- return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.header);
253
- }
254
- getCheckpointsForEpoch(epochNumber) {
255
- return Promise.resolve(this.getCheckpointsInEpoch(epochNumber));
256
- }
257
- getCheckpointsDataForEpoch(epochNumber) {
258
- const checkpoints = this.getCheckpointsInEpoch(epochNumber);
259
- return Promise.resolve(checkpoints.map((checkpoint)=>({
260
- checkpointNumber: checkpoint.number,
261
- header: checkpoint.header,
262
- archive: checkpoint.archive,
263
- checkpointOutHash: computeCheckpointOutHash(checkpoint.blocks.map((b)=>b.body.txEffects.map((tx)=>tx.l2ToL1Msgs))),
264
- startBlock: checkpoint.blocks[0].number,
265
- blockCount: checkpoint.blocks.length,
266
- attestations: [],
267
- l1: this.mockL1DataForCheckpoint(checkpoint)
268
- })));
269
238
  }
270
- getCheckpointedBlocksForEpoch(epochNumber) {
271
- const checkpoints = this.getCheckpointsInEpoch(epochNumber);
272
- return Promise.resolve(checkpoints.flatMap((checkpoint)=>checkpoint.blocks.map((block)=>this.toCheckpointedBlock(block))));
239
+ resolveCheckpointsQuery(query) {
240
+ if ('from' in query) {
241
+ return this.checkpointList.slice(query.from - 1, query.from - 1 + query.limit);
242
+ }
243
+ return this.getCheckpointsInEpoch(query.epoch);
273
244
  }
274
245
  getBlocksForSlot(slotNumber) {
275
246
  const blocks = this.l2Blocks.filter((b)=>b.header.globalVariables.slotNumber === slotNumber);
276
247
  return Promise.resolve(blocks);
277
248
  }
278
- async getCheckpointedBlockHeadersForEpoch(epochNumber) {
279
- const checkpointedBlocks = await this.getCheckpointedBlocksForEpoch(epochNumber);
280
- return checkpointedBlocks.map((b)=>b.block.header);
281
- }
282
249
  /**
283
250
  * Gets a tx effect.
284
251
  * @param txHash - The hash of the tx corresponding to the tx effect.
@@ -296,63 +263,76 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
296
263
  data: txEffect,
297
264
  l2BlockNumber: block.number,
298
265
  l2BlockHash: await block.hash(),
299
- txIndexInBlock: block.body.txEffects.indexOf(txEffect)
266
+ txIndexInBlock: block.body.txEffects.findIndex((t)=>t.txHash.equals(txHash)),
267
+ slotNumber: block.header.globalVariables.slotNumber
300
268
  };
301
269
  }
302
- /**
303
- * Gets a receipt of a settled tx.
304
- * @param txHash - The hash of a tx we try to get the receipt for.
305
- * @returns The requested tx receipt (or undefined if not found).
306
- */ async getSettledTxReceipt(txHash) {
307
- for (const block of this.l2Blocks){
308
- for (const txEffect of block.body.txEffects){
309
- if (txEffect.txHash.equals(txHash)) {
310
- // In mock, assume all txs are checkpointed with successful execution
311
- return new TxReceipt(txHash, TxStatus.CHECKPOINTED, TxExecutionResult.SUCCESS, undefined, txEffect.transactionFee.toBigInt(), await block.hash(), block.number, getEpochAtSlot(block.slot, EmptyL1RollupConstants));
312
- }
313
- }
314
- }
315
- return undefined;
270
+ getL2ToL1MembershipWitness() {
271
+ // Mock does not back the L2-to-L1 message witness flow.
272
+ return Promise.resolve(undefined);
316
273
  }
317
274
  async getL2Tips() {
318
- const [latest, proven, finalized, checkpointed] = [
275
+ const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
319
276
  await this.getBlockNumber(),
320
- await this.getProvenBlockNumber(),
277
+ this.provenBlockNumber,
321
278
  this.finalizedBlockNumber,
322
- this.checkpointedBlockNumber
279
+ this.checkpointedBlockNumber,
280
+ await this.getProposedCheckpointL2BlockNumber()
323
281
  ];
324
282
  const latestBlock = this.l2Blocks[latest - 1];
325
283
  const provenBlock = this.l2Blocks[proven - 1];
326
284
  const finalizedBlock = this.l2Blocks[finalized - 1];
327
285
  const checkpointedBlock = this.l2Blocks[checkpointed - 1];
286
+ const proposedCheckpointBlock = this.l2Blocks[proposedCheckpoint - 1];
287
+ // For genesis tips (block number 0) report the dynamic initial header hash so consumers
288
+ // running L2BlockStream against this mock agree at block 0 with their local tip store.
289
+ const genesisHash = (await this.initialHeader.hash()).toString();
290
+ const tipHash = async (block, number)=>{
291
+ if (block) {
292
+ return (await block.hash()).toString();
293
+ }
294
+ return number === 0 ? genesisHash : '';
295
+ };
328
296
  const latestBlockId = {
329
297
  number: BlockNumber(latest),
330
- hash: (await latestBlock?.hash())?.toString()
298
+ hash: await tipHash(latestBlock, latest)
331
299
  };
332
300
  const provenBlockId = {
333
301
  number: BlockNumber(proven),
334
- hash: (await provenBlock?.hash())?.toString()
302
+ hash: await tipHash(provenBlock, proven)
335
303
  };
336
304
  const finalizedBlockId = {
337
305
  number: BlockNumber(finalized),
338
- hash: (await finalizedBlock?.hash())?.toString()
306
+ hash: await tipHash(finalizedBlock, finalized)
339
307
  };
340
308
  const checkpointedBlockId = {
341
309
  number: BlockNumber(checkpointed),
342
- hash: (await checkpointedBlock?.hash())?.toString()
310
+ hash: await tipHash(checkpointedBlock, checkpointed)
343
311
  };
344
- const makeTipId = (blockId)=>({
312
+ const proposedCheckpointBlockId = {
313
+ number: BlockNumber(proposedCheckpoint),
314
+ hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint)
315
+ };
316
+ const makeTipId = (blockId)=>{
317
+ const checkpointNumber = this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0);
318
+ // Match production semantics: checkpoint 0 is fully synthetic (no real checkpoint header
319
+ // exists at 0), so its hash stays at the protocol constant `GENESIS_CHECKPOINT_HEADER_HASH`
320
+ // even though the block-0 hash is dynamic. See L2TipsCache for the production path.
321
+ const hash = checkpointNumber === 0 ? GENESIS_CHECKPOINT_HEADER_HASH.toString() : blockId.hash;
322
+ return {
345
323
  block: blockId,
346
324
  checkpoint: {
347
- number: this.findCheckpointNumberForBlock(blockId.number) ?? CheckpointNumber(0),
348
- hash: blockId.hash
325
+ number: checkpointNumber,
326
+ hash
349
327
  }
350
- });
328
+ };
329
+ };
351
330
  return {
352
331
  proposed: latestBlockId,
353
332
  checkpointed: makeTipId(checkpointedBlockId),
354
333
  proven: makeTipId(provenBlockId),
355
- finalized: makeTipId(finalizedBlockId)
334
+ finalized: makeTipId(finalizedBlockId),
335
+ proposedCheckpoint: makeTipId(proposedCheckpointBlockId)
356
336
  };
357
337
  }
358
338
  getSyncedL2EpochNumber() {
@@ -367,9 +347,12 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
367
347
  getL1Constants() {
368
348
  return Promise.resolve(EmptyL1RollupConstants);
369
349
  }
350
+ isPruneDueAtSlot(_slot) {
351
+ return Promise.resolve(false);
352
+ }
370
353
  getGenesisValues() {
371
354
  return Promise.resolve({
372
- genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT)
355
+ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT)
373
356
  });
374
357
  }
375
358
  getL1Timestamp() {
@@ -410,6 +393,88 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
410
393
  syncImmediate() {
411
394
  return Promise.resolve();
412
395
  }
396
+ async getBlock(query) {
397
+ if ('number' in query) {
398
+ if (query.number === 0) {
399
+ return this.getGenesisBlock();
400
+ }
401
+ return this.l2Blocks[query.number - 1];
402
+ }
403
+ if ('hash' in query) {
404
+ const genesis = this.getGenesisBlock();
405
+ if ((await genesis.hash()).equals(query.hash)) {
406
+ return genesis;
407
+ }
408
+ for (const b of this.l2Blocks){
409
+ const hash = await b.hash();
410
+ if (hash.equals(query.hash)) {
411
+ return b;
412
+ }
413
+ }
414
+ return undefined;
415
+ }
416
+ if ('archive' in query) {
417
+ const genesis = this.getGenesisBlock();
418
+ if (genesis.archive.root.equals(query.archive)) {
419
+ return genesis;
420
+ }
421
+ return this.l2Blocks.find((b)=>b.archive.root.equals(query.archive));
422
+ }
423
+ const number = this.resolveBlockTag(query.tag);
424
+ if (number === 0) {
425
+ return this.getGenesisBlock();
426
+ }
427
+ return this.l2Blocks[number - 1];
428
+ }
429
+ resolveBlockTag(tag) {
430
+ switch(tag){
431
+ case 'latest':
432
+ case 'proposed':
433
+ return this.l2Blocks.length;
434
+ case 'checkpointed':
435
+ return this.checkpointedBlockNumber;
436
+ case 'proven':
437
+ return this.provenBlockNumber;
438
+ case 'finalized':
439
+ return this.finalizedBlockNumber;
440
+ }
441
+ }
442
+ getBlocks(query) {
443
+ let blocks;
444
+ if ('from' in query) {
445
+ blocks = this.l2Blocks.slice(query.from - 1, query.from - 1 + query.limit);
446
+ } else {
447
+ const epochCheckpoints = this.getCheckpointsInEpoch(query.epoch);
448
+ blocks = epochCheckpoints.flatMap((c)=>c.blocks);
449
+ }
450
+ if (query.onlyCheckpointed) {
451
+ blocks = blocks.filter((b)=>b.header.globalVariables.blockNumber <= this.checkpointedBlockNumber);
452
+ }
453
+ return Promise.resolve(blocks);
454
+ }
455
+ async getBlockData(query) {
456
+ const block = await this.getBlock(query);
457
+ if (!block) {
458
+ return undefined;
459
+ }
460
+ return {
461
+ header: block.header,
462
+ archive: block.archive,
463
+ blockHash: await block.hash(),
464
+ checkpointNumber: block.checkpointNumber,
465
+ indexWithinCheckpoint: block.indexWithinCheckpoint
466
+ };
467
+ }
468
+ async getBlocksData(query) {
469
+ const blocks = await this.getBlocks(query);
470
+ return Promise.all(blocks.map(async (block)=>({
471
+ header: block.header,
472
+ archive: block.archive,
473
+ blockHash: await block.hash(),
474
+ checkpointNumber: block.checkpointNumber,
475
+ indexWithinCheckpoint: block.indexWithinCheckpoint
476
+ })));
477
+ }
413
478
  isPendingChainInvalid() {
414
479
  return Promise.resolve(false);
415
480
  }
@@ -418,6 +483,9 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
418
483
  valid: true
419
484
  });
420
485
  }
486
+ getProposedCheckpointData(_query) {
487
+ return Promise.resolve(undefined);
488
+ }
421
489
  /** Returns checkpoints whose slot falls within the given epoch. */ getCheckpointsInEpoch(epochNumber) {
422
490
  const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
423
491
  const [start, end] = getSlotRangeForEpoch(epochNumber, {
@@ -428,11 +496,6 @@ import { TxExecutionResult, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
428
496
  /** Creates a mock L1PublishedData for a checkpoint. */ mockL1DataForCheckpoint(checkpoint) {
429
497
  return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
430
498
  }
431
- /** Creates a CheckpointedL2Block from a block using stored checkpoint info. */ toCheckpointedBlock(block) {
432
- const checkpoint = this.checkpointList.find((c)=>c.blocks.some((b)=>b.number === block.number));
433
- const checkpointNumber = checkpoint?.number ?? block.checkpointNumber;
434
- return new CheckpointedL2Block(checkpointNumber, block, new L1PublishedData(BigInt(block.number), BigInt(block.number), `0x${block.number.toString(16).padStart(64, '0')}`), []);
435
- }
436
499
  /** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */ findCheckpointNumberForBlock(blockNumber) {
437
500
  const checkpoint = this.checkpointList.find((c)=>c.blocks.some((b)=>b.number === blockNumber));
438
501
  return checkpoint?.number;
@@ -1,26 +1,30 @@
1
1
  import { SlotNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { DateProvider } from '@aztec/foundation/timer';
4
+ import type { BlockHash } from '@aztec/stdlib/block';
3
5
  import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
6
+ import type { BlockHeader } from '@aztec/stdlib/tx';
4
7
  import { type TelemetryClient } from '@aztec/telemetry-client';
5
8
  import { Archiver } from '../archiver.js';
6
9
  import { ArchiverInstrumentation } from '../modules/instrumentation.js';
7
- import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
10
+ import type { ArchiverDataStores } from '../store/data_stores.js';
11
+ import { L2TipsCache } from '../store/l2_tips_cache.js';
8
12
  /**
9
13
  * Archiver with mocked L1 connectivity for testing.
10
14
  * Uses mock L1 clients and a noop synchronizer, enabling tests that
11
15
  * don't require real Ethereum connectivity.
12
16
  */
13
17
  export declare class NoopL1Archiver extends Archiver {
14
- constructor(dataStore: KVArchiverDataStore, l1Constants: L1RollupConstants & {
18
+ constructor(dataStores: ArchiverDataStores, l1Constants: L1RollupConstants & {
15
19
  genesisArchiveRoot: Fr;
16
- }, instrumentation: ArchiverInstrumentation);
20
+ }, instrumentation: ArchiverInstrumentation, initialHeader: BlockHeader, initialBlockHash: BlockHash, l2TipsCache: L2TipsCache, dateProvider?: DateProvider);
17
21
  /** Override start to skip L1 validation checks. */
18
22
  start(_blockUntilSynced?: boolean): Promise<void>;
19
23
  /** Always reports as fully synced since there is no real L1 to sync from. */
20
24
  getSyncedL2SlotNumber(): Promise<SlotNumber | undefined>;
21
25
  }
22
26
  /** Creates an archiver with mocked L1 connectivity for testing. */
23
- export declare function createNoopL1Archiver(dataStore: KVArchiverDataStore, l1Constants: L1RollupConstants & {
27
+ export declare function createNoopL1Archiver(dataStores: ArchiverDataStores, l1Constants: L1RollupConstants & {
24
28
  genesisArchiveRoot: Fr;
25
- }, telemetry?: TelemetryClient): Promise<NoopL1Archiver>;
26
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9vcF9sMV9hcmNoaXZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3Qvbm9vcF9sMV9hcmNoaXZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXBELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDckUsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFtQyxNQUFNLHlCQUF5QixDQUFDO0FBS2hHLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUV4RSxPQUFPLEtBQUssRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBeUJ6RTs7OztHQUlHO0FBQ0gscUJBQWEsY0FBZSxTQUFRLFFBQVE7SUFDMUMsWUFDRSxTQUFTLEVBQUUsbUJBQW1CLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztRQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtLQUFFLEVBQzNELGVBQWUsRUFBRSx1QkFBdUIsRUF1Q3pDO0lBRUQsbURBQW1EO0lBQ25DLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWhFO0lBRUQsNkVBQTZFO0lBQzdELHFCQUFxQixJQUFJLE9BQU8sQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLENBRXZFO0NBQ0Y7QUFFRCxtRUFBbUU7QUFDbkUsd0JBQXNCLG9CQUFvQixDQUN4QyxTQUFTLEVBQUUsbUJBQW1CLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztJQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtDQUFFLEVBQzNELFNBQVMsR0FBRSxlQUFzQyxHQUNoRCxPQUFPLENBQUMsY0FBYyxDQUFDLENBR3pCIn0=
29
+ }, telemetry: TelemetryClient | undefined, initialHeader: BlockHeader, dateProvider?: DateProvider): Promise<NoopL1Archiver>;
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9vcF9sMV9hcmNoaXZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3Qvbm9vcF9sMV9hcmNoaXZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXBELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUV2RCxPQUFPLEtBQUssRUFBbUIsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEUsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNyRSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQW1DLE1BQU0seUJBQXlCLENBQUM7QUFLaEcsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRXhFLE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBeUJ4RDs7OztHQUlHO0FBQ0gscUJBQWEsY0FBZSxTQUFRLFFBQVE7SUFDMUMsWUFDRSxVQUFVLEVBQUUsa0JBQWtCLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztRQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtLQUFFLEVBQzNELGVBQWUsRUFBRSx1QkFBdUIsRUFDeEMsYUFBYSxFQUFFLFdBQVcsRUFDMUIsZ0JBQWdCLEVBQUUsU0FBUyxFQUMzQixXQUFXLEVBQUUsV0FBVyxFQUN4QixZQUFZLEdBQUUsWUFBaUMsRUFpRGhEO0lBRUQsbURBQW1EO0lBQ25DLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBSWhFO0lBRUQsNkVBQTZFO0lBQzdELHFCQUFxQixJQUFJLE9BQU8sQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLENBRXZFO0NBQ0Y7QUFFRCxtRUFBbUU7QUFDbkUsd0JBQXNCLG9CQUFvQixDQUN4QyxVQUFVLEVBQUUsa0JBQWtCLEVBQzlCLFdBQVcsRUFBRSxpQkFBaUIsR0FBRztJQUFFLGtCQUFrQixFQUFFLEVBQUUsQ0FBQTtDQUFFLEVBQzNELFNBQVMsNkJBQXdDLEVBQ2pELGFBQWEsRUFBRSxXQUFXLEVBQzFCLFlBQVksQ0FBQyxFQUFFLFlBQVksR0FDMUIsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQWlCekIifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"noop_l1_archiver.d.ts","sourceRoot":"","sources":["../../src/test/noop_l1_archiver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,yBAAyB,CAAC;AAKhG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAyBzE;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,YACE,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;QAAE,kBAAkB,EAAE,EAAE,CAAA;KAAE,EAC3D,eAAe,EAAE,uBAAuB,EAuCzC;IAED,mDAAmD;IACnC,KAAK,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;IAED,6EAA6E;IAC7D,qBAAqB,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAEvE;CACF;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;IAAE,kBAAkB,EAAE,EAAE,CAAA;CAAE,EAC3D,SAAS,GAAE,eAAsC,GAChD,OAAO,CAAC,cAAc,CAAC,CAGzB"}
1
+ {"version":3,"file":"noop_l1_archiver.d.ts","sourceRoot":"","sources":["../../src/test/noop_l1_archiver.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,yBAAyB,CAAC;AAKhG,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAyBxD;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,YACE,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;QAAE,kBAAkB,EAAE,EAAE,CAAA;KAAE,EAC3D,eAAe,EAAE,uBAAuB,EACxC,aAAa,EAAE,WAAW,EAC1B,gBAAgB,EAAE,SAAS,EAC3B,WAAW,EAAE,WAAW,EACxB,YAAY,GAAE,YAAiC,EAiDhD;IAED,mDAAmD;IACnC,KAAK,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhE;IAED,6EAA6E;IAC7D,qBAAqB,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAEvE;CACF;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,kBAAkB,EAC9B,WAAW,EAAE,iBAAiB,GAAG;IAAE,kBAAkB,EAAE,EAAE,CAAA;CAAE,EAC3D,SAAS,6BAAwC,EACjD,aAAa,EAAE,WAAW,EAC1B,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,cAAc,CAAC,CAiBzB"}