@aztec/archiver 0.0.1-commit.b655e406 → 0.0.1-commit.b9865e97

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 (241) hide show
  1. package/README.md +164 -22
  2. package/dest/archiver.d.ts +176 -0
  3. package/dest/archiver.d.ts.map +1 -0
  4. package/dest/archiver.js +905 -0
  5. package/dest/config.d.ts +33 -0
  6. package/dest/config.d.ts.map +1 -0
  7. package/dest/config.js +78 -0
  8. package/dest/errors.d.ts +87 -0
  9. package/dest/errors.d.ts.map +1 -0
  10. package/dest/errors.js +129 -0
  11. package/dest/factory.d.ts +17 -10
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +117 -22
  14. package/dest/index.d.ts +19 -4
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +17 -3
  17. package/dest/interfaces.d.ts +9 -0
  18. package/dest/interfaces.d.ts.map +1 -0
  19. package/dest/interfaces.js +3 -0
  20. package/dest/l1/bin/retrieve-calldata.d.ts +3 -0
  21. package/dest/l1/bin/retrieve-calldata.d.ts.map +1 -0
  22. package/dest/l1/bin/retrieve-calldata.js +152 -0
  23. package/dest/l1/calldata_retriever.d.ts +136 -0
  24. package/dest/l1/calldata_retriever.d.ts.map +1 -0
  25. package/dest/l1/calldata_retriever.js +412 -0
  26. package/dest/l1/data_retrieval.d.ts +97 -0
  27. package/dest/l1/data_retrieval.d.ts.map +1 -0
  28. package/dest/l1/data_retrieval.js +307 -0
  29. package/dest/l1/debug_tx.d.ts +19 -0
  30. package/dest/l1/debug_tx.d.ts.map +1 -0
  31. package/dest/l1/debug_tx.js +73 -0
  32. package/dest/l1/spire_proposer.d.ts +70 -0
  33. package/dest/l1/spire_proposer.d.ts.map +1 -0
  34. package/dest/l1/spire_proposer.js +149 -0
  35. package/dest/l1/trace_tx.d.ts +43 -0
  36. package/dest/l1/trace_tx.d.ts.map +1 -0
  37. package/dest/l1/trace_tx.js +91 -0
  38. package/dest/l1/types.d.ts +12 -0
  39. package/dest/l1/types.d.ts.map +1 -0
  40. package/dest/l1/types.js +3 -0
  41. package/dest/l1/validate_historical_logs.d.ts +23 -0
  42. package/dest/l1/validate_historical_logs.d.ts.map +1 -0
  43. package/dest/l1/validate_historical_logs.js +108 -0
  44. package/dest/l1/validate_trace.d.ts +32 -0
  45. package/dest/l1/validate_trace.d.ts.map +1 -0
  46. package/dest/l1/validate_trace.js +154 -0
  47. package/dest/modules/contract_data_source_adapter.d.ts +25 -0
  48. package/dest/modules/contract_data_source_adapter.d.ts.map +1 -0
  49. package/dest/modules/contract_data_source_adapter.js +40 -0
  50. package/dest/modules/data_source_base.d.ts +113 -0
  51. package/dest/modules/data_source_base.d.ts.map +1 -0
  52. package/dest/modules/data_source_base.js +348 -0
  53. package/dest/modules/data_store_updater.d.ts +105 -0
  54. package/dest/modules/data_store_updater.d.ts.map +1 -0
  55. package/dest/modules/data_store_updater.js +392 -0
  56. package/dest/modules/instrumentation.d.ts +55 -0
  57. package/dest/modules/instrumentation.d.ts.map +1 -0
  58. package/dest/modules/instrumentation.js +145 -0
  59. package/dest/modules/l1_synchronizer.d.ts +77 -0
  60. package/dest/modules/l1_synchronizer.d.ts.map +1 -0
  61. package/dest/modules/l1_synchronizer.js +1344 -0
  62. package/dest/modules/outbox_trees_resolver.d.ts +62 -0
  63. package/dest/modules/outbox_trees_resolver.d.ts.map +1 -0
  64. package/dest/modules/outbox_trees_resolver.js +162 -0
  65. package/dest/modules/validation.d.ts +18 -0
  66. package/dest/modules/validation.d.ts.map +1 -0
  67. package/dest/modules/validation.js +104 -0
  68. package/dest/store/block_store.d.ts +294 -0
  69. package/dest/store/block_store.d.ts.map +1 -0
  70. package/dest/store/block_store.js +1188 -0
  71. package/dest/store/contract_class_store.d.ts +31 -0
  72. package/dest/store/contract_class_store.d.ts.map +1 -0
  73. package/dest/store/contract_class_store.js +80 -0
  74. package/dest/store/contract_instance_store.d.ts +51 -0
  75. package/dest/store/contract_instance_store.d.ts.map +1 -0
  76. package/dest/{archiver/kv_archiver_store → store}/contract_instance_store.js +38 -3
  77. package/dest/store/data_stores.d.ts +68 -0
  78. package/dest/store/data_stores.d.ts.map +1 -0
  79. package/dest/store/data_stores.js +54 -0
  80. package/dest/store/function_names_cache.d.ts +17 -0
  81. package/dest/store/function_names_cache.d.ts.map +1 -0
  82. package/dest/store/function_names_cache.js +30 -0
  83. package/dest/store/l2_tips_cache.d.ts +25 -0
  84. package/dest/store/l2_tips_cache.d.ts.map +1 -0
  85. package/dest/store/l2_tips_cache.js +26 -0
  86. package/dest/store/log_store.d.ts +59 -0
  87. package/dest/store/log_store.d.ts.map +1 -0
  88. package/dest/store/log_store.js +310 -0
  89. package/dest/store/log_store_codec.d.ts +70 -0
  90. package/dest/store/log_store_codec.d.ts.map +1 -0
  91. package/dest/store/log_store_codec.js +101 -0
  92. package/dest/store/message_store.d.ts +50 -0
  93. package/dest/store/message_store.d.ts.map +1 -0
  94. package/dest/{archiver/kv_archiver_store → store}/message_store.js +66 -23
  95. package/dest/structs/data_retrieval.d.ts +27 -0
  96. package/dest/structs/data_retrieval.d.ts.map +1 -0
  97. package/dest/structs/inbox_message.d.ts +15 -0
  98. package/dest/structs/inbox_message.d.ts.map +1 -0
  99. package/dest/{archiver/structs → structs}/inbox_message.js +6 -5
  100. package/dest/structs/published.d.ts +2 -0
  101. package/dest/structs/published.d.ts.map +1 -0
  102. package/dest/test/fake_l1_state.d.ts +214 -0
  103. package/dest/test/fake_l1_state.d.ts.map +1 -0
  104. package/dest/test/fake_l1_state.js +517 -0
  105. package/dest/test/index.d.ts +2 -1
  106. package/dest/test/index.d.ts.map +1 -1
  107. package/dest/test/index.js +4 -1
  108. package/dest/test/mock_archiver.d.ts +16 -8
  109. package/dest/test/mock_archiver.d.ts.map +1 -1
  110. package/dest/test/mock_archiver.js +19 -14
  111. package/dest/test/mock_l1_to_l2_message_source.d.ts +7 -6
  112. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  113. package/dest/test/mock_l1_to_l2_message_source.js +23 -12
  114. package/dest/test/mock_l2_block_source.d.ts +76 -40
  115. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  116. package/dest/test/mock_l2_block_source.js +362 -133
  117. package/dest/test/mock_structs.d.ts +83 -4
  118. package/dest/test/mock_structs.d.ts.map +1 -1
  119. package/dest/test/mock_structs.js +157 -11
  120. package/dest/test/noop_l1_archiver.d.ts +30 -0
  121. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  122. package/dest/test/noop_l1_archiver.js +85 -0
  123. package/package.json +20 -20
  124. package/src/archiver.ts +719 -0
  125. package/src/config.ts +108 -0
  126. package/src/errors.ts +203 -0
  127. package/src/factory.ts +179 -23
  128. package/src/index.ts +27 -3
  129. package/src/interfaces.ts +9 -0
  130. package/src/l1/README.md +55 -0
  131. package/src/l1/bin/retrieve-calldata.ts +194 -0
  132. package/src/l1/calldata_retriever.ts +522 -0
  133. package/src/l1/data_retrieval.ts +484 -0
  134. package/src/l1/debug_tx.ts +99 -0
  135. package/src/l1/spire_proposer.ts +152 -0
  136. package/src/l1/trace_tx.ts +128 -0
  137. package/src/l1/types.ts +13 -0
  138. package/src/l1/validate_historical_logs.ts +140 -0
  139. package/src/l1/validate_trace.ts +229 -0
  140. package/src/modules/contract_data_source_adapter.ts +55 -0
  141. package/src/modules/data_source_base.ts +495 -0
  142. package/src/modules/data_store_updater.ts +518 -0
  143. package/src/modules/instrumentation.ts +204 -0
  144. package/src/modules/l1_synchronizer.ts +1257 -0
  145. package/src/modules/outbox_trees_resolver.ts +199 -0
  146. package/src/modules/validation.ts +130 -0
  147. package/src/store/block_store.ts +1540 -0
  148. package/src/store/contract_class_store.ts +108 -0
  149. package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +53 -7
  150. package/src/store/data_stores.ts +104 -0
  151. package/src/store/function_names_cache.ts +37 -0
  152. package/src/store/l2_tips_cache.ts +35 -0
  153. package/src/store/log_store.ts +379 -0
  154. package/src/store/log_store_codec.ts +132 -0
  155. package/src/{archiver/kv_archiver_store → store}/message_store.ts +81 -28
  156. package/src/{archiver/structs → structs}/inbox_message.ts +7 -7
  157. package/src/structs/published.ts +1 -0
  158. package/src/test/fake_l1_state.ts +770 -0
  159. package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
  160. package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
  161. package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
  162. package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
  163. package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
  164. package/src/test/fixtures/trace_transaction-proxied.json +128 -0
  165. package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
  166. package/src/test/index.ts +4 -0
  167. package/src/test/mock_archiver.ts +23 -16
  168. package/src/test/mock_l1_to_l2_message_source.ts +19 -11
  169. package/src/test/mock_l2_block_source.ts +431 -145
  170. package/src/test/mock_structs.ts +289 -13
  171. package/src/test/noop_l1_archiver.ts +148 -0
  172. package/dest/archiver/archiver.d.ts +0 -277
  173. package/dest/archiver/archiver.d.ts.map +0 -1
  174. package/dest/archiver/archiver.js +0 -1322
  175. package/dest/archiver/archiver_store.d.ts +0 -255
  176. package/dest/archiver/archiver_store.d.ts.map +0 -1
  177. package/dest/archiver/archiver_store.js +0 -4
  178. package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
  179. package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
  180. package/dest/archiver/archiver_store_test_suite.js +0 -1288
  181. package/dest/archiver/config.d.ts +0 -21
  182. package/dest/archiver/config.d.ts.map +0 -1
  183. package/dest/archiver/config.js +0 -50
  184. package/dest/archiver/data_retrieval.d.ts +0 -79
  185. package/dest/archiver/data_retrieval.d.ts.map +0 -1
  186. package/dest/archiver/data_retrieval.js +0 -362
  187. package/dest/archiver/errors.d.ts +0 -12
  188. package/dest/archiver/errors.d.ts.map +0 -1
  189. package/dest/archiver/errors.js +0 -17
  190. package/dest/archiver/index.d.ts +0 -7
  191. package/dest/archiver/index.d.ts.map +0 -1
  192. package/dest/archiver/index.js +0 -4
  193. package/dest/archiver/instrumentation.d.ts +0 -35
  194. package/dest/archiver/instrumentation.d.ts.map +0 -1
  195. package/dest/archiver/instrumentation.js +0 -140
  196. package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -124
  197. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
  198. package/dest/archiver/kv_archiver_store/block_store.js +0 -370
  199. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -18
  200. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
  201. package/dest/archiver/kv_archiver_store/contract_class_store.js +0 -120
  202. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -24
  203. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
  204. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -168
  205. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
  206. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +0 -296
  207. package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -49
  208. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
  209. package/dest/archiver/kv_archiver_store/log_store.js +0 -336
  210. package/dest/archiver/kv_archiver_store/message_store.d.ts +0 -39
  211. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
  212. package/dest/archiver/structs/data_retrieval.d.ts +0 -27
  213. package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
  214. package/dest/archiver/structs/inbox_message.d.ts +0 -15
  215. package/dest/archiver/structs/inbox_message.d.ts.map +0 -1
  216. package/dest/archiver/structs/published.d.ts +0 -2
  217. package/dest/archiver/structs/published.d.ts.map +0 -1
  218. package/dest/archiver/validation.d.ts +0 -11
  219. package/dest/archiver/validation.d.ts.map +0 -1
  220. package/dest/archiver/validation.js +0 -90
  221. package/dest/rpc/index.d.ts +0 -9
  222. package/dest/rpc/index.d.ts.map +0 -1
  223. package/dest/rpc/index.js +0 -15
  224. package/src/archiver/archiver.ts +0 -1722
  225. package/src/archiver/archiver_store.ts +0 -305
  226. package/src/archiver/archiver_store_test_suite.ts +0 -1263
  227. package/src/archiver/config.ts +0 -74
  228. package/src/archiver/data_retrieval.ts +0 -545
  229. package/src/archiver/errors.ts +0 -26
  230. package/src/archiver/index.ts +0 -6
  231. package/src/archiver/instrumentation.ts +0 -187
  232. package/src/archiver/kv_archiver_store/block_store.ts +0 -481
  233. package/src/archiver/kv_archiver_store/contract_class_store.ts +0 -176
  234. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +0 -422
  235. package/src/archiver/kv_archiver_store/log_store.ts +0 -406
  236. package/src/archiver/structs/published.ts +0 -1
  237. package/src/archiver/validation.ts +0 -99
  238. package/src/rpc/index.ts +0 -16
  239. /package/dest/{archiver/structs → structs}/data_retrieval.js +0 -0
  240. /package/dest/{archiver/structs → structs}/published.js +0 -0
  241. /package/src/{archiver/structs → structs}/data_retrieval.ts +0 -0
@@ -1,22 +1,48 @@
1
1
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
2
- import { DefaultL1ContractsConfig } from '@aztec/ethereum';
2
+ import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
3
+ import {
4
+ BlockNumber,
5
+ CheckpointNumber,
6
+ EpochNumber,
7
+ IndexWithinCheckpoint,
8
+ SlotNumber,
9
+ } from '@aztec/foundation/branded-types';
3
10
  import { Buffer32 } from '@aztec/foundation/buffer';
11
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
12
  import { EthAddress } from '@aztec/foundation/eth-address';
5
- import { Fr } from '@aztec/foundation/fields';
6
13
  import { createLogger } from '@aztec/foundation/log';
7
14
  import type { FunctionSelector } from '@aztec/stdlib/abi';
8
15
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
9
16
  import {
17
+ type BlockData,
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,
10
27
  L2Block,
11
- L2BlockHash,
12
28
  type L2BlockSource,
13
29
  type L2Tips,
14
- PublishedL2Block,
15
- type ValidateBlockResult,
30
+ type ProposedCheckpointQuery,
31
+ type ValidateCheckpointResult,
16
32
  } from '@aztec/stdlib/block';
33
+ import {
34
+ Checkpoint,
35
+ type CheckpointData,
36
+ L1PublishedData,
37
+ type ProposedCheckpointData,
38
+ PublishedCheckpoint,
39
+ } from '@aztec/stdlib/checkpoint';
17
40
  import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
18
41
  import { EmptyL1RollupConstants, type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
19
- import { type BlockHeader, TxHash, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
42
+ import { computeCheckpointOutHash } from '@aztec/stdlib/messaging';
43
+ import { CheckpointHeader } from '@aztec/stdlib/rollup';
44
+ import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
45
+ import { BlockHeader, TxHash } from '@aztec/stdlib/tx';
20
46
  import type { UInt64 } from '@aztec/stdlib/types';
21
47
 
22
48
  /**
@@ -24,29 +50,123 @@ import type { UInt64 } from '@aztec/stdlib/types';
24
50
  */
25
51
  export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
26
52
  protected l2Blocks: L2Block[] = [];
53
+ protected checkpointList: Checkpoint[] = [];
27
54
 
28
55
  private provenBlockNumber: number = 0;
29
56
  private finalizedBlockNumber: number = 0;
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;
30
64
 
31
65
  private log = createLogger('archiver:mock_l2_block_source');
32
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
+
120
+ /** Creates blocks grouped into single-block checkpoints. */
33
121
  public async createBlocks(numBlocks: number) {
34
- for (let i = 0; i < numBlocks; i++) {
35
- const blockNum = this.l2Blocks.length + 1;
36
- const block = await L2Block.random(blockNum);
37
- this.l2Blocks.push(block);
122
+ await this.createCheckpoints(numBlocks, 1);
123
+ }
124
+
125
+ public getCheckpointNumber(): Promise<CheckpointNumber> {
126
+ return Promise.resolve(
127
+ this.checkpointList.length === 0 ? CheckpointNumber.ZERO : CheckpointNumber(this.checkpointList.length),
128
+ );
129
+ }
130
+
131
+ /** Creates checkpoints, each containing `blocksPerCheckpoint` blocks. */
132
+ public async createCheckpoints(numCheckpoints: number, blocksPerCheckpoint: number = 1) {
133
+ for (let c = 0; c < numCheckpoints; c++) {
134
+ const checkpointNum = CheckpointNumber(this.checkpointList.length + 1);
135
+ const startBlockNum = this.l2Blocks.length + 1;
136
+ const slotNumber = SlotNumber(Number(checkpointNum));
137
+ const checkpoint = await Checkpoint.random(checkpointNum, {
138
+ numBlocks: blocksPerCheckpoint,
139
+ startBlockNumber: startBlockNum,
140
+ slotNumber,
141
+ checkpointNumber: checkpointNum,
142
+ });
143
+ this.checkpointList.push(checkpoint);
144
+ this.l2Blocks.push(...checkpoint.blocks);
38
145
  }
39
146
 
40
- this.log.verbose(`Created ${numBlocks} blocks in the mock L2 block source`);
147
+ this.log.verbose(
148
+ `Created ${numCheckpoints} checkpoints with ${blocksPerCheckpoint} blocks each in the mock L2 block source`,
149
+ );
41
150
  }
42
151
 
43
- public addBlocks(blocks: L2Block[]) {
152
+ public addProposedBlocks(blocks: L2Block[]) {
44
153
  this.l2Blocks.push(...blocks);
45
- this.log.verbose(`Added ${blocks.length} blocks to the mock L2 block source`);
154
+ this.log.verbose(`Added ${blocks.length} proposed blocks to the mock L2 block source`);
46
155
  }
47
156
 
48
157
  public removeBlocks(numBlocks: number) {
49
158
  this.l2Blocks = this.l2Blocks.slice(0, -numBlocks);
159
+ const maxBlockNum = this.l2Blocks.length;
160
+ // Remove any checkpoint whose last block is beyond the remaining blocks.
161
+ this.checkpointList = this.checkpointList.filter(c => {
162
+ const lastBlockNum = c.blocks[0].number + c.blocks.length - 1;
163
+ return lastBlockNum <= maxBlockNum;
164
+ });
165
+ // Keep tip numbers consistent with remaining blocks.
166
+ this.checkpointedBlockNumber = Math.min(this.checkpointedBlockNumber, maxBlockNum);
167
+ this.proposedCheckpointBlockNumber = Math.min(this.proposedCheckpointBlockNumber, maxBlockNum);
168
+ this.provenBlockNumber = Math.min(this.provenBlockNumber, maxBlockNum);
169
+ this.finalizedBlockNumber = Math.min(this.finalizedBlockNumber, maxBlockNum);
50
170
  this.log.verbose(`Removed ${numBlocks} blocks from the mock L2 block source`);
51
171
  }
52
172
 
@@ -61,6 +181,44 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
61
181
  this.finalizedBlockNumber = finalizedBlockNumber;
62
182
  }
63
183
 
184
+ public setProposedCheckpointBlockNumber(blockNumber: number) {
185
+ this.proposedCheckpointBlockNumber = blockNumber;
186
+ }
187
+
188
+ public setCheckpointedBlockNumber(checkpointedBlockNumber: number) {
189
+ const prevCheckpointed = this.checkpointedBlockNumber;
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
+ }
195
+ // Auto-create single-block checkpoints for newly checkpointed blocks that don't have one yet.
196
+ // This handles blocks added via addProposedBlocks that are now being marked as checkpointed.
197
+ const newCheckpoints: Checkpoint[] = [];
198
+ for (let blockNum = prevCheckpointed + 1; blockNum <= checkpointedBlockNumber; blockNum++) {
199
+ const block = this.l2Blocks[blockNum - 1];
200
+ if (!block) {
201
+ continue;
202
+ }
203
+ if (this.checkpointList.some(c => c.blocks.some(b => b.number === block.number))) {
204
+ continue;
205
+ }
206
+ const checkpointNum = CheckpointNumber(this.checkpointList.length + newCheckpoints.length + 1);
207
+ const checkpoint = new Checkpoint(
208
+ block.archive,
209
+ CheckpointHeader.random({ slotNumber: block.header.globalVariables.slotNumber }),
210
+ [block],
211
+ checkpointNum,
212
+ );
213
+ newCheckpoints.push(checkpoint);
214
+ }
215
+ // Insert new checkpoints in order by number.
216
+ if (newCheckpoints.length > 0) {
217
+ this.checkpointList.push(...newCheckpoints);
218
+ this.checkpointList.sort((a, b) => a.number - b.number);
219
+ }
220
+ }
221
+
64
222
  /**
65
223
  * Method to fetch the rollup contract address at the base-layer.
66
224
  * @returns The rollup address.
@@ -81,120 +239,110 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
81
239
  * Gets the number of the latest L2 block processed by the block source implementation.
82
240
  * @returns In this mock instance, returns the number of L2 blocks that we've mocked.
83
241
  */
84
- public getBlockNumber() {
85
- return Promise.resolve(this.l2Blocks.length);
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);
247
+ }
248
+ if ('number' in query) {
249
+ return query.number;
250
+ }
251
+ if ('tag' in query) {
252
+ return BlockNumber(this.resolveBlockTag(query.tag));
253
+ }
254
+ const block = await this.getBlock(query);
255
+ return block ? block.header.globalVariables.blockNumber : undefined;
86
256
  }
87
257
 
88
- public getProvenBlockNumber(): Promise<number> {
89
- return Promise.resolve(this.provenBlockNumber);
258
+ public getProposedCheckpointL2BlockNumber() {
259
+ return Promise.resolve(BlockNumber(this.proposedCheckpointBlockNumber));
90
260
  }
91
261
 
92
- /**
93
- * Gets an l2 block.
94
- * @param number - The block number to return (inclusive).
95
- * @returns The requested L2 block.
96
- */
97
- public getBlock(number: number) {
98
- return Promise.resolve(this.l2Blocks[number - 1]);
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), []));
99
268
  }
100
269
 
101
- /**
102
- * Gets up to `limit` amount of L2 blocks starting from `from`.
103
- * @param from - Number of the first block to return (inclusive).
104
- * @param limit - The maximum number of blocks to return.
105
- * @returns The requested mocked L2 blocks.
106
- */
107
- public getBlocks(from: number, limit: number, proven?: boolean) {
270
+ public getCheckpoints(query: CheckpointsQuery): Promise<PublishedCheckpoint[]> {
271
+ const checkpoints = this.resolveCheckpointsQuery(query);
108
272
  return Promise.resolve(
109
- this.l2Blocks
110
- .slice(from - 1, from - 1 + limit)
111
- .filter(b => !proven || this.provenBlockNumber === undefined || b.number <= this.provenBlockNumber),
273
+ checkpoints.map(checkpoint => new PublishedCheckpoint(checkpoint, this.mockL1DataForCheckpoint(checkpoint), [])),
112
274
  );
113
275
  }
114
276
 
115
- public async getPublishedBlocks(from: number, limit: number, proven?: boolean) {
116
- const blocks = await this.getBlocks(from, limit, proven);
117
- return blocks.map(block =>
118
- PublishedL2Block.fromFields({
119
- block,
120
- l1: {
121
- blockNumber: BigInt(block.number),
122
- blockHash: Buffer32.random().toString(),
123
- timestamp: BigInt(block.number),
124
- },
125
- attestations: [],
126
- }),
127
- );
277
+ public getCheckpointByArchive(archive: Fr): Promise<Checkpoint | undefined> {
278
+ const checkpoint = this.checkpointList.find(c => c.archive.root.equals(archive));
279
+ return Promise.resolve(checkpoint);
128
280
  }
129
281
 
130
- public async getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined> {
131
- for (const block of this.l2Blocks) {
132
- const hash = await block.hash();
133
- if (hash.equals(blockHash)) {
134
- return PublishedL2Block.fromFields({
135
- block,
136
- l1: {
137
- blockNumber: BigInt(block.number),
138
- blockHash: Buffer32.random().toString(),
139
- timestamp: BigInt(block.number),
140
- },
141
- attestations: [],
142
- });
143
- }
144
- }
145
- return undefined;
146
- }
147
-
148
- public getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
149
- const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
150
- if (!block) {
282
+ public getCheckpointData(query: CheckpointQuery): Promise<CheckpointData | undefined> {
283
+ const checkpoint = this.resolveCheckpointQuery(query);
284
+ if (!checkpoint) {
151
285
  return Promise.resolve(undefined);
152
286
  }
153
- return Promise.resolve(
154
- PublishedL2Block.fromFields({
155
- block,
156
- l1: {
157
- blockNumber: BigInt(block.number),
158
- blockHash: Buffer32.random().toString(),
159
- timestamp: BigInt(block.number),
160
- },
161
- attestations: [],
162
- }),
163
- );
287
+ return Promise.resolve(this.checkpointToData(checkpoint));
164
288
  }
165
289
 
166
- public async getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
167
- for (const block of this.l2Blocks) {
168
- const hash = await block.hash();
169
- if (hash.equals(blockHash)) {
170
- return block.getBlockHeader();
171
- }
172
- }
173
- return undefined;
290
+ public getCheckpointsData(query: CheckpointsQuery): Promise<CheckpointData[]> {
291
+ const checkpoints = this.resolveCheckpointsQuery(query);
292
+ return Promise.resolve(checkpoints.map(c => this.checkpointToData(c)));
174
293
  }
175
294
 
176
- public getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
177
- const block = this.l2Blocks.find(b => b.archive.root.equals(archive));
178
- return Promise.resolve(block?.getBlockHeader());
295
+ private checkpointToData(checkpoint: Checkpoint): CheckpointData {
296
+ return {
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),
308
+ };
179
309
  }
180
310
 
181
- getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
182
- return Promise.resolve(this.l2Blocks.at(typeof number === 'number' ? number - 1 : -1)?.getBlockHeader());
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
+ }
333
+ }
183
334
  }
184
335
 
185
- getBlocksForEpoch(epochNumber: bigint): Promise<L2Block[]> {
186
- const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
187
- const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
188
- const blocks = this.l2Blocks.filter(b => {
189
- const slot = b.header.globalVariables.slotNumber.toBigInt();
190
- return slot >= start && slot <= end;
191
- });
192
- return Promise.resolve(blocks);
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);
193
341
  }
194
342
 
195
- async getBlockHeadersForEpoch(epochNumber: bigint): Promise<BlockHeader[]> {
196
- const blocks = await this.getBlocksForEpoch(epochNumber);
197
- return blocks.map(b => b.getBlockHeader());
343
+ getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
344
+ const blocks = this.l2Blocks.filter(b => b.header.globalVariables.slotNumber === slotNumber);
345
+ return Promise.resolve(blocks);
198
346
  }
199
347
 
200
348
  /**
@@ -213,70 +361,93 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
213
361
  return {
214
362
  data: txEffect,
215
363
  l2BlockNumber: block.number,
216
- l2BlockHash: L2BlockHash.fromField(await block.hash()),
217
- txIndexInBlock: block.body.txEffects.indexOf(txEffect),
364
+ l2BlockHash: await block.hash(),
365
+ txIndexInBlock: block.body.txEffects.findIndex(t => t.txHash.equals(txHash)),
366
+ slotNumber: block.header.globalVariables.slotNumber,
218
367
  };
219
368
  }
220
369
 
221
- /**
222
- * Gets a receipt of a settled tx.
223
- * @param txHash - The hash of a tx we try to get the receipt for.
224
- * @returns The requested tx receipt (or undefined if not found).
225
- */
226
- public async getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
227
- for (const block of this.l2Blocks) {
228
- for (const txEffect of block.body.txEffects) {
229
- if (txEffect.txHash.equals(txHash)) {
230
- return new TxReceipt(
231
- txHash,
232
- TxStatus.SUCCESS,
233
- '',
234
- txEffect.transactionFee.toBigInt(),
235
- L2BlockHash.fromField(await block.hash()),
236
- block.number,
237
- );
238
- }
239
- }
240
- }
241
- return undefined;
370
+ public getL2ToL1MembershipWitness(): Promise<undefined> {
371
+ // Mock does not back the L2-to-L1 message witness flow.
372
+ return Promise.resolve(undefined);
242
373
  }
243
374
 
244
375
  async getL2Tips(): Promise<L2Tips> {
245
- const [latest, proven, finalized] = [
376
+ const [latest, proven, finalized, checkpointed, proposedCheckpoint] = [
246
377
  await this.getBlockNumber(),
247
- await this.getProvenBlockNumber(),
378
+ this.provenBlockNumber,
248
379
  this.finalizedBlockNumber,
380
+ this.checkpointedBlockNumber,
381
+ await this.getProposedCheckpointL2BlockNumber(),
249
382
  ] as const;
250
383
 
251
384
  const latestBlock = this.l2Blocks[latest - 1];
252
385
  const provenBlock = this.l2Blocks[proven - 1];
253
386
  const finalizedBlock = this.l2Blocks[finalized - 1];
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
+ };
399
+
400
+ const latestBlockId = {
401
+ number: BlockNumber(latest),
402
+ hash: await tipHash(latestBlock, latest),
403
+ };
404
+ const provenBlockId = {
405
+ number: BlockNumber(proven),
406
+ hash: await tipHash(provenBlock, proven),
407
+ };
408
+ const finalizedBlockId = {
409
+ number: BlockNumber(finalized),
410
+ hash: await tipHash(finalizedBlock, finalized),
411
+ };
412
+ const checkpointedBlockId = {
413
+ number: BlockNumber(checkpointed),
414
+ hash: await tipHash(checkpointedBlock, checkpointed),
415
+ };
416
+ const proposedCheckpointBlockId = {
417
+ number: BlockNumber(proposedCheckpoint),
418
+ hash: await tipHash(proposedCheckpointBlock, proposedCheckpoint),
419
+ };
420
+
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
+ };
254
432
 
255
433
  return {
256
- latest: {
257
- number: latest,
258
- hash: (await latestBlock?.hash())?.toString(),
259
- },
260
- proven: {
261
- number: proven,
262
- hash: (await provenBlock?.hash())?.toString(),
263
- },
264
- finalized: {
265
- number: finalized,
266
- hash: (await finalizedBlock?.hash())?.toString(),
267
- },
434
+ proposed: latestBlockId,
435
+ checkpointed: makeTipId(checkpointedBlockId),
436
+ proven: makeTipId(provenBlockId),
437
+ finalized: makeTipId(finalizedBlockId),
438
+ proposedCheckpoint: makeTipId(proposedCheckpointBlockId),
268
439
  };
269
440
  }
270
441
 
271
- getL2EpochNumber(): Promise<bigint> {
442
+ getSyncedL2EpochNumber(): Promise<EpochNumber> {
272
443
  throw new Error('Method not implemented.');
273
444
  }
274
445
 
275
- getL2SlotNumber(): Promise<bigint> {
446
+ getSyncedL2SlotNumber(): Promise<SlotNumber> {
276
447
  throw new Error('Method not implemented.');
277
448
  }
278
449
 
279
- isEpochComplete(_epochNumber: bigint): Promise<boolean> {
450
+ isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
280
451
  throw new Error('Method not implemented.');
281
452
  }
282
453
 
@@ -284,8 +455,12 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
284
455
  return Promise.resolve(EmptyL1RollupConstants);
285
456
  }
286
457
 
458
+ isPruneDueAtSlot(_slot: SlotNumber): Promise<boolean> {
459
+ return Promise.resolve(false);
460
+ }
461
+
287
462
  getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
288
- return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
463
+ return Promise.resolve({ genesisArchiveRoot: this.genesisArchiveRoot ?? new Fr(GENESIS_ARCHIVE_ROOT) });
289
464
  }
290
465
 
291
466
  getL1Timestamp(): Promise<bigint> {
@@ -338,11 +513,122 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource {
338
513
  return Promise.resolve();
339
514
  }
340
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
+
341
605
  isPendingChainInvalid(): Promise<boolean> {
342
606
  return Promise.resolve(false);
343
607
  }
344
608
 
345
- getPendingChainValidationStatus(): Promise<ValidateBlockResult> {
609
+ getPendingChainValidationStatus(): Promise<ValidateCheckpointResult> {
346
610
  return Promise.resolve({ valid: true });
347
611
  }
612
+
613
+ getProposedCheckpointData(_query?: ProposedCheckpointQuery): Promise<ProposedCheckpointData | undefined> {
614
+ return Promise.resolve(undefined);
615
+ }
616
+
617
+ /** Returns checkpoints whose slot falls within the given epoch. */
618
+ private getCheckpointsInEpoch(epochNumber: EpochNumber): Checkpoint[] {
619
+ const epochDuration = DefaultL1ContractsConfig.aztecEpochDuration;
620
+ const [start, end] = getSlotRangeForEpoch(epochNumber, { epochDuration });
621
+ return this.checkpointList.filter(c => c.header.slotNumber >= start && c.header.slotNumber <= end);
622
+ }
623
+
624
+ /** Creates a mock L1PublishedData for a checkpoint. */
625
+ private mockL1DataForCheckpoint(checkpoint: Checkpoint): L1PublishedData {
626
+ return new L1PublishedData(BigInt(checkpoint.number), BigInt(checkpoint.number), Buffer32.random().toString());
627
+ }
628
+
629
+ /** Finds the checkpoint number for a block, or undefined if the block is not in any checkpoint. */
630
+ private findCheckpointNumberForBlock(blockNumber: BlockNumber): CheckpointNumber | undefined {
631
+ const checkpoint = this.checkpointList.find(c => c.blocks.some(b => b.number === blockNumber));
632
+ return checkpoint?.number;
633
+ }
348
634
  }