@aztec/archiver 0.0.1-commit.d3ec352c → 0.0.1-commit.f295ac2

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 (201) hide show
  1. package/README.md +147 -22
  2. package/dest/archiver.d.ts +135 -0
  3. package/dest/archiver.d.ts.map +1 -0
  4. package/dest/archiver.js +769 -0
  5. package/dest/config.d.ts +30 -0
  6. package/dest/config.d.ts.map +1 -0
  7. package/dest/{archiver/config.js → config.js} +21 -5
  8. package/dest/errors.d.ts +36 -0
  9. package/dest/errors.d.ts.map +1 -0
  10. package/dest/errors.js +54 -0
  11. package/dest/factory.d.ts +5 -6
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +82 -5
  14. package/dest/index.d.ts +10 -4
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +8 -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 +149 -0
  23. package/dest/l1/calldata_retriever.d.ts +112 -0
  24. package/dest/l1/calldata_retriever.d.ts.map +1 -0
  25. package/dest/l1/calldata_retriever.js +471 -0
  26. package/dest/l1/data_retrieval.d.ts +88 -0
  27. package/dest/l1/data_retrieval.d.ts.map +1 -0
  28. package/dest/{archiver → l1}/data_retrieval.js +75 -150
  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 +157 -0
  35. package/dest/l1/trace_tx.d.ts +97 -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_trace.d.ts +29 -0
  42. package/dest/l1/validate_trace.d.ts.map +1 -0
  43. package/dest/l1/validate_trace.js +150 -0
  44. package/dest/modules/data_source_base.d.ts +85 -0
  45. package/dest/modules/data_source_base.d.ts.map +1 -0
  46. package/dest/modules/data_source_base.js +291 -0
  47. package/dest/modules/data_store_updater.d.ts +69 -0
  48. package/dest/modules/data_store_updater.d.ts.map +1 -0
  49. package/dest/modules/data_store_updater.js +304 -0
  50. package/dest/modules/instrumentation.d.ts +37 -0
  51. package/dest/modules/instrumentation.d.ts.map +1 -0
  52. package/dest/{archiver → modules}/instrumentation.js +22 -59
  53. package/dest/modules/l1_synchronizer.d.ts +75 -0
  54. package/dest/modules/l1_synchronizer.d.ts.map +1 -0
  55. package/dest/modules/l1_synchronizer.js +1113 -0
  56. package/dest/modules/validation.d.ts +17 -0
  57. package/dest/modules/validation.d.ts.map +1 -0
  58. package/dest/{archiver → modules}/validation.js +7 -1
  59. package/dest/store/block_store.d.ts +178 -0
  60. package/dest/store/block_store.d.ts.map +1 -0
  61. package/dest/store/block_store.js +680 -0
  62. package/dest/store/contract_class_store.d.ts +18 -0
  63. package/dest/store/contract_class_store.d.ts.map +1 -0
  64. package/dest/{archiver/kv_archiver_store → store}/contract_class_store.js +2 -2
  65. package/dest/store/contract_instance_store.d.ts +24 -0
  66. package/dest/store/contract_instance_store.d.ts.map +1 -0
  67. package/dest/{archiver/kv_archiver_store → store}/contract_instance_store.js +1 -1
  68. package/dest/store/kv_archiver_store.d.ts +331 -0
  69. package/dest/store/kv_archiver_store.d.ts.map +1 -0
  70. package/dest/store/kv_archiver_store.js +438 -0
  71. package/dest/store/log_store.d.ts +45 -0
  72. package/dest/store/log_store.d.ts.map +1 -0
  73. package/dest/store/log_store.js +422 -0
  74. package/dest/store/message_store.d.ts +40 -0
  75. package/dest/store/message_store.d.ts.map +1 -0
  76. package/dest/{archiver/kv_archiver_store → store}/message_store.js +15 -14
  77. package/dest/{archiver/structs → structs}/data_retrieval.d.ts +1 -1
  78. package/dest/structs/data_retrieval.d.ts.map +1 -0
  79. package/dest/structs/inbox_message.d.ts +15 -0
  80. package/dest/structs/inbox_message.d.ts.map +1 -0
  81. package/dest/{archiver/structs → structs}/inbox_message.js +6 -6
  82. package/dest/structs/published.d.ts +2 -0
  83. package/dest/structs/published.d.ts.map +1 -0
  84. package/dest/test/fake_l1_state.d.ts +190 -0
  85. package/dest/test/fake_l1_state.d.ts.map +1 -0
  86. package/dest/test/fake_l1_state.js +383 -0
  87. package/dest/test/index.d.ts +2 -1
  88. package/dest/test/index.d.ts.map +1 -1
  89. package/dest/test/index.js +1 -0
  90. package/dest/test/mock_archiver.d.ts +5 -6
  91. package/dest/test/mock_archiver.d.ts.map +1 -1
  92. package/dest/test/mock_archiver.js +6 -11
  93. package/dest/test/mock_l1_to_l2_message_source.d.ts +6 -7
  94. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  95. package/dest/test/mock_l1_to_l2_message_source.js +19 -14
  96. package/dest/test/mock_l2_block_source.d.ts +28 -14
  97. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  98. package/dest/test/mock_l2_block_source.js +160 -52
  99. package/dest/test/mock_structs.d.ts +78 -3
  100. package/dest/test/mock_structs.d.ts.map +1 -1
  101. package/dest/test/mock_structs.js +141 -10
  102. package/package.json +17 -18
  103. package/src/archiver.ts +525 -0
  104. package/src/{archiver/config.ts → config.ts} +28 -12
  105. package/src/errors.ts +90 -0
  106. package/src/factory.ts +118 -6
  107. package/src/index.ts +10 -3
  108. package/src/interfaces.ts +9 -0
  109. package/src/l1/README.md +98 -0
  110. package/src/l1/bin/retrieve-calldata.ts +182 -0
  111. package/src/l1/calldata_retriever.ts +641 -0
  112. package/src/{archiver → l1}/data_retrieval.ts +136 -218
  113. package/src/l1/debug_tx.ts +99 -0
  114. package/src/l1/spire_proposer.ts +160 -0
  115. package/src/l1/trace_tx.ts +128 -0
  116. package/src/l1/types.ts +13 -0
  117. package/src/l1/validate_trace.ts +211 -0
  118. package/src/modules/data_source_base.ts +414 -0
  119. package/src/modules/data_store_updater.ts +419 -0
  120. package/src/{archiver → modules}/instrumentation.ts +24 -59
  121. package/src/modules/l1_synchronizer.ts +931 -0
  122. package/src/{archiver → modules}/validation.ts +11 -6
  123. package/src/store/block_store.ts +919 -0
  124. package/src/{archiver/kv_archiver_store → store}/contract_class_store.ts +2 -2
  125. package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +2 -2
  126. package/src/store/kv_archiver_store.ts +622 -0
  127. package/src/store/log_store.ts +552 -0
  128. package/src/{archiver/kv_archiver_store → store}/message_store.ts +21 -18
  129. package/src/{archiver/structs → structs}/inbox_message.ts +7 -8
  130. package/src/{archiver/structs → structs}/published.ts +0 -1
  131. package/src/test/fake_l1_state.ts +599 -0
  132. package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
  133. package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
  134. package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
  135. package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
  136. package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
  137. package/src/test/fixtures/trace_transaction-proxied.json +128 -0
  138. package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
  139. package/src/test/index.ts +1 -0
  140. package/src/test/mock_archiver.ts +8 -13
  141. package/src/test/mock_l1_to_l2_message_source.ts +16 -15
  142. package/src/test/mock_l2_block_source.ts +184 -64
  143. package/src/test/mock_structs.ts +256 -11
  144. package/dest/archiver/archiver.d.ts +0 -290
  145. package/dest/archiver/archiver.d.ts.map +0 -1
  146. package/dest/archiver/archiver.js +0 -1434
  147. package/dest/archiver/archiver_store.d.ts +0 -256
  148. package/dest/archiver/archiver_store.d.ts.map +0 -1
  149. package/dest/archiver/archiver_store.js +0 -4
  150. package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
  151. package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
  152. package/dest/archiver/archiver_store_test_suite.js +0 -1289
  153. package/dest/archiver/config.d.ts +0 -21
  154. package/dest/archiver/config.d.ts.map +0 -1
  155. package/dest/archiver/data_retrieval.d.ts +0 -80
  156. package/dest/archiver/data_retrieval.d.ts.map +0 -1
  157. package/dest/archiver/errors.d.ts +0 -12
  158. package/dest/archiver/errors.d.ts.map +0 -1
  159. package/dest/archiver/errors.js +0 -17
  160. package/dest/archiver/index.d.ts +0 -7
  161. package/dest/archiver/index.d.ts.map +0 -1
  162. package/dest/archiver/index.js +0 -4
  163. package/dest/archiver/instrumentation.d.ts +0 -35
  164. package/dest/archiver/instrumentation.d.ts.map +0 -1
  165. package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -125
  166. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
  167. package/dest/archiver/kv_archiver_store/block_store.js +0 -371
  168. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -18
  169. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
  170. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -24
  171. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
  172. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -169
  173. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
  174. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +0 -296
  175. package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -49
  176. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
  177. package/dest/archiver/kv_archiver_store/log_store.js +0 -337
  178. package/dest/archiver/kv_archiver_store/message_store.d.ts +0 -39
  179. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
  180. package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
  181. package/dest/archiver/structs/inbox_message.d.ts +0 -15
  182. package/dest/archiver/structs/inbox_message.d.ts.map +0 -1
  183. package/dest/archiver/structs/published.d.ts +0 -3
  184. package/dest/archiver/structs/published.d.ts.map +0 -1
  185. package/dest/archiver/validation.d.ts +0 -17
  186. package/dest/archiver/validation.d.ts.map +0 -1
  187. package/dest/rpc/index.d.ts +0 -9
  188. package/dest/rpc/index.d.ts.map +0 -1
  189. package/dest/rpc/index.js +0 -15
  190. package/src/archiver/archiver.ts +0 -1880
  191. package/src/archiver/archiver_store.ts +0 -310
  192. package/src/archiver/archiver_store_test_suite.ts +0 -1295
  193. package/src/archiver/errors.ts +0 -26
  194. package/src/archiver/index.ts +0 -6
  195. package/src/archiver/kv_archiver_store/block_store.ts +0 -482
  196. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +0 -423
  197. package/src/archiver/kv_archiver_store/log_store.ts +0 -407
  198. package/src/rpc/index.ts +0 -16
  199. /package/dest/{archiver/structs → structs}/data_retrieval.js +0 -0
  200. /package/dest/{archiver/structs → structs}/published.js +0 -0
  201. /package/src/{archiver/structs → structs}/data_retrieval.ts +0 -0
@@ -1,3 +1,4 @@
1
+ import type { BlobClientInterface } from '@aztec/blob-client/client';
1
2
  import {
2
3
  BlobDeserializationError,
3
4
  type CheckpointBlobData,
@@ -5,43 +6,34 @@ import {
5
6
  decodeCheckpointBlobDataFromBlobs,
6
7
  encodeBlockBlobData,
7
8
  } from '@aztec/blob-lib';
8
- import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
9
9
  import type {
10
+ CheckpointProposedLog,
10
11
  EpochProofPublicInputArgs,
11
- ViemClient,
12
- ViemCommitteeAttestations,
13
- ViemHeader,
14
- ViemPublicClient,
15
- } from '@aztec/ethereum';
12
+ InboxContract,
13
+ MessageSentLog,
14
+ RollupContract,
15
+ } from '@aztec/ethereum/contracts';
16
+ import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
16
17
  import { asyncPool } from '@aztec/foundation/async-pool';
17
- import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
18
- import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
19
- import type { EthAddress } from '@aztec/foundation/eth-address';
20
- import type { ViemSignature } from '@aztec/foundation/eth-signature';
21
- import { Fr } from '@aztec/foundation/fields';
18
+ import { CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
19
+ import { Fr } from '@aztec/foundation/curves/bn254';
20
+ import { EthAddress } from '@aztec/foundation/eth-address';
22
21
  import { type Logger, createLogger } from '@aztec/foundation/log';
23
- import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts';
22
+ import { RollupAbi } from '@aztec/l1-artifacts';
24
23
  import { Body, CommitteeAttestation, L2BlockNew } from '@aztec/stdlib/block';
25
- import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
24
+ import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
26
25
  import { Proof } from '@aztec/stdlib/proofs';
27
26
  import { CheckpointHeader } from '@aztec/stdlib/rollup';
28
27
  import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
29
28
  import { BlockHeader, GlobalVariables, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
30
29
 
31
- import {
32
- type GetContractEventsReturnType,
33
- type GetContractReturnType,
34
- type Hex,
35
- decodeFunctionData,
36
- getAbiItem,
37
- hexToBytes,
38
- multicall3Abi,
39
- } from 'viem';
40
-
41
- import { NoBlobBodiesFoundError } from './errors.js';
42
- import type { DataRetrieval } from './structs/data_retrieval.js';
43
- import type { InboxMessage } from './structs/inbox_message.js';
44
- import type { L1PublishedData } from './structs/published.js';
30
+ import { type Hex, decodeFunctionData, getAbiItem, hexToBytes } from 'viem';
31
+
32
+ import { NoBlobBodiesFoundError } from '../errors.js';
33
+ import type { ArchiverInstrumentation } from '../modules/instrumentation.js';
34
+ import type { DataRetrieval } from '../structs/data_retrieval.js';
35
+ import type { InboxMessage } from '../structs/inbox_message.js';
36
+ import { CalldataRetriever } from './calldata_retriever.js';
45
37
 
46
38
  export type RetrievedCheckpoint = {
47
39
  checkpointNumber: CheckpointNumber;
@@ -72,8 +64,8 @@ export async function retrievedToPublishedCheckpoint({
72
64
  .slice(1)
73
65
  .concat([archiveRoot]);
74
66
 
75
- // `blocksBlobData` is created from `decodeCheckpointBlobDataFromBlobs`. An error will be thrown if it can't read a
76
- // field for the `l1ToL2MessageRoot` of the first block. So below we can safely assume it exists:
67
+ // An error will be thrown from `decodeCheckpointBlobDataFromBlobs` if it can't read a field for the
68
+ // `l1ToL2MessageRoot` of the first block. So below we can safely assume it exists:
77
69
  const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
78
70
 
79
71
  const spongeBlob = SpongeBlob.init();
@@ -127,7 +119,7 @@ export async function retrievedToPublishedCheckpoint({
127
119
 
128
120
  const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
129
121
 
130
- l2Blocks.push(new L2BlockNew(newArchive, header, body));
122
+ l2Blocks.push(new L2BlockNew(newArchive, header, body, checkpointNumber, IndexWithinCheckpoint(i)));
131
123
  }
132
124
 
133
125
  const lastBlock = l2Blocks.at(-1)!;
@@ -143,20 +135,33 @@ export async function retrievedToPublishedCheckpoint({
143
135
 
144
136
  /**
145
137
  * Fetches new checkpoints.
138
+ * @param rollup - The rollup contract wrapper.
146
139
  * @param publicClient - The viem public client to use for transaction retrieval.
147
- * @param rollupAddress - The address of the rollup contract.
140
+ * @param debugClient - The viem debug client to use for trace/debug RPC methods (optional).
141
+ * @param blobClient - The blob client client for fetching blob data.
148
142
  * @param searchStartBlock - The block number to use for starting the search.
149
143
  * @param searchEndBlock - The highest block number that we should search up to.
150
- * @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
151
- * @returns An array of block; as well as the next eth block to search from.
144
+ * @param contractAddresses - The contract addresses (governanceProposerAddress, slashFactoryAddress, slashingProposerAddress).
145
+ * @param instrumentation - The archiver instrumentation instance.
146
+ * @param logger - The logger instance.
147
+ * @param isHistoricalSync - Whether this is a historical sync.
148
+ * @returns An array of retrieved checkpoints.
152
149
  */
153
150
  export async function retrieveCheckpointsFromRollup(
154
- rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
151
+ rollup: RollupContract,
155
152
  publicClient: ViemPublicClient,
156
- blobSinkClient: BlobSinkClientInterface,
153
+ debugClient: ViemPublicDebugClient,
154
+ blobClient: BlobClientInterface,
157
155
  searchStartBlock: bigint,
158
156
  searchEndBlock: bigint,
157
+ contractAddresses: {
158
+ governanceProposerAddress: EthAddress;
159
+ slashFactoryAddress?: EthAddress;
160
+ slashingProposerAddress: EthAddress;
161
+ },
162
+ instrumentation: ArchiverInstrumentation,
159
163
  logger: Logger = createLogger('archiver'),
164
+ isHistoricalSync: boolean = false,
160
165
  ): Promise<RetrievedCheckpoint[]> {
161
166
  const retrievedCheckpoints: RetrievedCheckpoint[] = [];
162
167
 
@@ -166,15 +171,7 @@ export async function retrieveCheckpointsFromRollup(
166
171
  if (searchStartBlock > searchEndBlock) {
167
172
  break;
168
173
  }
169
- const checkpointProposedLogs = (
170
- await rollup.getEvents.CheckpointProposed(
171
- {},
172
- {
173
- fromBlock: searchStartBlock,
174
- toBlock: searchEndBlock,
175
- },
176
- )
177
- ).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
174
+ const checkpointProposedLogs = await rollup.getCheckpointProposedEvents(searchStartBlock, searchEndBlock);
178
175
 
179
176
  if (checkpointProposedLogs.length === 0) {
180
177
  break;
@@ -182,32 +179,36 @@ export async function retrieveCheckpointsFromRollup(
182
179
 
183
180
  const lastLog = checkpointProposedLogs.at(-1)!;
184
181
  logger.debug(
185
- `Got ${checkpointProposedLogs.length} processed logs for checkpoints ${checkpointProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
182
+ `Got ${checkpointProposedLogs.length} processed logs for checkpoints ${checkpointProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
186
183
  );
187
184
 
188
185
  if (rollupConstants === undefined) {
189
186
  const [chainId, version, targetCommitteeSize] = await Promise.all([
190
187
  publicClient.getChainId(),
191
- rollup.read.getVersion(),
192
- rollup.read.getTargetCommitteeSize(),
188
+ rollup.getVersion(),
189
+ rollup.getTargetCommitteeSize(),
193
190
  ]);
194
191
  rollupConstants = {
195
192
  chainId: new Fr(chainId),
196
193
  version: new Fr(version),
197
- targetCommitteeSize: Number(targetCommitteeSize),
194
+ targetCommitteeSize,
198
195
  };
199
196
  }
200
197
 
201
198
  const newCheckpoints = await processCheckpointProposedLogs(
202
199
  rollup,
203
200
  publicClient,
204
- blobSinkClient,
201
+ debugClient,
202
+ blobClient,
205
203
  checkpointProposedLogs,
206
204
  rollupConstants,
205
+ contractAddresses,
206
+ instrumentation,
207
207
  logger,
208
+ isHistoricalSync,
208
209
  );
209
210
  retrievedCheckpoints.push(...newCheckpoints);
210
- searchStartBlock = lastLog.blockNumber! + 1n;
211
+ searchStartBlock = lastLog.l1BlockNumber + 1n;
211
212
  } while (searchStartBlock <= searchEndBlock);
212
213
 
213
214
  // The asyncPool from processCheckpointProposedLogs will not necessarily return the checkpoints in order, so we sort them before returning.
@@ -216,56 +217,90 @@ export async function retrieveCheckpointsFromRollup(
216
217
 
217
218
  /**
218
219
  * Processes newly received CheckpointProposed logs.
219
- * @param rollup - The rollup contract
220
+ * @param rollup - The rollup contract wrapper.
220
221
  * @param publicClient - The viem public client to use for transaction retrieval.
222
+ * @param debugClient - The viem debug client to use for trace/debug RPC methods (optional).
223
+ * @param blobClient - The blob client client for fetching blob data.
221
224
  * @param logs - CheckpointProposed logs.
222
- * @returns - An array of checkpoints.
225
+ * @param rollupConstants - The rollup constants (chainId, version, targetCommitteeSize).
226
+ * @param contractAddresses - The contract addresses (governanceProposerAddress, slashFactoryAddress, slashingProposerAddress).
227
+ * @param instrumentation - The archiver instrumentation instance.
228
+ * @param logger - The logger instance.
229
+ * @param isHistoricalSync - Whether this is a historical sync.
230
+ * @returns An array of retrieved checkpoints.
223
231
  */
224
232
  async function processCheckpointProposedLogs(
225
- rollup: GetContractReturnType<typeof RollupAbi, ViemPublicClient>,
233
+ rollup: RollupContract,
226
234
  publicClient: ViemPublicClient,
227
- blobSinkClient: BlobSinkClientInterface,
228
- logs: GetContractEventsReturnType<typeof RollupAbi, 'CheckpointProposed'>,
235
+ debugClient: ViemPublicDebugClient,
236
+ blobClient: BlobClientInterface,
237
+ logs: CheckpointProposedLog[],
229
238
  { chainId, version, targetCommitteeSize }: { chainId: Fr; version: Fr; targetCommitteeSize: number },
239
+ contractAddresses: {
240
+ governanceProposerAddress: EthAddress;
241
+ slashFactoryAddress?: EthAddress;
242
+ slashingProposerAddress: EthAddress;
243
+ },
244
+ instrumentation: ArchiverInstrumentation,
230
245
  logger: Logger,
246
+ isHistoricalSync: boolean,
231
247
  ): Promise<RetrievedCheckpoint[]> {
232
248
  const retrievedCheckpoints: RetrievedCheckpoint[] = [];
249
+ const calldataRetriever = new CalldataRetriever(
250
+ publicClient,
251
+ debugClient,
252
+ targetCommitteeSize,
253
+ instrumentation,
254
+ logger,
255
+ { ...contractAddresses, rollupAddress: EthAddress.fromString(rollup.address) },
256
+ );
257
+
233
258
  await asyncPool(10, logs, async log => {
234
- const checkpointNumber = CheckpointNumber.fromBigInt(log.args.checkpointNumber!);
235
- const archive = log.args.archive!;
236
- const archiveFromChain = await rollup.read.archiveAt([BigInt(checkpointNumber)]);
237
- const blobHashes = log.args.versionedBlobHashes!.map(blobHash => Buffer.from(blobHash.slice(2), 'hex'));
259
+ const checkpointNumber = log.args.checkpointNumber;
260
+ const archive = log.args.archive;
261
+ const archiveFromChain = await rollup.archiveAt(checkpointNumber);
262
+ const blobHashes = log.args.versionedBlobHashes;
238
263
 
239
264
  // The value from the event and contract will match only if the checkpoint is in the chain.
240
- if (archive === archiveFromChain) {
241
- const checkpoint = await getCheckpointFromRollupTx(
242
- publicClient,
243
- blobSinkClient,
244
- log.transactionHash!,
265
+ if (archive.equals(archiveFromChain)) {
266
+ // Build expected hashes object (fields may be undefined for backwards compatibility with older events)
267
+ const expectedHashes = {
268
+ attestationsHash: log.args.attestationsHash?.toString(),
269
+ payloadDigest: log.args.payloadDigest?.toString(),
270
+ };
271
+
272
+ const checkpoint = await calldataRetriever.getCheckpointFromRollupTx(
273
+ log.l1TransactionHash,
274
+ blobHashes,
275
+ checkpointNumber,
276
+ expectedHashes,
277
+ );
278
+ const checkpointBlobData = await getCheckpointBlobDataFromBlobs(
279
+ blobClient,
280
+ checkpoint.blockHash,
245
281
  blobHashes,
246
282
  checkpointNumber,
247
- rollup.address,
248
- targetCommitteeSize,
249
283
  logger,
284
+ isHistoricalSync,
250
285
  );
251
286
 
252
- const l1: L1PublishedData = {
253
- blockNumber: log.blockNumber,
254
- blockHash: log.blockHash,
255
- timestamp: await getL1BlockTime(publicClient, log.blockNumber),
256
- };
287
+ const l1 = new L1PublishedData(
288
+ log.l1BlockNumber,
289
+ await getL1BlockTime(publicClient, log.l1BlockNumber),
290
+ log.l1BlockHash.toString(),
291
+ );
257
292
 
258
- retrievedCheckpoints.push({ ...checkpoint, l1, chainId, version });
259
- logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.transactionHash}`, {
260
- l1BlockNumber: log.blockNumber,
293
+ retrievedCheckpoints.push({ ...checkpoint, checkpointBlobData, l1, chainId, version });
294
+ logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.l1TransactionHash}`, {
295
+ l1BlockNumber: log.l1BlockNumber,
261
296
  checkpointNumber,
262
297
  archive: archive.toString(),
263
298
  attestations: checkpoint.attestations,
264
299
  });
265
300
  } else {
266
301
  logger.warn(`Ignoring checkpoint ${checkpointNumber} due to archive root mismatch`, {
267
- actual: archive,
268
- expected: archiveFromChain,
302
+ actual: archive.toString(),
303
+ expected: archiveFromChain.toString(),
269
304
  });
270
305
  }
271
306
  });
@@ -278,118 +313,15 @@ export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber
278
313
  return block.timestamp;
279
314
  }
280
315
 
281
- /**
282
- * Extracts the first 'propose' method calldata from a multicall3 transaction's data.
283
- * @param multicall3Data - The multicall3 transaction input data
284
- * @param rollupAddress - The address of the rollup contract
285
- * @returns The calldata for the first 'propose' method call to the rollup contract
286
- */
287
- function extractRollupProposeCalldata(multicall3Data: Hex, rollupAddress: Hex): Hex {
288
- const { functionName: multicall3FunctionName, args: multicall3Args } = decodeFunctionData({
289
- abi: multicall3Abi,
290
- data: multicall3Data,
291
- });
292
-
293
- if (multicall3FunctionName !== 'aggregate3') {
294
- throw new Error(`Unexpected multicall3 method called ${multicall3FunctionName}`);
295
- }
296
-
297
- if (multicall3Args.length !== 1) {
298
- throw new Error(`Unexpected number of arguments for multicall3`);
299
- }
300
-
301
- const [calls] = multicall3Args;
302
-
303
- // Find all rollup calls
304
- const rollupAddressLower = rollupAddress.toLowerCase();
305
-
306
- for (let i = 0; i < calls.length; i++) {
307
- const addr = calls[i].target;
308
- if (addr.toLowerCase() !== rollupAddressLower) {
309
- continue;
310
- }
311
- const callData = calls[i].callData;
312
-
313
- try {
314
- const { functionName: rollupFunctionName } = decodeFunctionData({
315
- abi: RollupAbi,
316
- data: callData,
317
- });
318
-
319
- if (rollupFunctionName === 'propose') {
320
- return callData;
321
- }
322
- } catch {
323
- // Skip invalid function data
324
- continue;
325
- }
326
- }
327
-
328
- throw new Error(`Rollup address not found in multicall3 args`);
329
- }
330
-
331
- /**
332
- * Gets checkpoint from the calldata of an L1 transaction.
333
- * Assumes that the checkpoint was published from an EOA.
334
- * TODO: Add retries and error management.
335
- * @param publicClient - The viem public client to use for transaction retrieval.
336
- * @param txHash - Hash of the tx that published it.
337
- * @param checkpointNumber - Checkpoint number.
338
- * @returns Checkpoint from the calldata, deserialized
339
- */
340
- async function getCheckpointFromRollupTx(
341
- publicClient: ViemPublicClient,
342
- blobSinkClient: BlobSinkClientInterface,
343
- txHash: `0x${string}`,
344
- blobHashes: Buffer[], // TODO(md): buffer32?
316
+ export async function getCheckpointBlobDataFromBlobs(
317
+ blobClient: BlobClientInterface,
318
+ blockHash: string,
319
+ blobHashes: Buffer<ArrayBufferLike>[],
345
320
  checkpointNumber: CheckpointNumber,
346
- rollupAddress: Hex,
347
- targetCommitteeSize: number,
348
321
  logger: Logger,
349
- ): Promise<Omit<RetrievedCheckpoint, 'l1' | 'chainId' | 'version'>> {
350
- logger.trace(`Fetching checkpoint ${checkpointNumber} from rollup tx ${txHash}`);
351
- const { input: forwarderData, blockHash } = await publicClient.getTransaction({ hash: txHash });
352
-
353
- const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
354
- const { functionName: rollupFunctionName, args: rollupArgs } = decodeFunctionData({
355
- abi: RollupAbi,
356
- data: rollupData,
357
- });
358
-
359
- if (rollupFunctionName !== 'propose') {
360
- throw new Error(`Unexpected rollup method called ${rollupFunctionName}`);
361
- }
362
-
363
- const [decodedArgs, packedAttestations, _signers, _blobInput] = rollupArgs! as readonly [
364
- {
365
- archive: Hex;
366
- oracleInput: {
367
- feeAssetPriceModifier: bigint;
368
- };
369
- header: ViemHeader;
370
- txHashes: readonly Hex[];
371
- },
372
- ViemCommitteeAttestations,
373
- Hex[],
374
- ViemSignature,
375
- Hex,
376
- ];
377
-
378
- const attestations = CommitteeAttestation.fromPacked(packedAttestations, targetCommitteeSize);
379
-
380
- logger.trace(`Recovered propose calldata from tx ${txHash}`, {
381
- checkpointNumber,
382
- archive: decodedArgs.archive,
383
- header: decodedArgs.header,
384
- l1BlockHash: blockHash,
385
- blobHashes,
386
- attestations,
387
- packedAttestations,
388
- targetCommitteeSize,
389
- });
390
-
391
- const header = CheckpointHeader.fromViem(decodedArgs.header);
392
- const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
322
+ isHistoricalSync: boolean,
323
+ ): Promise<CheckpointBlobData> {
324
+ const blobBodies = await blobClient.getBlobSidecar(blockHash, blobHashes, { isHistoricalSync });
393
325
  if (blobBodies.length === 0) {
394
326
  throw new NoBlobBodiesFoundError(checkpointNumber);
395
327
  }
@@ -397,35 +329,28 @@ async function getCheckpointFromRollupTx(
397
329
  let checkpointBlobData: CheckpointBlobData;
398
330
  try {
399
331
  // Attempt to decode the checkpoint blob data.
400
- checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies.map(b => b.blob));
332
+ checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies);
401
333
  } catch (err: any) {
402
334
  if (err instanceof BlobDeserializationError) {
403
335
  logger.fatal(err.message);
404
336
  } else {
405
337
  logger.fatal('Unable to sync: failed to decode fetched blob, this blob was likely not created by us');
406
338
  }
339
+ // Throwing an error since this is most likely caused by a bug.
407
340
  throw err;
408
341
  }
409
342
 
410
- const archiveRoot = new Fr(Buffer.from(hexToBytes(decodedArgs.archive)));
411
-
412
- return {
413
- checkpointNumber,
414
- archiveRoot,
415
- header,
416
- checkpointBlobData,
417
- attestations,
418
- };
343
+ return checkpointBlobData;
419
344
  }
420
345
 
421
346
  /** Given an L1 to L2 message, retrieves its corresponding event from the Inbox within a specific block range. */
422
347
  export async function retrieveL1ToL2Message(
423
- inbox: GetContractReturnType<typeof InboxAbi, ViemClient>,
348
+ inbox: InboxContract,
424
349
  leaf: Fr,
425
350
  fromBlock: bigint,
426
351
  toBlock: bigint,
427
352
  ): Promise<InboxMessage | undefined> {
428
- const logs = await inbox.getEvents.MessageSent({ hash: leaf.toString() }, { fromBlock, toBlock });
353
+ const logs = await inbox.getMessageSentEventByHash(leaf.toString(), fromBlock, toBlock);
429
354
 
430
355
  const messages = mapLogsInboxMessage(logs);
431
356
  return messages.length > 0 ? messages[0] : undefined;
@@ -433,47 +358,40 @@ export async function retrieveL1ToL2Message(
433
358
 
434
359
  /**
435
360
  * Fetch L1 to L2 messages.
436
- * @param publicClient - The viem public client to use for transaction retrieval.
437
- * @param inboxAddress - The address of the inbox contract to fetch messages from.
438
- * @param blockUntilSynced - If true, blocks until the archiver has fully synced.
361
+ * @param inbox - The inbox contract wrapper.
439
362
  * @param searchStartBlock - The block number to use for starting the search.
440
363
  * @param searchEndBlock - The highest block number that we should search up to.
441
364
  * @returns An array of InboxLeaf and next eth block to search from.
442
365
  */
443
366
  export async function retrieveL1ToL2Messages(
444
- inbox: GetContractReturnType<typeof InboxAbi, ViemClient>,
367
+ inbox: InboxContract,
445
368
  searchStartBlock: bigint,
446
369
  searchEndBlock: bigint,
447
370
  ): Promise<InboxMessage[]> {
448
371
  const retrievedL1ToL2Messages: InboxMessage[] = [];
449
372
  while (searchStartBlock <= searchEndBlock) {
450
- const messageSentLogs = (
451
- await inbox.getEvents.MessageSent({}, { fromBlock: searchStartBlock, toBlock: searchEndBlock })
452
- ).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
373
+ const messageSentLogs = await inbox.getMessageSentEvents(searchStartBlock, searchEndBlock);
453
374
 
454
375
  if (messageSentLogs.length === 0) {
455
376
  break;
456
377
  }
457
378
 
458
379
  retrievedL1ToL2Messages.push(...mapLogsInboxMessage(messageSentLogs));
459
- searchStartBlock = messageSentLogs.at(-1)!.blockNumber + 1n;
380
+ searchStartBlock = messageSentLogs.at(-1)!.l1BlockNumber + 1n;
460
381
  }
461
382
 
462
383
  return retrievedL1ToL2Messages;
463
384
  }
464
385
 
465
- function mapLogsInboxMessage(logs: GetContractEventsReturnType<typeof InboxAbi, 'MessageSent'>): InboxMessage[] {
466
- return logs.map(log => {
467
- const { index, hash, checkpointNumber, rollingHash } = log.args;
468
- return {
469
- index: index!,
470
- leaf: Fr.fromHexString(hash!),
471
- l1BlockNumber: log.blockNumber,
472
- l1BlockHash: Buffer32.fromString(log.blockHash),
473
- l2BlockNumber: BlockNumber(Number(checkpointNumber!)),
474
- rollingHash: Buffer16.fromString(rollingHash!),
475
- };
476
- });
386
+ function mapLogsInboxMessage(logs: MessageSentLog[]): InboxMessage[] {
387
+ return logs.map(log => ({
388
+ index: log.args.index,
389
+ leaf: log.args.leaf,
390
+ l1BlockNumber: log.l1BlockNumber,
391
+ l1BlockHash: log.l1BlockHash,
392
+ checkpointNumber: log.args.checkpointNumber,
393
+ rollingHash: log.args.rollingHash,
394
+ }));
477
395
  }
478
396
 
479
397
  /** Retrieves L2ProofVerified events from the rollup contract. */
@@ -0,0 +1,99 @@
1
+ import type { DebugCallTrace, ViemPublicDebugClient } from '@aztec/ethereum/types';
2
+ import { EthAddress } from '@aztec/foundation/eth-address';
3
+ import type { Logger } from '@aztec/foundation/log';
4
+ import { type ZodFor, schemas } from '@aztec/foundation/schemas';
5
+ import { withHexPrefix } from '@aztec/foundation/string';
6
+
7
+ import type { Hex } from 'viem';
8
+ import { z } from 'zod';
9
+
10
+ import type { CallInfo } from './types.js';
11
+
12
+ /** Zod schema for validating call trace from debug_traceTransaction */
13
+ export const callTraceSchema: ZodFor<DebugCallTrace> = z.lazy(() =>
14
+ z.object({
15
+ from: schemas.HexStringWith0x,
16
+ to: schemas.HexStringWith0x.optional(),
17
+ type: z.string(),
18
+ input: schemas.HexStringWith0x.optional(),
19
+ output: schemas.HexStringWith0x.optional(),
20
+ gas: schemas.HexStringWith0x.optional(),
21
+ gasUsed: schemas.HexStringWith0x.optional(),
22
+ value: schemas.HexStringWith0x.optional(),
23
+ error: z.string().optional(),
24
+ calls: z.array(callTraceSchema).optional(),
25
+ }),
26
+ );
27
+
28
+ /**
29
+ * Traces a transaction and extracts all CALL operations to a specific contract and function selector.
30
+ *
31
+ * @param client - The Viem public client
32
+ * @param txHash - The transaction hash to trace
33
+ * @param targetAddress - The contract address to filter for
34
+ * @param functionSelector - The 4-byte function selector to filter for (with or without 0x prefix)
35
+ * @returns Array of CallInfo objects containing from, gasUsed, input, and value for matching calls
36
+ */
37
+ export async function getSuccessfulCallsFromDebug(
38
+ client: ViemPublicDebugClient,
39
+ txHash: Hex,
40
+ targetAddress: EthAddress,
41
+ functionSelector: string,
42
+ logger?: Logger,
43
+ ): Promise<CallInfo[]> {
44
+ // Normalize inputs for comparison
45
+ const normalizedTarget = targetAddress.toString().toLowerCase();
46
+ const normalizedSelector = withHexPrefix(functionSelector.toLowerCase());
47
+
48
+ // Call debug_traceTransaction with callTracer
49
+ // Using 'any' here because debug_traceTransaction is not in viem's standard RPC types
50
+ const rawTrace = await client.request({
51
+ method: 'debug_traceTransaction',
52
+ params: [txHash, { tracer: 'callTracer' }],
53
+ });
54
+
55
+ if (rawTrace === null || rawTrace === undefined) {
56
+ throw new Error(`Failed to retrieve debug_traceTransaction for ${txHash}`);
57
+ }
58
+
59
+ logger?.trace(`Retrieved debug_traceTransaction for ${txHash}`, { trace: rawTrace });
60
+
61
+ // Validate the response with zod
62
+ const trace = callTraceSchema.parse(rawTrace);
63
+
64
+ const results: CallInfo[] = [];
65
+
66
+ /**
67
+ * Recursively traverse the call trace tree
68
+ */
69
+ function traverseCalls(callTrace: DebugCallTrace) {
70
+ // Skip calls that have errors, and all its descendants
71
+ if (callTrace.error) {
72
+ return;
73
+ }
74
+
75
+ // Check if this is a CALL (not DELEGATECALL or STATICCALL) to the target address with matching selector
76
+ if (
77
+ callTrace.type.toUpperCase() === 'CALL' &&
78
+ callTrace.to?.toLowerCase() === normalizedTarget &&
79
+ callTrace.input?.toLowerCase().startsWith(normalizedSelector)
80
+ ) {
81
+ results.push({
82
+ from: EthAddress.fromString(callTrace.from),
83
+ gasUsed: callTrace.gasUsed === undefined ? undefined : BigInt(callTrace.gasUsed),
84
+ input: callTrace.input,
85
+ value: callTrace.value ? BigInt(callTrace.value) : 0n,
86
+ });
87
+ }
88
+
89
+ // Recursively process nested calls
90
+ for (const nestedCall of callTrace.calls ?? []) {
91
+ traverseCalls(nestedCall);
92
+ }
93
+ }
94
+
95
+ // Start traversal from the root trace
96
+ traverseCalls(trace);
97
+
98
+ return results;
99
+ }