@aztec/archiver 3.0.0-rc.5 → 4.0.0-nightly.20260107

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 (55) hide show
  1. package/dest/archiver/archiver.d.ts +69 -49
  2. package/dest/archiver/archiver.d.ts.map +1 -1
  3. package/dest/archiver/archiver.js +777 -214
  4. package/dest/archiver/archiver_store.d.ts +89 -30
  5. package/dest/archiver/archiver_store.d.ts.map +1 -1
  6. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  8. package/dest/archiver/archiver_store_test_suite.js +1785 -288
  9. package/dest/archiver/config.d.ts +3 -3
  10. package/dest/archiver/config.d.ts.map +1 -1
  11. package/dest/archiver/config.js +2 -2
  12. package/dest/archiver/errors.d.ts +25 -1
  13. package/dest/archiver/errors.d.ts.map +1 -1
  14. package/dest/archiver/errors.js +37 -0
  15. package/dest/archiver/index.d.ts +2 -2
  16. package/dest/archiver/index.d.ts.map +1 -1
  17. package/dest/archiver/kv_archiver_store/block_store.d.ts +49 -17
  18. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  19. package/dest/archiver/kv_archiver_store/block_store.js +320 -84
  20. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +33 -37
  21. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  22. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +60 -35
  23. package/dest/archiver/kv_archiver_store/log_store.d.ts +14 -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 +149 -62
  26. package/dest/archiver/l1/bin/retrieve-calldata.js +5 -3
  27. package/dest/archiver/l1/calldata_retriever.d.ts +17 -3
  28. package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -1
  29. package/dest/archiver/l1/calldata_retriever.js +75 -7
  30. package/dest/archiver/l1/data_retrieval.d.ts +13 -10
  31. package/dest/archiver/l1/data_retrieval.d.ts.map +1 -1
  32. package/dest/archiver/l1/data_retrieval.js +31 -18
  33. package/dest/archiver/structs/published.d.ts +1 -2
  34. package/dest/archiver/structs/published.d.ts.map +1 -1
  35. package/dest/factory.d.ts +1 -1
  36. package/dest/factory.js +1 -1
  37. package/dest/test/mock_l2_block_source.d.ts +10 -3
  38. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  39. package/dest/test/mock_l2_block_source.js +16 -15
  40. package/package.json +13 -13
  41. package/src/archiver/archiver.ts +509 -260
  42. package/src/archiver/archiver_store.ts +99 -29
  43. package/src/archiver/archiver_store_test_suite.ts +1831 -274
  44. package/src/archiver/config.ts +7 -3
  45. package/src/archiver/errors.ts +64 -0
  46. package/src/archiver/index.ts +1 -1
  47. package/src/archiver/kv_archiver_store/block_store.ts +434 -94
  48. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +74 -49
  49. package/src/archiver/kv_archiver_store/log_store.ts +213 -77
  50. package/src/archiver/l1/bin/retrieve-calldata.ts +3 -3
  51. package/src/archiver/l1/calldata_retriever.ts +116 -6
  52. package/src/archiver/l1/data_retrieval.ts +41 -20
  53. package/src/archiver/structs/published.ts +0 -1
  54. package/src/factory.ts +1 -1
  55. package/src/test/mock_l2_block_source.ts +20 -16
@@ -1,9 +1,376 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1
+ function applyDecs2203RFactory() {
2
+ function createAddInitializerMethod(initializers, decoratorFinishedRef) {
3
+ return function addInitializer(initializer) {
4
+ assertNotFinished(decoratorFinishedRef, "addInitializer");
5
+ assertCallable(initializer, "An initializer");
6
+ initializers.push(initializer);
7
+ };
8
+ }
9
+ function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
10
+ var kindStr;
11
+ switch(kind){
12
+ case 1:
13
+ kindStr = "accessor";
14
+ break;
15
+ case 2:
16
+ kindStr = "method";
17
+ break;
18
+ case 3:
19
+ kindStr = "getter";
20
+ break;
21
+ case 4:
22
+ kindStr = "setter";
23
+ break;
24
+ default:
25
+ kindStr = "field";
26
+ }
27
+ var ctx = {
28
+ kind: kindStr,
29
+ name: isPrivate ? "#" + name : name,
30
+ static: isStatic,
31
+ private: isPrivate,
32
+ metadata: metadata
33
+ };
34
+ var decoratorFinishedRef = {
35
+ v: false
36
+ };
37
+ ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
38
+ var get, set;
39
+ if (kind === 0) {
40
+ if (isPrivate) {
41
+ get = desc.get;
42
+ set = desc.set;
43
+ } else {
44
+ get = function() {
45
+ return this[name];
46
+ };
47
+ set = function(v) {
48
+ this[name] = v;
49
+ };
50
+ }
51
+ } else if (kind === 2) {
52
+ get = function() {
53
+ return desc.value;
54
+ };
55
+ } else {
56
+ if (kind === 1 || kind === 3) {
57
+ get = function() {
58
+ return desc.get.call(this);
59
+ };
60
+ }
61
+ if (kind === 1 || kind === 4) {
62
+ set = function(v) {
63
+ desc.set.call(this, v);
64
+ };
65
+ }
66
+ }
67
+ ctx.access = get && set ? {
68
+ get: get,
69
+ set: set
70
+ } : get ? {
71
+ get: get
72
+ } : {
73
+ set: set
74
+ };
75
+ try {
76
+ return dec(value, ctx);
77
+ } finally{
78
+ decoratorFinishedRef.v = true;
79
+ }
80
+ }
81
+ function assertNotFinished(decoratorFinishedRef, fnName) {
82
+ if (decoratorFinishedRef.v) {
83
+ throw new Error("attempted to call " + fnName + " after decoration was finished");
84
+ }
85
+ }
86
+ function assertCallable(fn, hint) {
87
+ if (typeof fn !== "function") {
88
+ throw new TypeError(hint + " must be a function");
89
+ }
90
+ }
91
+ function assertValidReturnValue(kind, value) {
92
+ var type = typeof value;
93
+ if (kind === 1) {
94
+ if (type !== "object" || value === null) {
95
+ throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
96
+ }
97
+ if (value.get !== undefined) {
98
+ assertCallable(value.get, "accessor.get");
99
+ }
100
+ if (value.set !== undefined) {
101
+ assertCallable(value.set, "accessor.set");
102
+ }
103
+ if (value.init !== undefined) {
104
+ assertCallable(value.init, "accessor.init");
105
+ }
106
+ } else if (type !== "function") {
107
+ var hint;
108
+ if (kind === 0) {
109
+ hint = "field";
110
+ } else if (kind === 10) {
111
+ hint = "class";
112
+ } else {
113
+ hint = "method";
114
+ }
115
+ throw new TypeError(hint + " decorators must return a function or void 0");
116
+ }
117
+ }
118
+ function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
119
+ var decs = decInfo[0];
120
+ var desc, init, value;
121
+ if (isPrivate) {
122
+ if (kind === 0 || kind === 1) {
123
+ desc = {
124
+ get: decInfo[3],
125
+ set: decInfo[4]
126
+ };
127
+ } else if (kind === 3) {
128
+ desc = {
129
+ get: decInfo[3]
130
+ };
131
+ } else if (kind === 4) {
132
+ desc = {
133
+ set: decInfo[3]
134
+ };
135
+ } else {
136
+ desc = {
137
+ value: decInfo[3]
138
+ };
139
+ }
140
+ } else if (kind !== 0) {
141
+ desc = Object.getOwnPropertyDescriptor(base, name);
142
+ }
143
+ if (kind === 1) {
144
+ value = {
145
+ get: desc.get,
146
+ set: desc.set
147
+ };
148
+ } else if (kind === 2) {
149
+ value = desc.value;
150
+ } else if (kind === 3) {
151
+ value = desc.get;
152
+ } else if (kind === 4) {
153
+ value = desc.set;
154
+ }
155
+ var newValue, get, set;
156
+ if (typeof decs === "function") {
157
+ newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
158
+ if (newValue !== void 0) {
159
+ assertValidReturnValue(kind, newValue);
160
+ if (kind === 0) {
161
+ init = newValue;
162
+ } else if (kind === 1) {
163
+ init = newValue.init;
164
+ get = newValue.get || value.get;
165
+ set = newValue.set || value.set;
166
+ value = {
167
+ get: get,
168
+ set: set
169
+ };
170
+ } else {
171
+ value = newValue;
172
+ }
173
+ }
174
+ } else {
175
+ for(var i = decs.length - 1; i >= 0; i--){
176
+ var dec = decs[i];
177
+ newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
178
+ if (newValue !== void 0) {
179
+ assertValidReturnValue(kind, newValue);
180
+ var newInit;
181
+ if (kind === 0) {
182
+ newInit = newValue;
183
+ } else if (kind === 1) {
184
+ newInit = newValue.init;
185
+ get = newValue.get || value.get;
186
+ set = newValue.set || value.set;
187
+ value = {
188
+ get: get,
189
+ set: set
190
+ };
191
+ } else {
192
+ value = newValue;
193
+ }
194
+ if (newInit !== void 0) {
195
+ if (init === void 0) {
196
+ init = newInit;
197
+ } else if (typeof init === "function") {
198
+ init = [
199
+ init,
200
+ newInit
201
+ ];
202
+ } else {
203
+ init.push(newInit);
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ if (kind === 0 || kind === 1) {
210
+ if (init === void 0) {
211
+ init = function(instance, init) {
212
+ return init;
213
+ };
214
+ } else if (typeof init !== "function") {
215
+ var ownInitializers = init;
216
+ init = function(instance, init) {
217
+ var value = init;
218
+ for(var i = 0; i < ownInitializers.length; i++){
219
+ value = ownInitializers[i].call(instance, value);
220
+ }
221
+ return value;
222
+ };
223
+ } else {
224
+ var originalInitializer = init;
225
+ init = function(instance, init) {
226
+ return originalInitializer.call(instance, init);
227
+ };
228
+ }
229
+ ret.push(init);
230
+ }
231
+ if (kind !== 0) {
232
+ if (kind === 1) {
233
+ desc.get = value.get;
234
+ desc.set = value.set;
235
+ } else if (kind === 2) {
236
+ desc.value = value;
237
+ } else if (kind === 3) {
238
+ desc.get = value;
239
+ } else if (kind === 4) {
240
+ desc.set = value;
241
+ }
242
+ if (isPrivate) {
243
+ if (kind === 1) {
244
+ ret.push(function(instance, args) {
245
+ return value.get.call(instance, args);
246
+ });
247
+ ret.push(function(instance, args) {
248
+ return value.set.call(instance, args);
249
+ });
250
+ } else if (kind === 2) {
251
+ ret.push(value);
252
+ } else {
253
+ ret.push(function(instance, args) {
254
+ return value.call(instance, args);
255
+ });
256
+ }
257
+ } else {
258
+ Object.defineProperty(base, name, desc);
259
+ }
260
+ }
261
+ }
262
+ function applyMemberDecs(Class, decInfos, metadata) {
263
+ var ret = [];
264
+ var protoInitializers;
265
+ var staticInitializers;
266
+ var existingProtoNonFields = new Map();
267
+ var existingStaticNonFields = new Map();
268
+ for(var i = 0; i < decInfos.length; i++){
269
+ var decInfo = decInfos[i];
270
+ if (!Array.isArray(decInfo)) continue;
271
+ var kind = decInfo[1];
272
+ var name = decInfo[2];
273
+ var isPrivate = decInfo.length > 3;
274
+ var isStatic = kind >= 5;
275
+ var base;
276
+ var initializers;
277
+ if (isStatic) {
278
+ base = Class;
279
+ kind = kind - 5;
280
+ staticInitializers = staticInitializers || [];
281
+ initializers = staticInitializers;
282
+ } else {
283
+ base = Class.prototype;
284
+ protoInitializers = protoInitializers || [];
285
+ initializers = protoInitializers;
286
+ }
287
+ if (kind !== 0 && !isPrivate) {
288
+ var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
289
+ var existingKind = existingNonFields.get(name) || 0;
290
+ if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) {
291
+ throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
292
+ } else if (!existingKind && kind > 2) {
293
+ existingNonFields.set(name, kind);
294
+ } else {
295
+ existingNonFields.set(name, true);
296
+ }
297
+ }
298
+ applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
299
+ }
300
+ pushInitializers(ret, protoInitializers);
301
+ pushInitializers(ret, staticInitializers);
302
+ return ret;
303
+ }
304
+ function pushInitializers(ret, initializers) {
305
+ if (initializers) {
306
+ ret.push(function(instance) {
307
+ for(var i = 0; i < initializers.length; i++){
308
+ initializers[i].call(instance);
309
+ }
310
+ return instance;
311
+ });
312
+ }
313
+ }
314
+ function applyClassDecs(targetClass, classDecs, metadata) {
315
+ if (classDecs.length > 0) {
316
+ var initializers = [];
317
+ var newClass = targetClass;
318
+ var name = targetClass.name;
319
+ for(var i = classDecs.length - 1; i >= 0; i--){
320
+ var decoratorFinishedRef = {
321
+ v: false
322
+ };
323
+ try {
324
+ var nextNewClass = classDecs[i](newClass, {
325
+ kind: "class",
326
+ name: name,
327
+ addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
328
+ metadata
329
+ });
330
+ } finally{
331
+ decoratorFinishedRef.v = true;
332
+ }
333
+ if (nextNewClass !== undefined) {
334
+ assertValidReturnValue(10, nextNewClass);
335
+ newClass = nextNewClass;
336
+ }
337
+ }
338
+ return [
339
+ defineMetadata(newClass, metadata),
340
+ function() {
341
+ for(var i = 0; i < initializers.length; i++){
342
+ initializers[i].call(newClass);
343
+ }
344
+ }
345
+ ];
346
+ }
347
+ }
348
+ function defineMetadata(Class, metadata) {
349
+ return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
350
+ configurable: true,
351
+ enumerable: true,
352
+ value: metadata
353
+ });
354
+ }
355
+ return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
356
+ if (parentClass !== void 0) {
357
+ var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
358
+ }
359
+ var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata);
360
+ var e = applyMemberDecs(targetClass, memberDecs, metadata);
361
+ if (!classDecs.length) defineMetadata(targetClass, metadata);
362
+ return {
363
+ e: e,
364
+ get c () {
365
+ return applyClassDecs(targetClass, classDecs, metadata);
366
+ }
367
+ };
368
+ };
369
+ }
370
+ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
371
+ return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
6
372
  }
373
+ var _dec, _initProto;
7
374
  import { GENESIS_BLOCK_HEADER_HASH } from '@aztec/constants';
8
375
  import { EpochCache } from '@aztec/epoch-cache';
9
376
  import { createEthereumChain } from '@aztec/ethereum/chain';
@@ -18,9 +385,11 @@ import { promiseWithResolvers } from '@aztec/foundation/promise';
18
385
  import { RunningPromise, makeLoggingErrorHandler } from '@aztec/foundation/running-promise';
19
386
  import { count } from '@aztec/foundation/string';
20
387
  import { DateProvider, Timer, elapsed } from '@aztec/foundation/timer';
388
+ import { isDefined } from '@aztec/foundation/types';
21
389
  import { ContractClassPublishedEvent, PrivateFunctionBroadcastedEvent, UtilityFunctionBroadcastedEvent } from '@aztec/protocol-contracts/class-registry';
22
390
  import { ContractInstancePublishedEvent, ContractInstanceUpdatedEvent } from '@aztec/protocol-contracts/instance-registry';
23
- import { L2Block, L2BlockSourceEvents, PublishedL2Block } from '@aztec/stdlib/block';
391
+ import { CommitteeAttestation, L2Block, L2BlockSourceEvents, PublishedL2Block } from '@aztec/stdlib/block';
392
+ import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
24
393
  import { computePublicBytecodeCommitment, isValidPrivateFunctionMembershipProof, isValidUtilityFunctionMembershipProof } from '@aztec/stdlib/contract';
25
394
  import { getEpochAtSlot, getEpochNumberAtTimestamp, getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
26
395
  import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
@@ -28,7 +397,7 @@ import { getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
28
397
  import { EventEmitter } from 'events';
29
398
  import groupBy from 'lodash.groupby';
30
399
  import { createPublicClient, fallback, http } from 'viem';
31
- import { InitialBlockNumberNotSequentialError, NoBlobBodiesFoundError } from './errors.js';
400
+ import { InitialCheckpointNumberNotSequentialError, NoBlobBodiesFoundError } from './errors.js';
32
401
  import { ArchiverInstrumentation } from './instrumentation.js';
33
402
  import { retrieveCheckpointsFromRollup, retrieveL1ToL2Message, retrieveL1ToL2Messages, retrievedToPublishedCheckpoint } from './l1/data_retrieval.js';
34
403
  import { validateAndLogTraceAvailability } from './l1/validate_trace.js';
@@ -42,6 +411,7 @@ function mapArchiverConfig(config) {
42
411
  ethereumAllowNoDebugHosts: config.ethereumAllowNoDebugHosts
43
412
  };
44
413
  }
414
+ _dec = trackSpan('Archiver.sync');
45
415
  /**
46
416
  * Pulls checkpoints in a non-blocking manner and provides interface for their retrieval.
47
417
  * Responsible for handling robust L1 polling so that other components do not need to
@@ -52,12 +422,21 @@ function mapArchiverConfig(config) {
52
422
  l1Addresses;
53
423
  dataStore;
54
424
  config;
55
- blobSinkClient;
425
+ blobClient;
56
426
  epochCache;
57
427
  dateProvider;
58
428
  instrumentation;
59
429
  l1constants;
60
430
  log;
431
+ static{
432
+ ({ e: [_initProto] } = _apply_decs_2203_r(this, [
433
+ [
434
+ _dec,
435
+ 2,
436
+ "sync"
437
+ ]
438
+ ], []));
439
+ }
61
440
  /** A loop in which we will be continually fetching new checkpoints. */ runningPromise;
62
441
  rollup;
63
442
  inbox;
@@ -66,6 +445,7 @@ function mapArchiverConfig(config) {
66
445
  l1Timestamp;
67
446
  initialSyncComplete;
68
447
  initialSyncPromise;
448
+ /** Queue of blocks to be added to the store, processed by the sync loop. */ blockQueue;
69
449
  tracer;
70
450
  /**
71
451
  * Creates a new instance of the Archiver.
@@ -77,8 +457,8 @@ function mapArchiverConfig(config) {
77
457
  * @param pollingIntervalMs - The interval for polling for L1 logs (in milliseconds).
78
458
  * @param store - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data.
79
459
  * @param log - A logger.
80
- */ constructor(publicClient, debugClient, l1Addresses, dataStore, config, blobSinkClient, epochCache, dateProvider, instrumentation, l1constants, log = createLogger('archiver')){
81
- super(), this.publicClient = publicClient, this.debugClient = debugClient, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.blobSinkClient = blobSinkClient, this.epochCache = epochCache, this.dateProvider = dateProvider, this.instrumentation = instrumentation, this.l1constants = l1constants, this.log = log, this.initialSyncComplete = false;
460
+ */ constructor(publicClient, debugClient, l1Addresses, dataStore, config, blobClient, epochCache, dateProvider, instrumentation, l1constants, log = createLogger('archiver')){
461
+ super(), this.publicClient = publicClient, this.debugClient = debugClient, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.blobClient = blobClient, this.epochCache = epochCache, this.dateProvider = dateProvider, this.instrumentation = instrumentation, this.l1constants = l1constants, this.log = log, this.initialSyncComplete = (_initProto(this), false), this.blockQueue = [];
82
462
  this.tracer = instrumentation.tracer;
83
463
  this.store = new ArchiverStoreHelper(dataStore);
84
464
  this.rollup = new RollupContract(publicClient, l1Addresses.rollupAddress);
@@ -98,14 +478,18 @@ function mapArchiverConfig(config) {
98
478
  const chain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
99
479
  const publicClient = createPublicClient({
100
480
  chain: chain.chainInfo,
101
- transport: fallback(config.l1RpcUrls.map((url)=>http(url))),
481
+ transport: fallback(config.l1RpcUrls.map((url)=>http(url, {
482
+ batch: false
483
+ }))),
102
484
  pollingInterval: config.viemPollingIntervalMS
103
485
  });
104
486
  // Create debug client using debug RPC URLs if available, otherwise fall back to regular RPC URLs
105
487
  const debugRpcUrls = config.l1DebugRpcUrls.length > 0 ? config.l1DebugRpcUrls : config.l1RpcUrls;
106
488
  const debugClient = createPublicClient({
107
489
  chain: chain.chainInfo,
108
- transport: fallback(debugRpcUrls.map((url)=>http(url))),
490
+ transport: fallback(debugRpcUrls.map((url)=>http(url, {
491
+ batch: false
492
+ }))),
109
493
  pollingInterval: config.viemPollingIntervalMS
110
494
  });
111
495
  const rollup = new RollupContract(publicClient, config.l1Contracts.rollupAddress);
@@ -129,7 +513,7 @@ function mapArchiverConfig(config) {
129
513
  slotDuration,
130
514
  ethereumSlotDuration,
131
515
  proofSubmissionEpochs: Number(proofSubmissionEpochs),
132
- genesisArchiveRoot: Fr.fromHexString(genesisArchiveRoot)
516
+ genesisArchiveRoot: Fr.fromString(genesisArchiveRoot.toString())
133
517
  };
134
518
  const opts = merge({
135
519
  pollingIntervalMs: 10_000,
@@ -142,7 +526,7 @@ function mapArchiverConfig(config) {
142
526
  const archiver = new Archiver(publicClient, debugClient, {
143
527
  ...config.l1Contracts,
144
528
  slashingProposerAddress
145
- }, archiverStore, opts, deps.blobSinkClient, epochCache, deps.dateProvider ?? new DateProvider(), await ArchiverInstrumentation.new(telemetry, ()=>archiverStore.estimateSize()), l1Constants);
529
+ }, archiverStore, opts, deps.blobClient, epochCache, deps.dateProvider ?? new DateProvider(), await ArchiverInstrumentation.new(telemetry, ()=>archiverStore.estimateSize()), l1Constants);
146
530
  await archiver.start(blockUntilSynced);
147
531
  return archiver;
148
532
  }
@@ -156,17 +540,17 @@ function mapArchiverConfig(config) {
156
540
  if (this.runningPromise.isRunning()) {
157
541
  throw new Error('Archiver is already running');
158
542
  }
159
- await this.blobSinkClient.testSources();
543
+ await this.blobClient.testSources();
160
544
  await this.testEthereumNodeSynced();
161
545
  await validateAndLogTraceAvailability(this.debugClient, this.config.ethereumAllowNoDebugHosts ?? false);
162
546
  // Log initial state for the archiver
163
547
  const { l1StartBlock } = this.l1constants;
164
548
  const { blocksSynchedTo = l1StartBlock, messagesSynchedTo = l1StartBlock } = await this.store.getSynchPoint();
165
- const currentL2Block = await this.getBlockNumber();
166
- this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2 block ${currentL2Block}`, {
549
+ const currentL2Checkpoint = await this.getSynchedCheckpointNumber();
550
+ this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2 checkpoint ${currentL2Checkpoint}`, {
167
551
  blocksSynchedTo,
168
552
  messagesSynchedTo,
169
- currentL2Block
553
+ currentL2Checkpoint
170
554
  });
171
555
  // Start sync loop, and return the wait for initial sync if we are asked to block until synced
172
556
  this.runningPromise.start();
@@ -177,6 +561,51 @@ function mapArchiverConfig(config) {
177
561
  syncImmediate() {
178
562
  return this.runningPromise.trigger();
179
563
  }
564
+ /**
565
+ * Queues a block to be added to the archiver store and triggers processing.
566
+ * The block will be processed by the sync loop.
567
+ * Implements the L2BlockSink interface.
568
+ * @param block - The L2 block to add.
569
+ * @returns A promise that resolves when the block has been added to the store, or rejects on error.
570
+ */ addBlock(block) {
571
+ return new Promise((resolve, reject)=>{
572
+ this.blockQueue.push({
573
+ block,
574
+ resolve,
575
+ reject
576
+ });
577
+ this.log.debug(`Queued block ${block.number} for processing`);
578
+ // Trigger an immediate sync, but don't wait for it - the promise resolves when the block is processed
579
+ this.syncImmediate().catch((err)=>{
580
+ this.log.error(`Sync immediate call failed: ${err}`);
581
+ });
582
+ });
583
+ }
584
+ /**
585
+ * Processes all queued blocks, adding them to the store.
586
+ * Called at the beginning of each sync iteration.
587
+ * Blocks are processed in the order they were queued.
588
+ */ async processQueuedBlocks() {
589
+ if (this.blockQueue.length === 0) {
590
+ return;
591
+ }
592
+ // Take all blocks from the queue
593
+ const queuedItems = this.blockQueue.splice(0, this.blockQueue.length);
594
+ this.log.debug(`Processing ${queuedItems.length} queued block(s)`);
595
+ // Process each block individually to properly resolve/reject each promise
596
+ for (const { block, resolve, reject } of queuedItems){
597
+ try {
598
+ await this.store.addBlocks([
599
+ block
600
+ ]);
601
+ this.log.debug(`Added block ${block.number} to store`);
602
+ resolve();
603
+ } catch (err) {
604
+ this.log.error(`Failed to add block ${block.number} to store: ${err.message}`);
605
+ reject(err);
606
+ }
607
+ }
608
+ }
180
609
  waitForInitialSync() {
181
610
  return this.initialSyncPromise.promise;
182
611
  }
@@ -193,9 +622,7 @@ function mapArchiverConfig(config) {
193
622
  throw new Error(`Ethereum node is out of sync (last block synced ${number} at ${l1Timestamp} vs current time ${currentTime})`);
194
623
  }
195
624
  }
196
- /**
197
- * Fetches logs from L1 contracts and processes them.
198
- */ async sync() {
625
+ async syncFromL1() {
199
626
  /**
200
627
  * We keep track of three "pointers" to L1 blocks:
201
628
  * 1. the last L1 block that published an L2 block
@@ -269,7 +696,7 @@ function mapArchiverConfig(config) {
269
696
  // past it, since otherwise we'll keep downloading it and reprocessing it on every iteration until
270
697
  // we get a valid checkpoint to advance the syncpoint.
271
698
  if (!rollupStatus.validationResult?.valid && rollupStatus.lastL1BlockWithCheckpoint !== undefined) {
272
- await this.store.setBlockSynchedL1BlockNumber(rollupStatus.lastL1BlockWithCheckpoint);
699
+ await this.store.setCheckpointSynchedL1BlockNumber(rollupStatus.lastL1BlockWithCheckpoint);
273
700
  }
274
701
  // And lastly we check if we are missing any checkpoints behind us due to a possible L1 reorg.
275
702
  // We only do this if rollup cant prune on the next submission. Otherwise we will end up
@@ -298,6 +725,14 @@ function mapArchiverConfig(config) {
298
725
  this.initialSyncPromise.resolve();
299
726
  }
300
727
  }
728
+ /**
729
+ * Fetches logs from L1 contracts and processes them.
730
+ */ async sync() {
731
+ // Process any queued blocks first, before doing L1 sync
732
+ await this.processQueuedBlocks();
733
+ // Now perform L1 sync
734
+ await this.syncFromL1();
735
+ }
301
736
  /** Queries the rollup contract on whether a prune can be executed on the immediate next L1 block. */ async canPrune(currentL1BlockNumber, currentL1Timestamp) {
302
737
  const time = (currentL1Timestamp ?? 0n) + BigInt(this.l1constants.ethereumSlotDuration);
303
738
  const result = await this.rollup.canPruneAtTime(time, {
@@ -326,12 +761,19 @@ function mapArchiverConfig(config) {
326
761
  const pruneFromSlotNumber = header.slotNumber;
327
762
  const pruneFromEpochNumber = getEpochAtSlot(pruneFromSlotNumber, this.l1constants);
328
763
  const checkpointsToUnwind = localPendingCheckpointNumber - provenCheckpointNumber;
329
- const checkpoints = await this.getCheckpoints(pruneFrom, checkpointsToUnwind);
764
+ const checkpointPromises = Array.from({
765
+ length: checkpointsToUnwind
766
+ }).fill(0).map((_, i)=>this.store.getCheckpointData(CheckpointNumber(i + pruneFrom)));
767
+ const checkpoints = await Promise.all(checkpointPromises);
768
+ const blockPromises = await Promise.all(checkpoints.filter(isDefined).map((cp)=>this.store.getBlocksForCheckpoint(CheckpointNumber(cp.checkpointNumber))));
769
+ const newBlocks = blockPromises.filter(isDefined).flat();
770
+ // TODO(pw/mbps): Don't convert to legacy blocks here
771
+ const blocks = (await Promise.all(newBlocks.map((x)=>this.getBlock(x.number)))).filter(isDefined);
330
772
  // Emit an event for listening services to react to the chain prune
331
773
  this.emit(L2BlockSourceEvents.L2PruneDetected, {
332
774
  type: L2BlockSourceEvents.L2PruneDetected,
333
775
  epochNumber: pruneFromEpochNumber,
334
- blocks: checkpoints.flatMap((c)=>L2Block.fromCheckpoint(c))
776
+ blocks
335
777
  });
336
778
  this.log.debug(`L2 prune from ${provenCheckpointNumber + 1} to ${localPendingCheckpointNumber} will occur on next checkpoint submission.`);
337
779
  await this.unwindCheckpoints(localPendingCheckpointNumber, checkpointsToUnwind);
@@ -507,16 +949,14 @@ function mapArchiverConfig(config) {
507
949
  async handleCheckpoints(blocksSynchedTo, currentL1BlockNumber) {
508
950
  const localPendingCheckpointNumber = await this.getSynchedCheckpointNumber();
509
951
  const initialValidationResult = await this.store.getPendingChainValidationStatus();
510
- const [rollupProvenCheckpointNumber, provenArchive, rollupPendingCheckpointNumber, pendingArchive, archiveForLocalPendingCheckpointNumber] = await this.rollup.status(localPendingCheckpointNumber, {
952
+ const { provenCheckpointNumber, provenArchive, pendingCheckpointNumber, pendingArchive, archiveOfMyCheckpoint: archiveForLocalPendingCheckpointNumber } = await this.rollup.status(localPendingCheckpointNumber, {
511
953
  blockNumber: currentL1BlockNumber
512
954
  });
513
- const provenCheckpointNumber = CheckpointNumber.fromBigInt(rollupProvenCheckpointNumber);
514
- const pendingCheckpointNumber = CheckpointNumber.fromBigInt(rollupPendingCheckpointNumber);
515
955
  const rollupStatus = {
516
956
  provenCheckpointNumber,
517
- provenArchive,
957
+ provenArchive: provenArchive.toString(),
518
958
  pendingCheckpointNumber,
519
- pendingArchive,
959
+ pendingArchive: pendingArchive.toString(),
520
960
  validationResult: initialValidationResult
521
961
  };
522
962
  this.log.trace(`Retrieved rollup status at current L1 block ${currentL1BlockNumber}.`, {
@@ -539,16 +979,15 @@ function mapArchiverConfig(config) {
539
979
  });
540
980
  }
541
981
  }
542
- const localCheckpointForDestinationProvenCheckpointNumber = await this.getCheckpoint(provenCheckpointNumber);
982
+ const localCheckpointForDestinationProvenCheckpointNumber = await this.store.getCheckpointData(provenCheckpointNumber);
543
983
  // Sanity check. I've hit what seems to be a state where the proven checkpoint is set to a value greater than the latest
544
984
  // synched checkpoint when requesting L2Tips from the archiver. This is the only place where the proven checkpoint is set.
545
985
  const synched = await this.getSynchedCheckpointNumber();
546
- if (localCheckpointForDestinationProvenCheckpointNumber && synched < localCheckpointForDestinationProvenCheckpointNumber.number) {
547
- this.log.error(`Hit local checkpoint greater than last synched checkpoint: ${localCheckpointForDestinationProvenCheckpointNumber.number} > ${synched}`);
986
+ if (localCheckpointForDestinationProvenCheckpointNumber && synched < localCheckpointForDestinationProvenCheckpointNumber.checkpointNumber) {
987
+ this.log.error(`Hit local checkpoint greater than last synched checkpoint: ${localCheckpointForDestinationProvenCheckpointNumber.checkpointNumber} > ${synched}`);
548
988
  }
549
989
  this.log.trace(`Local checkpoint for remote proven checkpoint ${provenCheckpointNumber} is ${localCheckpointForDestinationProvenCheckpointNumber?.archive.root.toString() ?? 'undefined'}`);
550
- const lastProvenBlockNumber = await this.getLastBlockNumberInCheckpoint(provenCheckpointNumber);
551
- if (localCheckpointForDestinationProvenCheckpointNumber && provenArchive === localCheckpointForDestinationProvenCheckpointNumber.archive.root.toString()) {
990
+ if (localCheckpointForDestinationProvenCheckpointNumber && provenArchive.equals(localCheckpointForDestinationProvenCheckpointNumber.archive.root)) {
552
991
  const localProvenCheckpointNumber = await this.getProvenCheckpointNumber();
553
992
  if (localProvenCheckpointNumber !== provenCheckpointNumber) {
554
993
  await this.setProvenCheckpointNumber(provenCheckpointNumber);
@@ -557,23 +996,24 @@ function mapArchiverConfig(config) {
557
996
  });
558
997
  const provenSlotNumber = localCheckpointForDestinationProvenCheckpointNumber.header.slotNumber;
559
998
  const provenEpochNumber = getEpochAtSlot(provenSlotNumber, this.l1constants);
999
+ const lastBlockNumberInCheckpoint = localCheckpointForDestinationProvenCheckpointNumber.startBlock + localCheckpointForDestinationProvenCheckpointNumber.numBlocks - 1;
560
1000
  this.emit(L2BlockSourceEvents.L2BlockProven, {
561
1001
  type: L2BlockSourceEvents.L2BlockProven,
562
- blockNumber: lastProvenBlockNumber,
1002
+ blockNumber: BlockNumber(lastBlockNumberInCheckpoint),
563
1003
  slotNumber: provenSlotNumber,
564
1004
  epochNumber: provenEpochNumber
565
1005
  });
1006
+ this.instrumentation.updateLastProvenBlock(lastBlockNumberInCheckpoint);
566
1007
  } else {
567
1008
  this.log.trace(`Proven checkpoint ${provenCheckpointNumber} already stored.`);
568
1009
  }
569
1010
  }
570
- this.instrumentation.updateLastProvenBlock(lastProvenBlockNumber);
571
1011
  };
572
1012
  // This is an edge case that we only hit if there are no proposed checkpoints.
573
1013
  // If we have 0 checkpoints locally and there are no checkpoints onchain there is nothing to do.
574
1014
  const noCheckpoints = localPendingCheckpointNumber === 0 && pendingCheckpointNumber === 0;
575
1015
  if (noCheckpoints) {
576
- await this.store.setBlockSynchedL1BlockNumber(currentL1BlockNumber);
1016
+ await this.store.setCheckpointSynchedL1BlockNumber(currentL1BlockNumber);
577
1017
  this.log.debug(`No checkpoints to retrieve from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}, no checkpoints on chain`);
578
1018
  return rollupStatus;
579
1019
  }
@@ -581,12 +1021,12 @@ function mapArchiverConfig(config) {
581
1021
  // Related to the L2 reorgs of the pending chain. We are only interested in actually addressing a reorg if there
582
1022
  // are any state that could be impacted by it. If we have no checkpoints, there is no impact.
583
1023
  if (localPendingCheckpointNumber > 0) {
584
- const localPendingCheckpoint = await this.getCheckpoint(localPendingCheckpointNumber);
1024
+ const localPendingCheckpoint = await this.store.getCheckpointData(localPendingCheckpointNumber);
585
1025
  if (localPendingCheckpoint === undefined) {
586
1026
  throw new Error(`Missing checkpoint ${localPendingCheckpointNumber}`);
587
1027
  }
588
1028
  const localPendingArchiveRoot = localPendingCheckpoint.archive.root.toString();
589
- const noCheckpointSinceLast = localPendingCheckpoint && pendingArchive === localPendingArchiveRoot;
1029
+ const noCheckpointSinceLast = localPendingCheckpoint && pendingArchive.toString() === localPendingArchiveRoot;
590
1030
  if (noCheckpointSinceLast) {
591
1031
  // We believe the following line causes a problem when we encounter L1 re-orgs.
592
1032
  // Basically, by setting the synched L1 block number here, we are saying that we have
@@ -599,7 +1039,7 @@ function mapArchiverConfig(config) {
599
1039
  this.log.debug(`No checkpoints to retrieve from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}`);
600
1040
  return rollupStatus;
601
1041
  }
602
- const localPendingCheckpointInChain = archiveForLocalPendingCheckpointNumber === localPendingArchiveRoot;
1042
+ const localPendingCheckpointInChain = archiveForLocalPendingCheckpointNumber.equals(localPendingCheckpoint.archive.root);
603
1043
  if (!localPendingCheckpointInChain) {
604
1044
  // If our local pending checkpoint tip is not in the chain on L1 a "prune" must have happened
605
1045
  // or the L1 have reorged.
@@ -612,16 +1052,16 @@ function mapArchiverConfig(config) {
612
1052
  });
613
1053
  let tipAfterUnwind = localPendingCheckpointNumber;
614
1054
  while(true){
615
- const candidateCheckpoint = await this.getCheckpoint(tipAfterUnwind);
1055
+ const candidateCheckpoint = await this.store.getCheckpointData(tipAfterUnwind);
616
1056
  if (candidateCheckpoint === undefined) {
617
1057
  break;
618
1058
  }
619
- const archiveAtContract = await this.rollup.archiveAt(candidateCheckpoint.number);
620
- this.log.trace(`Checking local checkpoint ${candidateCheckpoint.number} with archive ${candidateCheckpoint.archive.root}`, {
1059
+ const archiveAtContract = await this.rollup.archiveAt(candidateCheckpoint.checkpointNumber);
1060
+ this.log.trace(`Checking local checkpoint ${candidateCheckpoint.checkpointNumber} with archive ${candidateCheckpoint.archive.root}`, {
621
1061
  archiveAtContract,
622
1062
  archiveLocal: candidateCheckpoint.archive.root.toString()
623
1063
  });
624
- if (archiveAtContract === candidateCheckpoint.archive.root.toString()) {
1064
+ if (archiveAtContract.equals(candidateCheckpoint.archive.root)) {
625
1065
  break;
626
1066
  }
627
1067
  tipAfterUnwind--;
@@ -640,8 +1080,8 @@ function mapArchiverConfig(config) {
640
1080
  do {
641
1081
  [searchStartBlock, searchEndBlock] = this.nextRange(searchEndBlock, currentL1BlockNumber);
642
1082
  this.log.trace(`Retrieving checkpoints from L1 block ${searchStartBlock} to ${searchEndBlock}`);
643
- // TODO(md): Retrieve from blob sink then from consensus client, then from peers
644
- const retrievedCheckpoints = await retrieveCheckpointsFromRollup(this.rollup.getContract(), this.publicClient, this.debugClient, this.blobSinkClient, searchStartBlock, searchEndBlock, this.l1Addresses, this.instrumentation, this.log);
1083
+ // TODO(md): Retrieve from blob client then from consensus client, then from peers
1084
+ const retrievedCheckpoints = await retrieveCheckpointsFromRollup(this.rollup.getContract(), this.publicClient, this.debugClient, this.blobClient, searchStartBlock, searchEndBlock, this.l1Addresses, this.instrumentation, this.log, !this.initialSyncComplete);
645
1085
  if (retrievedCheckpoints.length === 0) {
646
1086
  // We are not calling `setBlockSynchedL1BlockNumber` because it may cause sync issues if based off infura.
647
1087
  // See further details in earlier comments.
@@ -709,15 +1149,14 @@ function mapArchiverConfig(config) {
709
1149
  const [processDuration] = await elapsed(()=>this.addCheckpoints(validCheckpoints, updatedValidationResult));
710
1150
  this.instrumentation.processNewBlocks(processDuration / validCheckpoints.length, validCheckpoints.flatMap((c)=>c.checkpoint.blocks));
711
1151
  } catch (err) {
712
- if (err instanceof InitialBlockNumberNotSequentialError) {
713
- const { previousBlockNumber, newBlockNumber } = err;
714
- const previousBlock = previousBlockNumber ? await this.store.getPublishedBlock(BlockNumber(previousBlockNumber)) : undefined;
715
- const updatedL1SyncPoint = previousBlock?.l1.blockNumber ?? this.l1constants.l1StartBlock;
1152
+ if (err instanceof InitialCheckpointNumberNotSequentialError) {
1153
+ const { previousCheckpointNumber, newCheckpointNumber } = err;
1154
+ const previousCheckpoint = previousCheckpointNumber ? await this.store.getCheckpointData(CheckpointNumber(previousCheckpointNumber)) : undefined;
1155
+ const updatedL1SyncPoint = previousCheckpoint?.l1.blockNumber ?? this.l1constants.l1StartBlock;
716
1156
  await this.store.setBlockSynchedL1BlockNumber(updatedL1SyncPoint);
717
- 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.`, {
718
- previousBlockNumber,
719
- previousBlockHash: await previousBlock?.block.hash(),
720
- newBlockNumber,
1157
+ this.log.warn(`Attempting to insert checkpoint ${newCheckpointNumber} with previous block ${previousCheckpointNumber}. Rolling back L1 sync point to ${updatedL1SyncPoint} to try and fetch the missing blocks.`, {
1158
+ previousCheckpointNumber,
1159
+ newCheckpointNumber,
721
1160
  updatedL1SyncPoint
722
1161
  });
723
1162
  }
@@ -756,9 +1195,16 @@ function mapArchiverConfig(config) {
756
1195
  // We suspect an L1 reorg that added checkpoints *behind* us. If that is the case, it must have happened between
757
1196
  // the last checkpoint we saw and the current one, so we reset the last synched L1 block number. In the edge case
758
1197
  // we don't have one, we go back 2 L1 epochs, which is the deepest possible reorg (assuming Casper is working).
759
- const latestLocalCheckpoint = lastRetrievedCheckpoint ?? (latestLocalCheckpointNumber > 0 ? await this.getPublishedCheckpoints(latestLocalCheckpointNumber, 1).then(([c])=>c) : undefined);
760
- const targetL1BlockNumber = latestLocalCheckpoint?.l1.blockNumber ?? maxBigint(currentL1BlockNumber - 64n, 0n);
761
- const latestLocalCheckpointArchive = latestLocalCheckpoint?.checkpoint.archive.root.toString();
1198
+ let latestLocalCheckpointArchive = undefined;
1199
+ let targetL1BlockNumber = maxBigint(currentL1BlockNumber - 64n, 0n);
1200
+ if (lastRetrievedCheckpoint) {
1201
+ latestLocalCheckpointArchive = lastRetrievedCheckpoint.checkpoint.archive.root.toString();
1202
+ targetL1BlockNumber = lastRetrievedCheckpoint.l1.blockNumber;
1203
+ } else if (latestLocalCheckpointNumber > 0) {
1204
+ const checkpoint = await this.store.getRangeOfCheckpoints(latestLocalCheckpointNumber, 1).then(([c])=>c);
1205
+ latestLocalCheckpointArchive = checkpoint.archive.root.toString();
1206
+ targetL1BlockNumber = checkpoint.l1.blockNumber;
1207
+ }
762
1208
  this.log.warn(`Failed to reach checkpoint ${pendingCheckpointNumber} at ${currentL1BlockNumber} (latest is ${latestLocalCheckpointNumber}). ` + `Rolling back last synched L1 block number to ${targetL1BlockNumber}.`, {
763
1209
  latestLocalCheckpointNumber,
764
1210
  latestLocalCheckpointArchive,
@@ -822,32 +1268,44 @@ function mapArchiverConfig(config) {
822
1268
  async getBlocksForEpoch(epochNumber) {
823
1269
  const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
824
1270
  const blocks = [];
825
- // Walk the list of blocks backwards and filter by slots matching the requested epoch.
826
- // We'll typically ask for blocks for a very recent epoch, so we shouldn't need an index here.
827
- let block = await this.getBlock(await this.store.getSynchedL2BlockNumber());
828
- const slot = (b)=>b.header.globalVariables.slotNumber;
829
- while(block && slot(block) >= start){
830
- if (slot(block) <= end) {
831
- blocks.push(block);
1271
+ // Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
1272
+ // We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
1273
+ let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
1274
+ const slot = (b)=>b.header.slotNumber;
1275
+ while(checkpoint && slot(checkpoint) >= start){
1276
+ if (slot(checkpoint) <= end) {
1277
+ // push the blocks on backwards
1278
+ const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
1279
+ for(let i = endBlock; i >= checkpoint.startBlock; i--){
1280
+ const block = await this.getBlock(BlockNumber(i));
1281
+ if (block) {
1282
+ blocks.push(block);
1283
+ }
1284
+ }
832
1285
  }
833
- block = await this.getBlock(BlockNumber(block.number - 1));
1286
+ checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
834
1287
  }
835
1288
  return blocks.reverse();
836
1289
  }
837
1290
  async getBlockHeadersForEpoch(epochNumber) {
838
1291
  const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
839
1292
  const blocks = [];
840
- // Walk the list of blocks backwards and filter by slots matching the requested epoch.
841
- // We'll typically ask for blocks for a very recent epoch, so we shouldn't need an index here.
842
- let number = await this.store.getSynchedL2BlockNumber();
843
- let header = await this.getBlockHeader(number);
844
- const slot = (b)=>b.globalVariables.slotNumber;
845
- while(header && slot(header) >= start){
846
- if (slot(header) <= end) {
847
- blocks.push(header);
1293
+ // Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
1294
+ // We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
1295
+ let checkpoint = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
1296
+ const slot = (b)=>b.header.slotNumber;
1297
+ while(checkpoint && slot(checkpoint) >= start){
1298
+ if (slot(checkpoint) <= end) {
1299
+ // push the blocks on backwards
1300
+ const endBlock = checkpoint.startBlock + checkpoint.numBlocks - 1;
1301
+ for(let i = endBlock; i >= checkpoint.startBlock; i--){
1302
+ const block = await this.getBlockHeader(BlockNumber(i));
1303
+ if (block) {
1304
+ blocks.push(block);
1305
+ }
1306
+ }
848
1307
  }
849
- number = BlockNumber(number - 1);
850
- header = await this.getBlockHeader(number);
1308
+ checkpoint = await this.store.getCheckpointData(CheckpointNumber(checkpoint.checkpointNumber - 1));
851
1309
  }
852
1310
  return blocks.reverse();
853
1311
  }
@@ -878,29 +1336,6 @@ function mapArchiverConfig(config) {
878
1336
  /** Returns whether the archiver has completed an initial sync run successfully. */ isInitialSyncComplete() {
879
1337
  return this.initialSyncComplete;
880
1338
  }
881
- async getPublishedCheckpoints(from, limit, proven) {
882
- // TODO: Implement this properly. This only works when we have one block per checkpoint.
883
- const blocks = await this.getPublishedBlocks(BlockNumber(from), limit, proven);
884
- return blocks.map((b)=>b.toPublishedCheckpoint());
885
- }
886
- async getCheckpointByArchive(archive) {
887
- // TODO: Implement this properly. This only works when we have one block per checkpoint.
888
- return (await this.getPublishedBlockByArchive(archive))?.block.toCheckpoint();
889
- }
890
- async getCheckpoints(from, limit, proven) {
891
- const published = await this.getPublishedCheckpoints(from, limit, proven);
892
- return published.map((p)=>p.checkpoint);
893
- }
894
- async getCheckpoint(number) {
895
- if (number < 0) {
896
- number = await this.getSynchedCheckpointNumber();
897
- }
898
- if (number === 0) {
899
- return undefined;
900
- }
901
- const published = await this.getPublishedCheckpoints(number, 1);
902
- return published[0]?.checkpoint;
903
- }
904
1339
  async getCheckpointHeader(number) {
905
1340
  if (number === 'latest') {
906
1341
  number = await this.getSynchedCheckpointNumber();
@@ -908,66 +1343,36 @@ function mapArchiverConfig(config) {
908
1343
  if (number === 0) {
909
1344
  return undefined;
910
1345
  }
911
- const checkpoint = await this.getCheckpoint(number);
912
- return checkpoint?.header;
1346
+ const checkpoint = await this.store.getCheckpointData(number);
1347
+ if (!checkpoint) {
1348
+ return undefined;
1349
+ }
1350
+ return checkpoint.header;
913
1351
  }
914
1352
  getCheckpointNumber() {
915
1353
  return this.getSynchedCheckpointNumber();
916
1354
  }
917
- async getSynchedCheckpointNumber() {
918
- // TODO: Create store and apis for checkpoints.
919
- // Checkpoint number will no longer be the same as the block number once we support multiple blocks per checkpoint.
920
- return CheckpointNumber(await this.store.getSynchedL2BlockNumber());
1355
+ getSynchedCheckpointNumber() {
1356
+ return this.store.getSynchedCheckpointNumber();
921
1357
  }
922
- async getProvenCheckpointNumber() {
923
- // TODO: Create store and apis for checkpoints.
924
- // Proven checkpoint number will no longer be the same as the proven block number once we support multiple blocks per checkpoint.
925
- return CheckpointNumber(await this.store.getProvenL2BlockNumber());
1358
+ getProvenCheckpointNumber() {
1359
+ return this.store.getProvenCheckpointNumber();
926
1360
  }
927
1361
  setProvenCheckpointNumber(checkpointNumber) {
928
- // TODO: Create store and apis for checkpoints.
929
- // Proven checkpoint number will no longer be the same as the proven block number once we support multiple blocks per checkpoint.
930
- return this.store.setProvenL2BlockNumber(BlockNumber.fromCheckpointNumber(checkpointNumber));
1362
+ return this.store.setProvenCheckpointNumber(checkpointNumber);
931
1363
  }
932
1364
  unwindCheckpoints(from, checkpointsToUnwind) {
933
- // TODO: Create store and apis for checkpoints.
934
- // This only works when we have one block per checkpoint.
935
- return this.store.unwindBlocks(BlockNumber.fromCheckpointNumber(from), checkpointsToUnwind);
1365
+ return this.store.unwindCheckpoints(from, checkpointsToUnwind);
936
1366
  }
937
- getLastBlockNumberInCheckpoint(checkpointNumber) {
938
- // TODO: Create store and apis for checkpoints.
939
- // Checkpoint number will no longer be the same as the block number once we support multiple blocks per checkpoint.
940
- return Promise.resolve(BlockNumber.fromCheckpointNumber(checkpointNumber));
1367
+ async getLastBlockNumberInCheckpoint(checkpointNumber) {
1368
+ const checkpointData = await this.store.getCheckpointData(checkpointNumber);
1369
+ if (!checkpointData) {
1370
+ return undefined;
1371
+ }
1372
+ return BlockNumber(checkpointData.startBlock + checkpointData.numBlocks - 1);
941
1373
  }
942
1374
  addCheckpoints(checkpoints, pendingChainValidationStatus) {
943
- // TODO: Create store and apis for checkpoints.
944
- // This only works when we have one block per checkpoint.
945
- return this.store.addBlocks(checkpoints.map((p)=>PublishedL2Block.fromPublishedCheckpoint(p)), pendingChainValidationStatus);
946
- }
947
- async getCheckpointsForEpoch(epochNumber) {
948
- // TODO: Create store and apis for checkpoints.
949
- // This only works when we have one block per checkpoint.
950
- const blocks = await this.getBlocksForEpoch(epochNumber);
951
- return blocks.map((b)=>b.toCheckpoint());
952
- }
953
- /**
954
- * Gets up to `limit` amount of L2 blocks starting from `from`.
955
- * @param from - Number of the first block to return (inclusive).
956
- * @param limit - The number of blocks to return.
957
- * @param proven - If true, only return blocks that have been proven.
958
- * @returns The requested L2 blocks.
959
- */ getBlocks(from, limit, proven) {
960
- return this.getPublishedBlocks(from, limit, proven).then((blocks)=>blocks.map((b)=>b.block));
961
- }
962
- /** Equivalent to getBlocks but includes publish data. */ async getPublishedBlocks(from, limit, proven) {
963
- const limitWithProven = proven ? Math.min(limit, Math.max(await this.store.getProvenL2BlockNumber() - from + 1, 0)) : limit;
964
- return limitWithProven === 0 ? [] : await this.store.getPublishedBlocks(from, limitWithProven);
965
- }
966
- getPublishedBlockByHash(blockHash) {
967
- return this.store.getPublishedBlockByHash(blockHash);
968
- }
969
- getPublishedBlockByArchive(archive) {
970
- return this.store.getPublishedBlockByArchive(archive);
1375
+ return this.store.addCheckpoints(checkpoints, pendingChainValidationStatus);
971
1376
  }
972
1377
  getBlockHeaderByHash(blockHash) {
973
1378
  return this.store.getBlockHeaderByHash(blockHash);
@@ -979,7 +1384,7 @@ function mapArchiverConfig(config) {
979
1384
  * Gets an l2 block.
980
1385
  * @param number - The block number to return.
981
1386
  * @returns The requested L2 block.
982
- */ async getBlock(number) {
1387
+ */ async getL2BlockNew(number) {
983
1388
  // If the number provided is -ve, then return the latest block.
984
1389
  if (number < 0) {
985
1390
  number = await this.store.getSynchedL2BlockNumber();
@@ -987,8 +1392,8 @@ function mapArchiverConfig(config) {
987
1392
  if (number === 0) {
988
1393
  return undefined;
989
1394
  }
990
- const publishedBlock = await this.store.getPublishedBlock(number);
991
- return publishedBlock?.block;
1395
+ const publishedBlock = await this.store.store.getBlock(number);
1396
+ return publishedBlock;
992
1397
  }
993
1398
  async getBlockHeader(number) {
994
1399
  if (number === 'latest') {
@@ -1000,19 +1405,29 @@ function mapArchiverConfig(config) {
1000
1405
  const headers = await this.store.getBlockHeaders(number, 1);
1001
1406
  return headers.length === 0 ? undefined : headers[0];
1002
1407
  }
1408
+ getCheckpointedBlock(number) {
1409
+ return this.store.getCheckpointedBlock(number);
1410
+ }
1411
+ getCheckpointedBlockByHash(blockHash) {
1412
+ return this.store.getCheckpointedBlockByHash(blockHash);
1413
+ }
1414
+ getProvenBlockNumber() {
1415
+ return this.store.getProvenBlockNumber();
1416
+ }
1417
+ getCheckpointedBlockByArchive(archive) {
1418
+ return this.store.getCheckpointedBlockByArchive(archive);
1419
+ }
1003
1420
  getTxEffect(txHash) {
1004
1421
  return this.store.getTxEffect(txHash);
1005
1422
  }
1006
1423
  getSettledTxReceipt(txHash) {
1007
1424
  return this.store.getSettledTxReceipt(txHash);
1008
1425
  }
1009
- /**
1010
- * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
1011
- * @param tags - The tags to filter the logs by.
1012
- * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
1013
- * that tag.
1014
- */ getLogsByTags(tags) {
1015
- return this.store.getLogsByTags(tags);
1426
+ getPrivateLogsByTags(tags) {
1427
+ return this.store.getPrivateLogsByTags(tags);
1428
+ }
1429
+ getPublicLogsByTagsFromContract(contractAddress, tags) {
1430
+ return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
1016
1431
  }
1017
1432
  /**
1018
1433
  * Gets public logs based on the provided filter.
@@ -1030,15 +1445,10 @@ function mapArchiverConfig(config) {
1030
1445
  }
1031
1446
  /**
1032
1447
  * Gets the number of the latest L2 block processed by the block source implementation.
1448
+ * This includes both checkpointed and uncheckpointed blocks.
1033
1449
  * @returns The number of the latest L2 block processed by the block source implementation.
1034
1450
  */ getBlockNumber() {
1035
- return this.store.getSynchedL2BlockNumber();
1036
- }
1037
- getProvenBlockNumber() {
1038
- return this.store.getProvenL2BlockNumber();
1039
- }
1040
- /** Forcefully updates the last proven block number. Use for testing. */ setProvenBlockNumber(blockNumber) {
1041
- return this.store.setProvenL2BlockNumber(blockNumber);
1451
+ return this.store.getLatestBlockNumber();
1042
1452
  }
1043
1453
  getContractClass(id) {
1044
1454
  return this.store.getContractClass(id);
@@ -1130,23 +1540,23 @@ function mapArchiverConfig(config) {
1130
1540
  };
1131
1541
  }
1132
1542
  async rollbackTo(targetL2BlockNumber) {
1543
+ // TODO(pw/mbps): This still assumes 1 block per checkpoint
1133
1544
  const currentBlocks = await this.getL2Tips();
1134
1545
  const currentL2Block = currentBlocks.latest.number;
1135
1546
  const currentProvenBlock = currentBlocks.proven.number;
1136
- // const currentFinalizedBlock = currentBlocks.finalized.number;
1137
1547
  if (targetL2BlockNumber >= currentL2Block) {
1138
1548
  throw new Error(`Target L2 block ${targetL2BlockNumber} must be less than current L2 block ${currentL2Block}`);
1139
1549
  }
1140
1550
  const blocksToUnwind = currentL2Block - targetL2BlockNumber;
1141
- const targetL2Block = await this.store.getPublishedBlock(targetL2BlockNumber);
1551
+ const targetL2Block = await this.store.getCheckpointedBlock(targetL2BlockNumber);
1142
1552
  if (!targetL2Block) {
1143
1553
  throw new Error(`Target L2 block ${targetL2BlockNumber} not found`);
1144
1554
  }
1145
1555
  const targetL1BlockNumber = targetL2Block.l1.blockNumber;
1146
1556
  const targetCheckpointNumber = CheckpointNumber.fromBlockNumber(targetL2BlockNumber);
1147
1557
  const targetL1BlockHash = await this.getL1BlockHash(targetL1BlockNumber);
1148
- this.log.info(`Unwinding ${blocksToUnwind} blocks from L2 block ${currentL2Block}`);
1149
- await this.store.unwindBlocks(BlockNumber(currentL2Block), blocksToUnwind);
1558
+ this.log.info(`Unwinding ${blocksToUnwind} checkpoints from L2 block ${currentL2Block}`);
1559
+ await this.store.unwindCheckpoints(CheckpointNumber(currentL2Block), blocksToUnwind);
1150
1560
  this.log.info(`Unwinding L1 to L2 messages to checkpoint ${targetCheckpointNumber}`);
1151
1561
  await this.store.rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber);
1152
1562
  this.log.info(`Setting L1 syncpoints to ${targetL1BlockNumber}`);
@@ -1157,7 +1567,7 @@ function mapArchiverConfig(config) {
1157
1567
  });
1158
1568
  if (targetL2BlockNumber < currentProvenBlock) {
1159
1569
  this.log.info(`Clearing proven L2 block number`);
1160
- await this.store.setProvenL2BlockNumber(BlockNumber.ZERO);
1570
+ await this.store.setProvenCheckpointNumber(CheckpointNumber.ZERO);
1161
1571
  }
1162
1572
  // TODO(palla/reorg): Set the finalized block when we add support for it.
1163
1573
  // if (targetL2BlockNumber < currentFinalizedBlock) {
@@ -1165,10 +1575,104 @@ function mapArchiverConfig(config) {
1165
1575
  // await this.store.setFinalizedL2BlockNumber(0);
1166
1576
  // }
1167
1577
  }
1578
+ async getPublishedCheckpoints(checkpointNumber, limit) {
1579
+ const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
1580
+ const blocks = (await Promise.all(checkpoints.map((ch)=>this.store.getBlocksForCheckpoint(ch.checkpointNumber)))).filter(isDefined);
1581
+ const fullCheckpoints = [];
1582
+ for(let i = 0; i < checkpoints.length; i++){
1583
+ const blocksForCheckpoint = blocks[i];
1584
+ const checkpoint = checkpoints[i];
1585
+ const fullCheckpoint = new Checkpoint(checkpoint.archive, checkpoint.header, blocksForCheckpoint, checkpoint.checkpointNumber);
1586
+ const publishedCheckpoint = new PublishedCheckpoint(fullCheckpoint, checkpoint.l1, checkpoint.attestations.map((x)=>CommitteeAttestation.fromBuffer(x)));
1587
+ fullCheckpoints.push(publishedCheckpoint);
1588
+ }
1589
+ return fullCheckpoints;
1590
+ }
1591
+ async getCheckpointsForEpoch(epochNumber) {
1592
+ const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1constants);
1593
+ const checkpoints = [];
1594
+ // Walk the list of checkpoints backwards and filter by slots matching the requested epoch.
1595
+ // We'll typically ask for checkpoints for a very recent epoch, so we shouldn't need an index here.
1596
+ let checkpointData = await this.store.getCheckpointData(await this.store.getSynchedCheckpointNumber());
1597
+ const slot = (b)=>b.header.slotNumber;
1598
+ while(checkpointData && slot(checkpointData) >= start){
1599
+ if (slot(checkpointData) <= end) {
1600
+ // push the checkpoints on backwards
1601
+ const [checkpoint] = await this.getPublishedCheckpoints(checkpointData.checkpointNumber, 1);
1602
+ checkpoints.push(checkpoint.checkpoint);
1603
+ }
1604
+ checkpointData = await this.store.getCheckpointData(CheckpointNumber(checkpointData.checkpointNumber - 1));
1605
+ }
1606
+ return checkpoints.reverse();
1607
+ }
1608
+ /* Legacy APIs */ async getPublishedBlockByHash(blockHash) {
1609
+ const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
1610
+ return this.buildOldBlockFromCheckpointedBlock(checkpointedBlock);
1611
+ }
1612
+ async getPublishedBlockByArchive(archive) {
1613
+ const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
1614
+ return this.buildOldBlockFromCheckpointedBlock(checkpointedBlock);
1615
+ }
1616
+ /**
1617
+ * Gets up to `limit` amount of L2 blocks starting from `from`.
1618
+ * @param from - Number of the first block to return (inclusive).
1619
+ * @param limit - The number of blocks to return.
1620
+ * @param proven - If true, only return blocks that have been proven.
1621
+ * @returns The requested L2 blocks.
1622
+ */ async getBlocks(from, limit, proven) {
1623
+ const publishedBlocks = await this.getPublishedBlocks(from, limit, proven);
1624
+ return publishedBlocks.map((x)=>x.block);
1625
+ }
1626
+ async getPublishedBlocks(from, limit, proven) {
1627
+ const checkpoints = await this.store.getRangeOfCheckpoints(CheckpointNumber(from), limit);
1628
+ const provenCheckpointNumber = await this.getProvenCheckpointNumber();
1629
+ const blocks = (await Promise.all(checkpoints.map((ch)=>this.store.getBlocksForCheckpoint(ch.checkpointNumber)))).filter(isDefined);
1630
+ const olbBlocks = [];
1631
+ for(let i = 0; i < checkpoints.length; i++){
1632
+ const blockForCheckpoint = blocks[i][0];
1633
+ const checkpoint = checkpoints[i];
1634
+ if (checkpoint.checkpointNumber > provenCheckpointNumber && proven === true) {
1635
+ continue;
1636
+ }
1637
+ const oldCheckpoint = new Checkpoint(blockForCheckpoint.archive, checkpoint.header, [
1638
+ blockForCheckpoint
1639
+ ], checkpoint.checkpointNumber);
1640
+ const oldBlock = L2Block.fromCheckpoint(oldCheckpoint);
1641
+ const publishedBlock = new PublishedL2Block(oldBlock, checkpoint.l1, checkpoint.attestations.map((x)=>CommitteeAttestation.fromBuffer(x)));
1642
+ olbBlocks.push(publishedBlock);
1643
+ }
1644
+ return olbBlocks;
1645
+ }
1646
+ async buildOldBlockFromCheckpointedBlock(checkpointedBlock) {
1647
+ if (!checkpointedBlock) {
1648
+ return undefined;
1649
+ }
1650
+ const checkpoint = await this.store.getCheckpointData(checkpointedBlock.checkpointNumber);
1651
+ if (!checkpoint) {
1652
+ return checkpoint;
1653
+ }
1654
+ const fullCheckpoint = new Checkpoint(checkpointedBlock?.block.archive, checkpoint?.header, [
1655
+ checkpointedBlock.block
1656
+ ], checkpoint.checkpointNumber);
1657
+ const oldBlock = L2Block.fromCheckpoint(fullCheckpoint);
1658
+ const published = new PublishedL2Block(oldBlock, checkpoint.l1, checkpoint.attestations.map((x)=>CommitteeAttestation.fromBuffer(x)));
1659
+ return published;
1660
+ }
1661
+ async getBlock(number) {
1662
+ // If the number provided is -ve, then return the latest block.
1663
+ if (number < 0) {
1664
+ number = await this.store.getSynchedL2BlockNumber();
1665
+ }
1666
+ if (number === 0) {
1667
+ return undefined;
1668
+ }
1669
+ const publishedBlocks = await this.getPublishedBlocks(number, 1);
1670
+ if (publishedBlocks.length === 0) {
1671
+ return undefined;
1672
+ }
1673
+ return publishedBlocks[0].block;
1674
+ }
1168
1675
  }
1169
- _ts_decorate([
1170
- trackSpan('Archiver.sync')
1171
- ], Archiver.prototype, "sync", null);
1172
1676
  var Operation = /*#__PURE__*/ function(Operation) {
1173
1677
  Operation[Operation["Store"] = 0] = "Store";
1174
1678
  Operation[Operation["Delete"] = 1] = "Delete";
@@ -1286,6 +1790,18 @@ var Operation = /*#__PURE__*/ function(Operation) {
1286
1790
  }
1287
1791
  return true;
1288
1792
  }
1793
+ async addBlockDataToDB(block) {
1794
+ const contractClassLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1795
+ // ContractInstancePublished event logs are broadcast in privateLogs.
1796
+ const privateLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1797
+ const publicLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1798
+ return (await Promise.all([
1799
+ this.#updatePublishedContractClasses(contractClassLogs, block.number, 0),
1800
+ this.#updateDeployedContractInstances(privateLogs, block.number, 0),
1801
+ this.#updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, 0),
1802
+ this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.number)
1803
+ ])).every(Boolean);
1804
+ }
1289
1805
  addBlocks(blocks, pendingChainValidationStatus) {
1290
1806
  // Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
1291
1807
  // or if the previous block is not in the store.
@@ -1295,34 +1811,51 @@ var Operation = /*#__PURE__*/ function(Operation) {
1295
1811
  // Update the pending chain validation status if provided
1296
1812
  pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
1297
1813
  // Add any logs emitted during the retrieved blocks
1298
- this.store.addLogs(blocks.map((block)=>block.block)),
1814
+ this.store.addLogs(blocks),
1299
1815
  // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1300
- ...blocks.map(async (block)=>{
1301
- const contractClassLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1302
- // ContractInstancePublished event logs are broadcast in privateLogs.
1303
- const privateLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1304
- const publicLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1305
- return (await Promise.all([
1306
- this.#updatePublishedContractClasses(contractClassLogs, block.block.number, 0),
1307
- this.#updateDeployedContractInstances(privateLogs, block.block.number, 0),
1308
- this.#updateUpdatedContractInstances(publicLogs, block.block.header.globalVariables.timestamp, 0),
1309
- this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.block.number)
1310
- ])).every(Boolean);
1816
+ ...blocks.map((block)=>{
1817
+ return this.addBlockDataToDB(block);
1311
1818
  })
1312
1819
  ]);
1313
1820
  return opResults.every(Boolean);
1314
1821
  });
1315
1822
  }
1316
- async unwindBlocks(from, blocksToUnwind) {
1317
- const last = await this.getSynchedL2BlockNumber();
1823
+ addCheckpoints(checkpoints, pendingChainValidationStatus) {
1824
+ // Add the blocks to the store. Store will throw if the blocks are not in order, there are gaps,
1825
+ // or if the previous block is not in the store.
1826
+ return this.store.transactionAsync(async ()=>{
1827
+ await this.store.addCheckpoints(checkpoints);
1828
+ const allBlocks = checkpoints.flatMap((ch)=>ch.checkpoint.blocks);
1829
+ const opResults = await Promise.all([
1830
+ // Update the pending chain validation status if provided
1831
+ pendingChainValidationStatus && this.store.setPendingChainValidationStatus(pendingChainValidationStatus),
1832
+ // Add any logs emitted during the retrieved blocks
1833
+ this.store.addLogs(allBlocks),
1834
+ // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1835
+ ...allBlocks.map((block)=>{
1836
+ return this.addBlockDataToDB(block);
1837
+ })
1838
+ ]);
1839
+ return opResults.every(Boolean);
1840
+ });
1841
+ }
1842
+ async unwindCheckpoints(from, checkpointsToUnwind) {
1843
+ if (checkpointsToUnwind <= 0) {
1844
+ throw new Error(`Cannot unwind ${checkpointsToUnwind} blocks`);
1845
+ }
1846
+ const last = await this.getSynchedCheckpointNumber();
1318
1847
  if (from != last) {
1319
- throw new Error(`Cannot unwind blocks from block ${from} when the last block is ${last}`);
1848
+ throw new Error(`Cannot unwind checkpoints from checkpoint ${from} when the last checkpoint is ${last}`);
1320
1849
  }
1321
- if (blocksToUnwind <= 0) {
1322
- throw new Error(`Cannot unwind ${blocksToUnwind} blocks`);
1850
+ const blocks = [];
1851
+ const lastCheckpointNumber = from + checkpointsToUnwind - 1;
1852
+ for(let checkpointNumber = from; checkpointNumber <= lastCheckpointNumber; checkpointNumber++){
1853
+ const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpointNumber);
1854
+ if (!blocksForCheckpoint) {
1855
+ continue;
1856
+ }
1857
+ blocks.push(...blocksForCheckpoint);
1323
1858
  }
1324
- // from - blocksToUnwind = the new head, so + 1 for what we need to remove
1325
- const blocks = await this.getPublishedBlocks(BlockNumber(from - blocksToUnwind + 1), blocksToUnwind);
1326
1859
  const opResults = await Promise.all([
1327
1860
  // Prune rolls back to the last proven block, which is by definition valid
1328
1861
  this.store.setPendingChainValidationStatus({
@@ -1330,32 +1863,44 @@ var Operation = /*#__PURE__*/ function(Operation) {
1330
1863
  }),
1331
1864
  // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them
1332
1865
  ...blocks.map(async (block)=>{
1333
- const contractClassLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1866
+ const contractClassLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
1334
1867
  // ContractInstancePublished event logs are broadcast in privateLogs.
1335
- const privateLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1336
- const publicLogs = block.block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1868
+ const privateLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.privateLogs);
1869
+ const publicLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.publicLogs);
1337
1870
  return (await Promise.all([
1338
- this.#updatePublishedContractClasses(contractClassLogs, block.block.number, 1),
1339
- this.#updateDeployedContractInstances(privateLogs, block.block.number, 1),
1340
- this.#updateUpdatedContractInstances(publicLogs, block.block.header.globalVariables.timestamp, 1)
1871
+ this.#updatePublishedContractClasses(contractClassLogs, block.number, 1),
1872
+ this.#updateDeployedContractInstances(privateLogs, block.number, 1),
1873
+ this.#updateUpdatedContractInstances(publicLogs, block.header.globalVariables.timestamp, 1)
1341
1874
  ])).every(Boolean);
1342
1875
  }),
1343
- this.store.deleteLogs(blocks.map((b)=>b.block)),
1344
- this.store.unwindBlocks(from, blocksToUnwind)
1876
+ this.store.deleteLogs(blocks),
1877
+ this.store.unwindCheckpoints(from, checkpointsToUnwind)
1345
1878
  ]);
1346
1879
  return opResults.every(Boolean);
1347
1880
  }
1348
- getPublishedBlocks(from, limit) {
1349
- return this.store.getPublishedBlocks(from, limit);
1881
+ getCheckpointData(checkpointNumber) {
1882
+ return this.store.getCheckpointData(checkpointNumber);
1883
+ }
1884
+ getRangeOfCheckpoints(from, limit) {
1885
+ return this.store.getRangeOfCheckpoints(from, limit);
1886
+ }
1887
+ getCheckpointedL2BlockNumber() {
1888
+ return this.store.getCheckpointedL2BlockNumber();
1889
+ }
1890
+ getSynchedCheckpointNumber() {
1891
+ return this.store.getSynchedCheckpointNumber();
1350
1892
  }
1351
- getPublishedBlock(number) {
1352
- return this.store.getPublishedBlock(number);
1893
+ setCheckpointSynchedL1BlockNumber(l1BlockNumber) {
1894
+ return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
1353
1895
  }
1354
- getPublishedBlockByHash(blockHash) {
1355
- return this.store.getPublishedBlockByHash(blockHash);
1896
+ getCheckpointedBlock(number) {
1897
+ return this.store.getCheckpointedBlock(number);
1356
1898
  }
1357
- getPublishedBlockByArchive(archive) {
1358
- return this.store.getPublishedBlockByArchive(archive);
1899
+ getCheckpointedBlockByHash(blockHash) {
1900
+ return this.store.getCheckpointedBlockByHash(blockHash);
1901
+ }
1902
+ getCheckpointedBlockByArchive(archive) {
1903
+ return this.store.getCheckpointedBlockByArchive(archive);
1359
1904
  }
1360
1905
  getBlockHeaders(from, limit) {
1361
1906
  return this.store.getBlockHeaders(from, limit);
@@ -1366,6 +1911,18 @@ var Operation = /*#__PURE__*/ function(Operation) {
1366
1911
  getBlockHeaderByArchive(archive) {
1367
1912
  return this.store.getBlockHeaderByArchive(archive);
1368
1913
  }
1914
+ getBlockByHash(blockHash) {
1915
+ return this.store.getBlockByHash(blockHash);
1916
+ }
1917
+ getBlockByArchive(archive) {
1918
+ return this.store.getBlockByArchive(archive);
1919
+ }
1920
+ getLatestBlockNumber() {
1921
+ return this.store.getLatestBlockNumber();
1922
+ }
1923
+ getBlocksForCheckpoint(checkpointNumber) {
1924
+ return this.store.getBlocksForCheckpoint(checkpointNumber);
1925
+ }
1369
1926
  getTxEffect(txHash) {
1370
1927
  return this.store.getTxEffect(txHash);
1371
1928
  }
@@ -1381,8 +1938,11 @@ var Operation = /*#__PURE__*/ function(Operation) {
1381
1938
  getL1ToL2MessageIndex(l1ToL2Message) {
1382
1939
  return this.store.getL1ToL2MessageIndex(l1ToL2Message);
1383
1940
  }
1384
- getLogsByTags(tags, logsPerTag) {
1385
- return this.store.getLogsByTags(tags, logsPerTag);
1941
+ getPrivateLogsByTags(tags) {
1942
+ return this.store.getPrivateLogsByTags(tags);
1943
+ }
1944
+ getPublicLogsByTagsFromContract(contractAddress, tags) {
1945
+ return this.store.getPublicLogsByTagsFromContract(contractAddress, tags);
1386
1946
  }
1387
1947
  getPublicLogs(filter) {
1388
1948
  return this.store.getPublicLogs(filter);
@@ -1391,16 +1951,19 @@ var Operation = /*#__PURE__*/ function(Operation) {
1391
1951
  return this.store.getContractClassLogs(filter);
1392
1952
  }
1393
1953
  getSynchedL2BlockNumber() {
1394
- return this.store.getSynchedL2BlockNumber();
1954
+ return this.store.getCheckpointedL2BlockNumber();
1395
1955
  }
1396
- getProvenL2BlockNumber() {
1397
- return this.store.getProvenL2BlockNumber();
1956
+ getProvenCheckpointNumber() {
1957
+ return this.store.getProvenCheckpointNumber();
1398
1958
  }
1399
- setProvenL2BlockNumber(l2BlockNumber) {
1400
- return this.store.setProvenL2BlockNumber(l2BlockNumber);
1959
+ getProvenBlockNumber() {
1960
+ return this.store.getProvenBlockNumber();
1961
+ }
1962
+ setProvenCheckpointNumber(checkpointNumber) {
1963
+ return this.store.setProvenCheckpointNumber(checkpointNumber);
1401
1964
  }
1402
1965
  setBlockSynchedL1BlockNumber(l1BlockNumber) {
1403
- return this.store.setBlockSynchedL1BlockNumber(l1BlockNumber);
1966
+ return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
1404
1967
  }
1405
1968
  setMessageSynchedL1Block(l1Block) {
1406
1969
  return this.store.setMessageSynchedL1Block(l1Block);