@aztec/archiver 0.86.0 → 0.87.0

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 (57) hide show
  1. package/dest/archiver/archiver.d.ts +62 -5
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +362 -91
  4. package/dest/archiver/archiver_store.d.ts +33 -17
  5. package/dest/archiver/archiver_store.d.ts.map +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.js +364 -62
  8. package/dest/archiver/data_retrieval.d.ts +23 -14
  9. package/dest/archiver/data_retrieval.d.ts.map +1 -1
  10. package/dest/archiver/data_retrieval.js +86 -38
  11. package/dest/archiver/errors.d.ts +8 -0
  12. package/dest/archiver/errors.d.ts.map +1 -1
  13. package/dest/archiver/errors.js +12 -0
  14. package/dest/archiver/instrumentation.d.ts.map +1 -1
  15. package/dest/archiver/kv_archiver_store/block_store.d.ts +4 -1
  16. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  17. package/dest/archiver/kv_archiver_store/block_store.js +43 -6
  18. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +3 -1
  19. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  20. package/dest/archiver/kv_archiver_store/contract_instance_store.js +17 -3
  21. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +24 -14
  22. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  23. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +37 -11
  24. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  25. package/dest/archiver/kv_archiver_store/log_store.js +1 -1
  26. package/dest/archiver/kv_archiver_store/message_store.d.ts +21 -15
  27. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  28. package/dest/archiver/kv_archiver_store/message_store.js +150 -48
  29. package/dest/archiver/structs/inbox_message.d.ts +14 -0
  30. package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
  31. package/dest/archiver/structs/inbox_message.js +38 -0
  32. package/dest/rpc/index.d.ts +1 -1
  33. package/dest/test/mock_l2_block_source.d.ts +2 -0
  34. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  35. package/dest/test/mock_l2_block_source.js +8 -1
  36. package/dest/test/mock_structs.d.ts +9 -0
  37. package/dest/test/mock_structs.d.ts.map +1 -0
  38. package/dest/test/mock_structs.js +37 -0
  39. package/package.json +15 -15
  40. package/src/archiver/archiver.ts +431 -108
  41. package/src/archiver/archiver_store.ts +37 -18
  42. package/src/archiver/archiver_store_test_suite.ts +307 -52
  43. package/src/archiver/data_retrieval.ts +130 -53
  44. package/src/archiver/errors.ts +21 -0
  45. package/src/archiver/instrumentation.ts +4 -1
  46. package/src/archiver/kv_archiver_store/block_store.ts +46 -8
  47. package/src/archiver/kv_archiver_store/contract_instance_store.ts +20 -7
  48. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +61 -17
  49. package/src/archiver/kv_archiver_store/log_store.ts +6 -2
  50. package/src/archiver/kv_archiver_store/message_store.ts +209 -53
  51. package/src/archiver/structs/inbox_message.ts +40 -0
  52. package/src/test/mock_l2_block_source.ts +9 -1
  53. package/src/test/mock_structs.ts +49 -0
  54. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
  55. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
  56. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
  57. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
@@ -4,14 +4,15 @@ function _ts_decorate(decorators, target, key, desc) {
4
4
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
- import { RollupContract, createEthereumChain } from '@aztec/ethereum';
7
+ import { BlockTagTooOldError, InboxContract, RollupContract, createEthereumChain } from '@aztec/ethereum';
8
+ import { maxBigint } from '@aztec/foundation/bigint';
9
+ import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
8
10
  import { Fr } from '@aztec/foundation/fields';
9
11
  import { createLogger } from '@aztec/foundation/log';
10
12
  import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
11
13
  import { sleep } from '@aztec/foundation/sleep';
12
14
  import { count } from '@aztec/foundation/string';
13
15
  import { elapsed } from '@aztec/foundation/timer';
14
- import { InboxAbi } from '@aztec/l1-artifacts';
15
16
  import { ContractClassRegisteredEvent, PrivateFunctionBroadcastedEvent, UtilityFunctionBroadcastedEvent } from '@aztec/protocol-contracts/class-registerer';
16
17
  import { ContractInstanceDeployedEvent, ContractInstanceUpdatedEvent } from '@aztec/protocol-contracts/instance-deployer';
17
18
  import { L2BlockSourceEvents } from '@aztec/stdlib/block';
@@ -20,9 +21,9 @@ import { getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotR
20
21
  import { Attributes, trackSpan } from '@aztec/telemetry-client';
21
22
  import { EventEmitter } from 'events';
22
23
  import groupBy from 'lodash.groupby';
23
- import { createPublicClient, fallback, getContract, http } from 'viem';
24
- import { retrieveBlocksFromRollup, retrieveL1ToL2Messages } from './data_retrieval.js';
25
- import { NoBlobBodiesFoundError } from './errors.js';
24
+ import { createPublicClient, fallback, http } from 'viem';
25
+ import { retrieveBlocksFromRollup, retrieveL1ToL2Message, retrieveL1ToL2Messages, retrievedBlockToPublishedL2Block } from './data_retrieval.js';
26
+ import { InitialBlockNumberNotSequentialError, NoBlobBodiesFoundError } from './errors.js';
26
27
  import { ArchiverInstrumentation } from './instrumentation.js';
27
28
  /**
28
29
  * Pulls L2 blocks in a non-blocking manner and provides interface for their retrieval.
@@ -61,11 +62,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
61
62
  this.tracer = instrumentation.tracer;
62
63
  this.store = new ArchiverStoreHelper(dataStore);
63
64
  this.rollup = new RollupContract(publicClient, l1Addresses.rollupAddress);
64
- this.inbox = getContract({
65
- address: l1Addresses.inboxAddress.toString(),
66
- abi: InboxAbi,
67
- client: publicClient
68
- });
65
+ this.inbox = new InboxContract(publicClient, l1Addresses.inboxAddress);
69
66
  }
70
67
  /**
71
68
  * Creates a new instance of the Archiver and blocks until it syncs from chain.
@@ -85,18 +82,25 @@ import { ArchiverInstrumentation } from './instrumentation.js';
85
82
  rollup.getL1StartBlock(),
86
83
  rollup.getL1GenesisTime()
87
84
  ]);
85
+ const l1StartBlockHash = await publicClient.getBlock({
86
+ blockNumber: l1StartBlock,
87
+ includeTransactions: false
88
+ }).then((block)=>Buffer32.fromString(block.hash));
88
89
  const { aztecEpochDuration: epochDuration, aztecSlotDuration: slotDuration, ethereumSlotDuration, aztecProofSubmissionWindow: proofSubmissionWindow } = config;
89
- const archiver = new Archiver(publicClient, config.l1Contracts, archiverStore, {
90
- pollingIntervalMs: config.archiverPollingIntervalMS ?? 10_000,
91
- batchSize: config.archiverBatchSize ?? 100
92
- }, deps.blobSinkClient, await ArchiverInstrumentation.new(deps.telemetry, ()=>archiverStore.estimateSize()), {
90
+ const l1Constants = {
91
+ l1StartBlockHash,
93
92
  l1StartBlock,
94
93
  l1GenesisTime,
95
94
  epochDuration,
96
95
  slotDuration,
97
96
  ethereumSlotDuration,
98
97
  proofSubmissionWindow
99
- });
98
+ };
99
+ const opts = {
100
+ pollingIntervalMs: config.archiverPollingIntervalMS ?? 10_000,
101
+ batchSize: config.archiverBatchSize ?? 100
102
+ };
103
+ const archiver = new Archiver(publicClient, config.l1Contracts, archiverStore, opts, deps.blobSinkClient, await ArchiverInstrumentation.new(deps.telemetry, ()=>archiverStore.estimateSize()), l1Constants);
100
104
  await archiver.start(blockUntilSynced);
101
105
  return archiver;
102
106
  }
@@ -132,6 +136,8 @@ import { ArchiverInstrumentation } from './instrumentation.js';
132
136
  } catch (error) {
133
137
  if (error instanceof NoBlobBodiesFoundError) {
134
138
  this.log.error(`Error syncing archiver: ${error.message}`);
139
+ } else if (error instanceof BlockTagTooOldError) {
140
+ this.log.warn(`Re-running archiver sync: ${error.message}`);
135
141
  } else {
136
142
  this.log.error('Error during archiver sync', error);
137
143
  }
@@ -152,11 +158,21 @@ import { ArchiverInstrumentation } from './instrumentation.js';
152
158
  * The archiver will stay back, until there's data on L1 that will move the pointers forward.
153
159
  *
154
160
  * This code does not handle reorgs.
155
- */ const { l1StartBlock } = this.l1constants;
156
- const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await this.store.getSynchPoint();
157
- const currentL1BlockNumber = await this.publicClient.getBlockNumber();
161
+ */ const { l1StartBlock, l1StartBlockHash } = this.l1constants;
162
+ const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = {
163
+ l1BlockNumber: l1StartBlock,
164
+ l1BlockHash: l1StartBlockHash
165
+ } } = await this.store.getSynchPoint();
166
+ const currentL1Block = await this.publicClient.getBlock({
167
+ includeTransactions: false
168
+ });
169
+ const currentL1BlockNumber = currentL1Block.number;
170
+ const currentL1BlockHash = Buffer32.fromString(currentL1Block.hash);
158
171
  if (initialRun) {
159
- this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${Math.min(Number(blocksSynchedTo), Number(messagesSynchedTo))} to current L1 block ${currentL1BlockNumber}`);
172
+ this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo}` + ` to current L1 block ${currentL1BlockNumber} with hash ${currentL1BlockHash.toString()}`, {
173
+ blocksSynchedTo,
174
+ messagesSynchedTo
175
+ });
160
176
  }
161
177
  // ********** Ensuring Consistency of data pulled from L1 **********
162
178
  /**
@@ -175,7 +191,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
175
191
  * data up to the currentBlockNumber captured at the top of this function. We might want to improve on this
176
192
  * in future but for the time being it should give us the guarantees that we need
177
193
  */ // ********** Events that are processed per L1 block **********
178
- await this.handleL1ToL2Messages(messagesSynchedTo, currentL1BlockNumber);
194
+ await this.handleL1ToL2Messages(messagesSynchedTo, currentL1BlockNumber, currentL1BlockHash);
179
195
  // Get L1 timestamp for the current block
180
196
  const currentL1Timestamp = !this.l1Timestamp || !this.l1BlockNumber || this.l1BlockNumber !== currentL1BlockNumber ? (await this.publicClient.getBlock({
181
197
  blockNumber: currentL1BlockNumber
@@ -183,13 +199,19 @@ import { ArchiverInstrumentation } from './instrumentation.js';
183
199
  // ********** Events that are processed per L2 block **********
184
200
  if (currentL1BlockNumber > blocksSynchedTo) {
185
201
  // First we retrieve new L2 blocks
186
- const { provenBlockNumber } = await this.handleL2blocks(blocksSynchedTo, currentL1BlockNumber);
187
- // And then we prune the current epoch if it'd reorg on next submission.
202
+ const rollupStatus = await this.handleL2blocks(blocksSynchedTo, currentL1BlockNumber);
203
+ // Then we prune the current epoch if it'd reorg on next submission.
188
204
  // Note that we don't do this before retrieving L2 blocks because we may need to retrieve
189
205
  // blocks from more than 2 epochs ago, so we want to make sure we have the latest view of
190
206
  // the chain locally before we start unwinding stuff. This can be optimized by figuring out
191
207
  // up to which point we're pruning, and then requesting L2 blocks up to that point only.
192
- await this.handleEpochPrune(provenBlockNumber, currentL1BlockNumber, currentL1Timestamp);
208
+ const { rollupCanPrune } = await this.handleEpochPrune(rollupStatus.provenBlockNumber, currentL1BlockNumber, currentL1Timestamp);
209
+ // And lastly we check if we are missing any L2 blocks behind us due to a possible L1 reorg.
210
+ // We only do this if rollup cant prune on the next submission. Otherwise we will end up
211
+ // re-syncing the blocks we have just unwound above.
212
+ if (!rollupCanPrune) {
213
+ await this.checkForNewBlocksBeforeL1SyncPoint(rollupStatus, blocksSynchedTo, currentL1BlockNumber);
214
+ }
193
215
  this.instrumentation.updateL1BlockHeight(currentL1BlockNumber);
194
216
  }
195
217
  // After syncing has completed, update the current l1 block number and timestamp,
@@ -206,7 +228,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
206
228
  });
207
229
  }
208
230
  }
209
- /** Queries the rollup contract on whether a prune can be executed on the immediatenext L1 block. */ async canPrune(currentL1BlockNumber, currentL1Timestamp) {
231
+ /** Queries the rollup contract on whether a prune can be executed on the immediate next L1 block. */ async canPrune(currentL1BlockNumber, currentL1Timestamp) {
210
232
  const time = (currentL1Timestamp ?? 0n) + BigInt(this.l1constants.ethereumSlotDuration);
211
233
  const result = await this.rollup.canPruneAtTime(time, {
212
234
  blockNumber: currentL1BlockNumber
@@ -221,8 +243,9 @@ import { ArchiverInstrumentation } from './instrumentation.js';
221
243
  return result;
222
244
  }
223
245
  /** Checks if there'd be a reorg for the next block submission and start pruning now. */ async handleEpochPrune(provenBlockNumber, currentL1BlockNumber, currentL1Timestamp) {
246
+ const rollupCanPrune = await this.canPrune(currentL1BlockNumber, currentL1Timestamp);
224
247
  const localPendingBlockNumber = BigInt(await this.getBlockNumber());
225
- const canPrune = localPendingBlockNumber > provenBlockNumber && await this.canPrune(currentL1BlockNumber, currentL1Timestamp);
248
+ const canPrune = localPendingBlockNumber > provenBlockNumber && rollupCanPrune;
226
249
  if (canPrune) {
227
250
  const pruneFrom = provenBlockNumber + 1n;
228
251
  const header = await this.getBlockHeader(Number(pruneFrom));
@@ -247,6 +270,9 @@ import { ArchiverInstrumentation } from './instrumentation.js';
247
270
  // Seems like the next iteration should handle this.
248
271
  // await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
249
272
  }
273
+ return {
274
+ rollupCanPrune
275
+ };
250
276
  }
251
277
  nextRange(end, limit) {
252
278
  const batchSize = this.config.batchSize * this.l1constants.slotDuration / this.l1constants.ethereumSlotDuration;
@@ -263,41 +289,172 @@ import { ArchiverInstrumentation } from './instrumentation.js';
263
289
  nextEnd
264
290
  ];
265
291
  }
266
- async handleL1ToL2Messages(messagesSynchedTo, currentL1BlockNumber) {
267
- this.log.trace(`Handling L1 to L2 messages from ${messagesSynchedTo} to ${currentL1BlockNumber}.`);
268
- if (currentL1BlockNumber <= messagesSynchedTo) {
292
+ async handleL1ToL2Messages(messagesSyncPoint, currentL1BlockNumber, currentL1BlockHash) {
293
+ this.log.trace(`Handling L1 to L2 messages from ${messagesSyncPoint.l1BlockNumber} to ${currentL1BlockNumber}.`);
294
+ if (currentL1BlockNumber <= messagesSyncPoint.l1BlockNumber) {
269
295
  return;
270
296
  }
271
- const localTotalMessageCount = await this.store.getTotalL1ToL2MessageCount();
272
- const destinationTotalMessageCount = await this.inbox.read.totalMessagesInserted();
273
- if (localTotalMessageCount === destinationTotalMessageCount) {
274
- await this.store.setMessageSynchedL1BlockNumber(currentL1BlockNumber);
275
- this.log.trace(`Retrieved no new L1 to L2 messages between L1 blocks ${messagesSynchedTo + 1n} and ${currentL1BlockNumber}.`);
297
+ // Load remote and local inbox states.
298
+ const localMessagesInserted = await this.store.getTotalL1ToL2MessageCount();
299
+ const localLastMessage = await this.store.getLastL1ToL2Message();
300
+ const remoteMessagesState = await this.inbox.getState({
301
+ blockNumber: currentL1BlockNumber
302
+ });
303
+ this.log.trace(`Retrieved remote inbox state at L1 block ${currentL1BlockNumber}.`, {
304
+ localMessagesInserted,
305
+ localLastMessage,
306
+ remoteMessagesState
307
+ });
308
+ // Compare message count and rolling hash. If they match, no need to retrieve anything.
309
+ if (remoteMessagesState.totalMessagesInserted === localMessagesInserted && remoteMessagesState.messagesRollingHash.equals(localLastMessage?.rollingHash ?? Buffer16.ZERO)) {
310
+ this.log.debug(`No L1 to L2 messages to query between L1 blocks ${messagesSyncPoint.l1BlockNumber} and ${currentL1BlockNumber}.`);
311
+ await this.store.setMessageSynchedL1Block({
312
+ l1BlockHash: currentL1BlockHash,
313
+ l1BlockNumber: currentL1BlockNumber
314
+ });
276
315
  return;
277
316
  }
278
- // Retrieve messages in batches. Each batch is estimated to acommodate up to L2 'blockBatchSize' blocks,
279
- let searchStartBlock = messagesSynchedTo;
280
- let searchEndBlock = messagesSynchedTo;
317
+ // Check if our syncpoint is still valid. If not, there was an L1 reorg and we need to re-retrieve messages.
318
+ // Note that we need to fetch it from logs and not from inbox state at the syncpoint l1 block number, since it
319
+ // could be older than 128 blocks and non-archive nodes cannot resolve it.
320
+ if (localLastMessage) {
321
+ const remoteLastMessage = await this.retrieveL1ToL2Message(localLastMessage.leaf);
322
+ this.log.trace(`Retrieved remote message for local last`, {
323
+ remoteLastMessage,
324
+ localLastMessage
325
+ });
326
+ if (!remoteLastMessage || !remoteLastMessage.rollingHash.equals(localLastMessage.rollingHash)) {
327
+ this.log.warn(`Rolling back L1 to L2 messages due to hash mismatch or msg not found.`, {
328
+ remoteLastMessage,
329
+ messagesSyncPoint,
330
+ localLastMessage
331
+ });
332
+ messagesSyncPoint = await this.rollbackL1ToL2Messages(localLastMessage, messagesSyncPoint);
333
+ this.log.debug(`Rolled back L1 to L2 messages to L1 block ${messagesSyncPoint.l1BlockNumber}.`, {
334
+ messagesSyncPoint
335
+ });
336
+ }
337
+ }
338
+ // Retrieve and save messages in batches. Each batch is estimated to acommodate up to L2 'blockBatchSize' blocks,
339
+ let searchStartBlock = 0n;
340
+ let searchEndBlock = messagesSyncPoint.l1BlockNumber;
341
+ let lastMessage;
342
+ let messageCount = 0;
281
343
  do {
282
344
  [searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
283
345
  this.log.trace(`Retrieving L1 to L2 messages between L1 blocks ${searchStartBlock} and ${searchEndBlock}.`);
284
- const retrievedL1ToL2Messages = await retrieveL1ToL2Messages(this.inbox, searchStartBlock, searchEndBlock);
285
- this.log.verbose(`Retrieved ${retrievedL1ToL2Messages.retrievedData.length} new L1 to L2 messages between L1 blocks ${searchStartBlock} and ${searchEndBlock}.`);
286
- await this.store.addL1ToL2Messages(retrievedL1ToL2Messages);
287
- for (const msg of retrievedL1ToL2Messages.retrievedData){
346
+ const messages = await retrieveL1ToL2Messages(this.inbox.getContract(), searchStartBlock, searchEndBlock);
347
+ this.log.verbose(`Retrieved ${messages.length} new L1 to L2 messages between L1 blocks ${searchStartBlock} and ${searchEndBlock}.`);
348
+ await this.store.addL1ToL2Messages(messages);
349
+ for (const msg of messages){
288
350
  this.log.debug(`Downloaded L1 to L2 message`, {
289
- leaf: msg.leaf.toString(),
290
- index: msg.index
351
+ ...msg,
352
+ leaf: msg.leaf.toString()
291
353
  });
354
+ lastMessage = msg;
355
+ messageCount++;
292
356
  }
293
357
  }while (searchEndBlock < currentL1BlockNumber)
358
+ // Log stats for messages retrieved (if any).
359
+ if (messageCount > 0) {
360
+ this.log.info(`Retrieved ${messageCount} new L1 to L2 messages up to message with index ${lastMessage?.index} for L2 block ${lastMessage?.l2BlockNumber}`, {
361
+ lastMessage,
362
+ messageCount
363
+ });
364
+ }
365
+ // Warn if the resulting rolling hash does not match the remote state we had retrieved.
366
+ if (lastMessage && !lastMessage.rollingHash.equals(remoteMessagesState.messagesRollingHash)) {
367
+ this.log.warn(`Last message retrieved rolling hash does not match remote state.`, {
368
+ lastMessage,
369
+ remoteMessagesState
370
+ });
371
+ }
372
+ }
373
+ retrieveL1ToL2Message(leaf) {
374
+ return retrieveL1ToL2Message(this.inbox.getContract(), leaf, this.l1constants.l1StartBlock);
375
+ }
376
+ async rollbackL1ToL2Messages(localLastMessage, messagesSyncPoint) {
377
+ // Slowly go back through our messages until we find the last common message.
378
+ // We could query the logs in batch as an optimization, but the depth of the reorg should not be deep, and this
379
+ // is a very rare case, so it's fine to query one log at a time.
380
+ let commonMsg;
381
+ this.log.verbose(`Searching most recent common L1 to L2 message at or before index ${localLastMessage.index}`);
382
+ for await (const msg of this.store.iterateL1ToL2Messages({
383
+ reverse: true,
384
+ end: localLastMessage.index
385
+ })){
386
+ const remoteMsg = await this.retrieveL1ToL2Message(msg.leaf);
387
+ const logCtx = {
388
+ remoteMsg,
389
+ localMsg: msg
390
+ };
391
+ if (remoteMsg && remoteMsg.rollingHash.equals(msg.rollingHash)) {
392
+ this.log.verbose(`Found most recent common L1 to L2 message at index ${msg.index} on L1 block ${msg.l1BlockNumber}`, logCtx);
393
+ commonMsg = remoteMsg;
394
+ break;
395
+ } else if (remoteMsg) {
396
+ this.log.debug(`Local L1 to L2 message with index ${msg.index} has different rolling hash`, logCtx);
397
+ } else {
398
+ this.log.debug(`Local L1 to L2 message with index ${msg.index} not found on L1`, logCtx);
399
+ }
400
+ }
401
+ // Delete everything after the common message we found.
402
+ const lastGoodIndex = commonMsg?.index;
403
+ this.log.warn(`Deleting all local L1 to L2 messages after index ${lastGoodIndex ?? 'undefined'}`);
404
+ await this.store.removeL1ToL2Messages(lastGoodIndex !== undefined ? lastGoodIndex + 1n : 0n);
405
+ // Update the syncpoint so the loop below reprocesses the changed messages. We go to the block before
406
+ // the last common one, so we force reprocessing it, in case new messages were added on that same L1 block
407
+ // after the last common message.
408
+ const syncPointL1BlockNumber = commonMsg ? commonMsg.l1BlockNumber - 1n : this.l1constants.l1StartBlock;
409
+ const syncPointL1BlockHash = await this.getL1BlockHash(syncPointL1BlockNumber);
410
+ messagesSyncPoint = {
411
+ l1BlockNumber: syncPointL1BlockNumber,
412
+ l1BlockHash: syncPointL1BlockHash
413
+ };
414
+ await this.store.setMessageSynchedL1Block(messagesSyncPoint);
415
+ return messagesSyncPoint;
416
+ }
417
+ async getL1BlockHash(l1BlockNumber) {
418
+ const block = await this.publicClient.getBlock({
419
+ blockNumber: l1BlockNumber,
420
+ includeTransactions: false
421
+ });
422
+ if (!block) {
423
+ throw new Error(`Missing L1 block ${l1BlockNumber}`);
424
+ }
425
+ return Buffer32.fromString(block.hash);
294
426
  }
295
427
  async handleL2blocks(blocksSynchedTo, currentL1BlockNumber) {
296
428
  const localPendingBlockNumber = BigInt(await this.getBlockNumber());
297
429
  const [provenBlockNumber, provenArchive, pendingBlockNumber, pendingArchive, archiveForLocalPendingBlockNumber] = await this.rollup.status(localPendingBlockNumber, {
298
430
  blockNumber: currentL1BlockNumber
299
431
  });
432
+ const rollupStatus = {
433
+ provenBlockNumber,
434
+ provenArchive,
435
+ pendingBlockNumber,
436
+ pendingArchive
437
+ };
438
+ this.log.trace(`Retrieved rollup status at current L1 block ${currentL1BlockNumber}.`, {
439
+ localPendingBlockNumber,
440
+ blocksSynchedTo,
441
+ currentL1BlockNumber,
442
+ archiveForLocalPendingBlockNumber,
443
+ ...rollupStatus
444
+ });
300
445
  const updateProvenBlock = async ()=>{
446
+ // Annoying edge case: if proven block is moved back to 0 due to a reorg at the beginning of the chain,
447
+ // we need to set it to zero. This is an edge case because we dont have a block zero (initial block is one),
448
+ // so localBlockForDestinationProvenBlockNumber would not be found below.
449
+ if (provenBlockNumber === 0n) {
450
+ const localProvenBlockNumber = await this.store.getProvenL2BlockNumber();
451
+ if (localProvenBlockNumber !== Number(provenBlockNumber)) {
452
+ await this.store.setProvenL2BlockNumber(Number(provenBlockNumber));
453
+ this.log.info(`Rolled back proven chain to block ${provenBlockNumber}`, {
454
+ provenBlockNumber
455
+ });
456
+ }
457
+ }
301
458
  const localBlockForDestinationProvenBlockNumber = await this.getBlock(Number(provenBlockNumber));
302
459
  // Sanity check. I've hit what seems to be a state where the proven block is set to a value greater than the latest
303
460
  // synched block when requesting L2Tips from the archiver. This is the only place where the proven block is set.
@@ -305,6 +462,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
305
462
  if (localBlockForDestinationProvenBlockNumber && synched < localBlockForDestinationProvenBlockNumber?.number) {
306
463
  this.log.error(`Hit local block greater than last synched block: ${localBlockForDestinationProvenBlockNumber.number} > ${synched}`);
307
464
  }
465
+ this.log.trace(`Local block for remote proven block ${provenBlockNumber} is ${localBlockForDestinationProvenBlockNumber?.archive.root.toString() ?? 'undefined'}`);
308
466
  if (localBlockForDestinationProvenBlockNumber && provenArchive === localBlockForDestinationProvenBlockNumber.archive.root.toString()) {
309
467
  const localProvenBlockNumber = await this.store.getProvenL2BlockNumber();
310
468
  if (localProvenBlockNumber !== Number(provenBlockNumber)) {
@@ -312,6 +470,8 @@ import { ArchiverInstrumentation } from './instrumentation.js';
312
470
  this.log.info(`Updated proven chain to block ${provenBlockNumber}`, {
313
471
  provenBlockNumber
314
472
  });
473
+ } else {
474
+ this.log.trace(`Proven block ${provenBlockNumber} already stored.`);
315
475
  }
316
476
  }
317
477
  this.instrumentation.updateLastProvenBlock(Number(provenBlockNumber));
@@ -322,9 +482,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
322
482
  if (noBlocks) {
323
483
  await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
324
484
  this.log.debug(`No blocks to retrieve from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}, no blocks on chain`);
325
- return {
326
- provenBlockNumber
327
- };
485
+ return rollupStatus;
328
486
  }
329
487
  await updateProvenBlock();
330
488
  // Related to the L2 reorgs of the pending chain. We are only interested in actually addressing a reorg if there
@@ -342,12 +500,10 @@ import { ArchiverInstrumentation } from './instrumentation.js';
342
500
  // this block again (or any blocks before).
343
501
  // However, in the re-org scenario, our L1 node is temporarily lying to us and we end up potentially missing blocks
344
502
  // We must only set this block number based on actually retrieved logs.
345
- // TODO(https://github.com/AztecProtocol/aztec-packages/issues/8621): Tackle this properly when we handle L1 Re-orgs.
346
- //await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
503
+ // TODO(#8621): Tackle this properly when we handle L1 Re-orgs.
504
+ // await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
347
505
  this.log.debug(`No blocks to retrieve from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}`);
348
- return {
349
- provenBlockNumber
350
- };
506
+ return rollupStatus;
351
507
  }
352
508
  const localPendingBlockInChain = archiveForLocalPendingBlockNumber === localPendingBlock.archive.root.toString();
353
509
  if (!localPendingBlockInChain) {
@@ -377,6 +533,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
377
533
  // computed using the L2 block time vs the L1 block time.
378
534
  let searchStartBlock = blocksSynchedTo;
379
535
  let searchEndBlock = blocksSynchedTo;
536
+ let lastRetrievedBlock;
380
537
  do {
381
538
  [searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
382
539
  this.log.trace(`Retrieving L2 blocks from L1 block ${searchStartBlock} to ${searchEndBlock}`);
@@ -390,7 +547,8 @@ import { ArchiverInstrumentation } from './instrumentation.js';
390
547
  }
391
548
  const lastProcessedL1BlockNumber = retrievedBlocks[retrievedBlocks.length - 1].l1.blockNumber;
392
549
  this.log.debug(`Retrieved ${retrievedBlocks.length} new L2 blocks between L1 blocks ${searchStartBlock} and ${searchEndBlock} with last processed L1 block ${lastProcessedL1BlockNumber}.`);
393
- for (const block of retrievedBlocks){
550
+ const publishedBlocks = retrievedBlocks.map((b)=>retrievedBlockToPublishedL2Block(b));
551
+ for (const block of publishedBlocks){
394
552
  this.log.debug(`Ingesting new L2 block ${block.block.number} with ${block.block.body.txEffects.length} txs`, {
395
553
  blockHash: block.block.hash(),
396
554
  l1BlockNumber: block.l1.blockNumber,
@@ -398,23 +556,72 @@ import { ArchiverInstrumentation } from './instrumentation.js';
398
556
  ...block.block.getStats()
399
557
  });
400
558
  }
401
- const [processDuration] = await elapsed(()=>this.store.addBlocks(retrievedBlocks));
402
- this.instrumentation.processNewBlocks(processDuration / retrievedBlocks.length, retrievedBlocks.map((b)=>b.block));
403
- for (const block of retrievedBlocks){
559
+ try {
560
+ const [processDuration] = await elapsed(()=>this.store.addBlocks(publishedBlocks));
561
+ this.instrumentation.processNewBlocks(processDuration / publishedBlocks.length, publishedBlocks.map((b)=>b.block));
562
+ } catch (err) {
563
+ if (err instanceof InitialBlockNumberNotSequentialError) {
564
+ const { previousBlockNumber, newBlockNumber } = err;
565
+ const previousBlock = previousBlockNumber ? await this.store.getPublishedBlock(previousBlockNumber) : undefined;
566
+ const updatedL1SyncPoint = previousBlock?.l1.blockNumber ?? this.l1constants.l1StartBlock;
567
+ await this.store.setBlockSynchedL1BlockNumber(updatedL1SyncPoint);
568
+ this.log.warn(`Attempting to insert block ${newBlockNumber} with previous block ${previousBlockNumber}. Rolling back L1 sync point to ${updatedL1SyncPoint} to try and fetch the missing blocks.`, {
569
+ previousBlockNumber,
570
+ previousBlockHash: await previousBlock?.block.hash(),
571
+ newBlockNumber,
572
+ updatedL1SyncPoint
573
+ });
574
+ }
575
+ throw err;
576
+ }
577
+ for (const block of publishedBlocks){
404
578
  this.log.info(`Downloaded L2 block ${block.block.number}`, {
405
- blockHash: block.block.hash(),
579
+ blockHash: await block.block.hash(),
406
580
  blockNumber: block.block.number,
407
581
  txCount: block.block.body.txEffects.length,
408
- globalVariables: block.block.header.globalVariables.toInspect()
582
+ globalVariables: block.block.header.globalVariables.toInspect(),
583
+ archiveRoot: block.block.archive.root.toString(),
584
+ archiveNextLeafIndex: block.block.archive.nextAvailableLeafIndex
409
585
  });
410
586
  }
587
+ lastRetrievedBlock = publishedBlocks.at(-1) ?? lastRetrievedBlock;
411
588
  }while (searchEndBlock < currentL1BlockNumber)
412
589
  // Important that we update AFTER inserting the blocks.
413
590
  await updateProvenBlock();
414
591
  return {
415
- provenBlockNumber
592
+ ...rollupStatus,
593
+ lastRetrievedBlock
416
594
  };
417
595
  }
596
+ async checkForNewBlocksBeforeL1SyncPoint(status, blocksSynchedTo, currentL1BlockNumber) {
597
+ const { lastRetrievedBlock, pendingBlockNumber } = status;
598
+ // Compare the last L2 block we have (either retrieved in this round or loaded from store) with what the
599
+ // rollup contract told us was the latest one (pinned at the currentL1BlockNumber).
600
+ const latestLocalL2BlockNumber = lastRetrievedBlock?.block.number ?? await this.store.getSynchedL2BlockNumber();
601
+ if (latestLocalL2BlockNumber < pendingBlockNumber) {
602
+ // Here we have consumed all logs until the `currentL1Block` we pinned at the beginning of the archiver loop,
603
+ // but still havent reached the pending block according to the call to the rollup contract.
604
+ // We suspect an L1 reorg that added blocks *behind* us. If that is the case, it must have happened between the
605
+ // last L2 block we saw and the current one, so we reset the last synched L1 block number. In the edge case we
606
+ // don't have one, we go back 2 L1 epochs, which is the deepest possible reorg (assuming Casper is working).
607
+ const latestLocalL2Block = lastRetrievedBlock ?? (latestLocalL2BlockNumber > 0 ? await this.store.getPublishedBlocks(latestLocalL2BlockNumber, 1).then(([b])=>b) : undefined);
608
+ const targetL1BlockNumber = latestLocalL2Block?.l1.blockNumber ?? maxBigint(currentL1BlockNumber - 64n, 0n);
609
+ const latestLocalL2BlockArchive = latestLocalL2Block?.block.archive.root.toString();
610
+ this.log.warn(`Failed to reach L2 block ${pendingBlockNumber} at ${currentL1BlockNumber} (latest is ${latestLocalL2BlockNumber}). ` + `Rolling back last synched L1 block number to ${targetL1BlockNumber}.`, {
611
+ latestLocalL2BlockNumber,
612
+ latestLocalL2BlockArchive,
613
+ blocksSynchedTo,
614
+ currentL1BlockNumber,
615
+ ...status
616
+ });
617
+ await this.store.setBlockSynchedL1BlockNumber(targetL1BlockNumber);
618
+ } else {
619
+ this.log.trace(`No new blocks behind L1 sync point to retrieve.`, {
620
+ latestLocalL2BlockNumber,
621
+ pendingBlockNumber
622
+ });
623
+ }
624
+ }
418
625
  /** Resumes the archiver after a stop. */ resume() {
419
626
  if (!this.runningPromise) {
420
627
  throw new Error(`Archiver was never started`);
@@ -535,7 +742,7 @@ import { ArchiverInstrumentation } from './instrumentation.js';
535
742
  }
536
743
  /** Equivalent to getBlocks but includes publish data. */ async getPublishedBlocks(from, limit, proven) {
537
744
  const limitWithProven = proven ? Math.min(limit, Math.max(await this.store.getProvenL2BlockNumber() - from + 1, 0)) : limit;
538
- return limitWithProven === 0 ? [] : await this.store.getBlocks(from, limitWithProven);
745
+ return limitWithProven === 0 ? [] : await this.store.getPublishedBlocks(from, limitWithProven);
539
746
  }
540
747
  /**
541
748
  * Gets an l2 block.
@@ -546,11 +753,11 @@ import { ArchiverInstrumentation } from './instrumentation.js';
546
753
  if (number < 0) {
547
754
  number = await this.store.getSynchedL2BlockNumber();
548
755
  }
549
- if (number == 0) {
756
+ if (number === 0) {
550
757
  return undefined;
551
758
  }
552
- const blocks = await this.store.getBlocks(number, 1);
553
- return blocks.length === 0 ? undefined : blocks[0].block;
759
+ const publishedBlock = await this.store.getPublishedBlock(number);
760
+ return publishedBlock?.block;
554
761
  }
555
762
  async getBlockHeader(number) {
556
763
  if (number === 'latest') {
@@ -647,9 +854,13 @@ import { ArchiverInstrumentation } from './instrumentation.js';
647
854
  this.getBlockNumber(),
648
855
  this.getProvenBlockNumber()
649
856
  ]);
650
- const [latestBlockHeader, provenBlockHeader] = await Promise.all([
857
+ // TODO(#13569): Compute proper finalized block number based on L1 finalized block.
858
+ // We just force it 2 epochs worth of proven data for now.
859
+ const finalizedBlockNumber = Math.max(provenBlockNumber - this.l1constants.epochDuration * 2, 0);
860
+ const [latestBlockHeader, provenBlockHeader, finalizedBlockHeader] = await Promise.all([
651
861
  latestBlockNumber > 0 ? this.getBlockHeader(latestBlockNumber) : undefined,
652
- provenBlockNumber > 0 ? this.getBlockHeader(provenBlockNumber) : undefined
862
+ provenBlockNumber > 0 ? this.getBlockHeader(provenBlockNumber) : undefined,
863
+ finalizedBlockNumber > 0 ? this.getBlockHeader(finalizedBlockNumber) : undefined
653
864
  ]);
654
865
  if (latestBlockNumber > 0 && !latestBlockHeader) {
655
866
  throw new Error(`Failed to retrieve latest block header for block ${latestBlockNumber}`);
@@ -657,9 +868,12 @@ import { ArchiverInstrumentation } from './instrumentation.js';
657
868
  if (provenBlockNumber > 0 && !provenBlockHeader) {
658
869
  throw new Error(`Failed to retrieve proven block header for block ${provenBlockNumber} (latest block is ${latestBlockNumber})`);
659
870
  }
871
+ if (finalizedBlockNumber > 0 && !finalizedBlockHeader) {
872
+ throw new Error(`Failed to retrieve finalized block header for block ${finalizedBlockNumber} (latest block is ${latestBlockNumber})`);
873
+ }
660
874
  const latestBlockHeaderHash = await latestBlockHeader?.hash();
661
875
  const provenBlockHeaderHash = await provenBlockHeader?.hash();
662
- const finalizedBlockHeaderHash = await provenBlockHeader?.hash();
876
+ const finalizedBlockHeaderHash = await finalizedBlockHeader?.hash();
663
877
  return {
664
878
  latest: {
665
879
  number: latestBlockNumber,
@@ -670,11 +884,46 @@ import { ArchiverInstrumentation } from './instrumentation.js';
670
884
  hash: provenBlockHeaderHash?.toString()
671
885
  },
672
886
  finalized: {
673
- number: provenBlockNumber,
887
+ number: finalizedBlockNumber,
674
888
  hash: finalizedBlockHeaderHash?.toString()
675
889
  }
676
890
  };
677
891
  }
892
+ async rollbackTo(targetL2BlockNumber) {
893
+ const currentBlocks = await this.getL2Tips();
894
+ const currentL2Block = currentBlocks.latest.number;
895
+ const currentProvenBlock = currentBlocks.proven.number;
896
+ // const currentFinalizedBlock = currentBlocks.finalized.number;
897
+ if (targetL2BlockNumber >= currentL2Block) {
898
+ throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
899
+ }
900
+ const blocksToUnwind = currentL2Block - targetL2BlockNumber;
901
+ const targetL2Block = await this.store.getPublishedBlock(targetL2BlockNumber);
902
+ if (!targetL2Block) {
903
+ throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
904
+ }
905
+ const targetL1BlockNumber = targetL2Block.l1.blockNumber;
906
+ const targetL1BlockHash = await this.getL1BlockHash(targetL1BlockNumber);
907
+ this.log.info(`Unwinding ${blocksToUnwind} blocks from L2 block ${currentL2Block}`);
908
+ await this.store.unwindBlocks(currentL2Block, blocksToUnwind);
909
+ this.log.info(`Unwinding L1 to L2 messages to ${targetL2BlockNumber}`);
910
+ await this.store.rollbackL1ToL2MessagesToL2Block(targetL2BlockNumber);
911
+ this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
912
+ await this.store.setBlockSynchedL1BlockNumber(targetL1BlockNumber);
913
+ await this.store.setMessageSynchedL1Block({
914
+ l1BlockNumber: targetL1BlockNumber,
915
+ l1BlockHash: targetL1BlockHash
916
+ });
917
+ if (targetL2BlockNumber < currentProvenBlock) {
918
+ this.log.info(`Clearing proven L2 block number`);
919
+ await this.store.setProvenL2BlockNumber(0);
920
+ }
921
+ // TODO(palla/reorg): Set the finalized block when we add support for it.
922
+ // if (targetL2BlockNumber < currentFinalizedBlock) {
923
+ // this.log.info(`Clearing finalized L2 block number`);
924
+ // await this.store.setFinalizedL2BlockNumber(0);
925
+ // }
926
+ }
678
927
  }
679
928
  _ts_decorate([
680
929
  trackSpan('Archiver.sync', (initialRun)=>({
@@ -691,7 +940,7 @@ var Operation = /*#__PURE__*/ function(Operation) {
691
940
  *
692
941
  * I would have preferred to not have this type. But it is useful for handling the logic that any
693
942
  * store would need to include otherwise while exposing fewer functions and logic directly to the archiver.
694
- */ class ArchiverStoreHelper {
943
+ */ export class ArchiverStoreHelper {
695
944
  store;
696
945
  #log;
697
946
  constructor(store){
@@ -796,33 +1045,40 @@ var Operation = /*#__PURE__*/ function(Operation) {
796
1045
  }
797
1046
  return true;
798
1047
  }
799
- async addBlocks(blocks) {
800
- const opResults = await Promise.all([
801
- this.store.addLogs(blocks.map((block)=>block.block)),
802
- // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
803
- ...blocks.map(async (block)=>{
804
- const contractClassLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
805
- // ContractInstanceDeployed event logs are broadcast in privateLogs.
806
- const privateLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
807
- const publicLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
808
- return (await Promise.all([
809
- this.#updateRegisteredContractClasses(contractClassLogs, block.block.number, 0),
810
- this.#updateDeployedContractInstances(privateLogs, block.block.number, 0),
811
- this.#updateUpdatedContractInstances(publicLogs, block.block.number, 0),
812
- this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.block.number)
813
- ])).every(Boolean);
814
- }),
815
- this.store.addBlocks(blocks)
816
- ]);
817
- return opResults.every(Boolean);
1048
+ addBlocks(blocks) {
1049
+ // Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
1050
+ // or if the previous block is not in the store.
1051
+ return this.store.transactionAsync(async ()=>{
1052
+ await this.store.addBlocks(blocks);
1053
+ const opResults = await Promise.all([
1054
+ this.store.addLogs(blocks.map((block)=>block.block)),
1055
+ // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1056
+ ...blocks.map(async (block)=>{
1057
+ const contractClassLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1058
+ // ContractInstanceDeployed event logs are broadcast in privateLogs.
1059
+ const privateLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1060
+ const publicLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1061
+ return (await Promise.all([
1062
+ this.#updateRegisteredContractClasses(contractClassLogs, block.block.number, 0),
1063
+ this.#updateDeployedContractInstances(privateLogs, block.block.number, 0),
1064
+ this.#updateUpdatedContractInstances(publicLogs, block.block.number, 0),
1065
+ this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.block.number)
1066
+ ])).every(Boolean);
1067
+ })
1068
+ ]);
1069
+ return opResults.every(Boolean);
1070
+ });
818
1071
  }
819
1072
  async unwindBlocks(from, blocksToUnwind) {
820
1073
  const last = await this.getSynchedL2BlockNumber();
821
1074
  if (from != last) {
822
- throw new Error(`Can only remove from the tip`);
1075
+ throw new Error(`Cannot unwind blocks from block ${from} when the last block is ${last}`);
1076
+ }
1077
+ if (blocksToUnwind <= 0) {
1078
+ throw new Error(`Cannot unwind ${blocksToUnwind} blocks`);
823
1079
  }
824
1080
  // from - blocksToUnwind = the new head, so + 1 for what we need to remove
825
- const blocks = await this.getBlocks(from - blocksToUnwind + 1, blocksToUnwind);
1081
+ const blocks = await this.getPublishedBlocks(from - blocksToUnwind + 1, blocksToUnwind);
826
1082
  const opResults = await Promise.all([
827
1083
  // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
828
1084
  ...blocks.map(async (block)=>{
@@ -841,8 +1097,11 @@ var Operation = /*#__PURE__*/ function(Operation) {
841
1097
  ]);
842
1098
  return opResults.every(Boolean);
843
1099
  }
844
- getBlocks(from, limit) {
845
- return this.store.getBlocks(from, limit);
1100
+ getPublishedBlocks(from, limit) {
1101
+ return this.store.getPublishedBlocks(from, limit);
1102
+ }
1103
+ getPublishedBlock(number) {
1104
+ return this.store.getPublishedBlock(number);
846
1105
  }
847
1106
  getBlockHeaders(from, limit) {
848
1107
  return this.store.getBlockHeaders(from, limit);
@@ -886,8 +1145,8 @@ var Operation = /*#__PURE__*/ function(Operation) {
886
1145
  setBlockSynchedL1BlockNumber(l1BlockNumber) {
887
1146
  return this.store.setBlockSynchedL1BlockNumber(l1BlockNumber);
888
1147
  }
889
- setMessageSynchedL1BlockNumber(l1BlockNumber) {
890
- return this.store.setMessageSynchedL1BlockNumber(l1BlockNumber);
1148
+ setMessageSynchedL1Block(l1Block) {
1149
+ return this.store.setMessageSynchedL1Block(l1Block);
891
1150
  }
892
1151
  getSynchPoint() {
893
1152
  return this.store.getSynchPoint();
@@ -916,4 +1175,16 @@ var Operation = /*#__PURE__*/ function(Operation) {
916
1175
  estimateSize() {
917
1176
  return this.store.estimateSize();
918
1177
  }
1178
+ rollbackL1ToL2MessagesToL2Block(targetBlockNumber) {
1179
+ return this.store.rollbackL1ToL2MessagesToL2Block(targetBlockNumber);
1180
+ }
1181
+ iterateL1ToL2Messages(range = {}) {
1182
+ return this.store.iterateL1ToL2Messages(range);
1183
+ }
1184
+ removeL1ToL2Messages(startIndex) {
1185
+ return this.store.removeL1ToL2Messages(startIndex);
1186
+ }
1187
+ getLastL1ToL2Message() {
1188
+ return this.store.getLastL1ToL2Message();
1189
+ }
919
1190
  }