@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.
- package/dest/archiver/archiver.d.ts +69 -49
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +777 -214
- package/dest/archiver/archiver_store.d.ts +89 -30
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +1785 -288
- package/dest/archiver/config.d.ts +3 -3
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +2 -2
- package/dest/archiver/errors.d.ts +25 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/errors.js +37 -0
- package/dest/archiver/index.d.ts +2 -2
- package/dest/archiver/index.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.d.ts +49 -17
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +320 -84
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +33 -37
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +60 -35
- package/dest/archiver/kv_archiver_store/log_store.d.ts +14 -11
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +149 -62
- package/dest/archiver/l1/bin/retrieve-calldata.js +5 -3
- package/dest/archiver/l1/calldata_retriever.d.ts +17 -3
- package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -1
- package/dest/archiver/l1/calldata_retriever.js +75 -7
- package/dest/archiver/l1/data_retrieval.d.ts +13 -10
- package/dest/archiver/l1/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/l1/data_retrieval.js +31 -18
- package/dest/archiver/structs/published.d.ts +1 -2
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/factory.d.ts +1 -1
- package/dest/factory.js +1 -1
- package/dest/test/mock_l2_block_source.d.ts +10 -3
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +16 -15
- package/package.json +13 -13
- package/src/archiver/archiver.ts +509 -260
- package/src/archiver/archiver_store.ts +99 -29
- package/src/archiver/archiver_store_test_suite.ts +1831 -274
- package/src/archiver/config.ts +7 -3
- package/src/archiver/errors.ts +64 -0
- package/src/archiver/index.ts +1 -1
- package/src/archiver/kv_archiver_store/block_store.ts +434 -94
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +74 -49
- package/src/archiver/kv_archiver_store/log_store.ts +213 -77
- package/src/archiver/l1/bin/retrieve-calldata.ts +3 -3
- package/src/archiver/l1/calldata_retriever.ts +116 -6
- package/src/archiver/l1/data_retrieval.ts +41 -20
- package/src/archiver/structs/published.ts +0 -1
- package/src/factory.ts +1 -1
- package/src/test/mock_l2_block_source.ts +20 -16
|
@@ -1,9 +1,376 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 {
|
|
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
|
-
|
|
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,
|
|
81
|
-
super(), this.publicClient = publicClient, this.debugClient = debugClient, this.l1Addresses = l1Addresses, this.dataStore = dataStore, this.config = config, this.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
166
|
-
this.log.info(`Starting archiver sync to rollup contract ${this.l1Addresses.rollupAddress.toString()} from L1 block ${blocksSynchedTo} and L2
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
547
|
-
this.log.error(`Hit local checkpoint greater than last synched checkpoint: ${localCheckpointForDestinationProvenCheckpointNumber.
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
620
|
-
this.log.trace(`Checking local checkpoint ${candidateCheckpoint.
|
|
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
|
|
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
|
|
644
|
-
const retrievedCheckpoints = await retrieveCheckpointsFromRollup(this.rollup.getContract(), this.publicClient, this.debugClient, this.
|
|
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
|
|
713
|
-
const {
|
|
714
|
-
const
|
|
715
|
-
const updatedL1SyncPoint =
|
|
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
|
|
718
|
-
|
|
719
|
-
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
|
826
|
-
// We'll typically ask for
|
|
827
|
-
let
|
|
828
|
-
const slot = (b)=>b.header.
|
|
829
|
-
while(
|
|
830
|
-
if (slot(
|
|
831
|
-
blocks
|
|
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
|
-
|
|
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
|
|
841
|
-
// We'll typically ask for
|
|
842
|
-
let
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
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
|
-
|
|
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.
|
|
912
|
-
|
|
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
|
-
|
|
918
|
-
|
|
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
|
-
|
|
923
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
939
|
-
|
|
940
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
991
|
-
return publishedBlock
|
|
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
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
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.
|
|
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.
|
|
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}
|
|
1149
|
-
await this.store.
|
|
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.
|
|
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
|
|
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(
|
|
1301
|
-
|
|
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
|
-
|
|
1317
|
-
|
|
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
|
|
1848
|
+
throw new Error(`Cannot unwind checkpoints from checkpoint ${from} when the last checkpoint is ${last}`);
|
|
1320
1849
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
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.
|
|
1866
|
+
const contractClassLogs = block.body.txEffects.flatMap((txEffect)=>txEffect.contractClassLogs);
|
|
1334
1867
|
// ContractInstancePublished event logs are broadcast in privateLogs.
|
|
1335
|
-
const privateLogs = block.
|
|
1336
|
-
const publicLogs = block.
|
|
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.
|
|
1339
|
-
this.#updateDeployedContractInstances(privateLogs, block.
|
|
1340
|
-
this.#updateUpdatedContractInstances(publicLogs, block.
|
|
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
|
|
1344
|
-
this.store.
|
|
1876
|
+
this.store.deleteLogs(blocks),
|
|
1877
|
+
this.store.unwindCheckpoints(from, checkpointsToUnwind)
|
|
1345
1878
|
]);
|
|
1346
1879
|
return opResults.every(Boolean);
|
|
1347
1880
|
}
|
|
1348
|
-
|
|
1349
|
-
return this.store.
|
|
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
|
-
|
|
1352
|
-
return this.store.
|
|
1893
|
+
setCheckpointSynchedL1BlockNumber(l1BlockNumber) {
|
|
1894
|
+
return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
|
|
1353
1895
|
}
|
|
1354
|
-
|
|
1355
|
-
return this.store.
|
|
1896
|
+
getCheckpointedBlock(number) {
|
|
1897
|
+
return this.store.getCheckpointedBlock(number);
|
|
1356
1898
|
}
|
|
1357
|
-
|
|
1358
|
-
return this.store.
|
|
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
|
-
|
|
1385
|
-
return this.store.
|
|
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.
|
|
1954
|
+
return this.store.getCheckpointedL2BlockNumber();
|
|
1395
1955
|
}
|
|
1396
|
-
|
|
1397
|
-
return this.store.
|
|
1956
|
+
getProvenCheckpointNumber() {
|
|
1957
|
+
return this.store.getProvenCheckpointNumber();
|
|
1398
1958
|
}
|
|
1399
|
-
|
|
1400
|
-
return this.store.
|
|
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.
|
|
1966
|
+
return this.store.setCheckpointSynchedL1BlockNumber(l1BlockNumber);
|
|
1404
1967
|
}
|
|
1405
1968
|
setMessageSynchedL1Block(l1Block) {
|
|
1406
1969
|
return this.store.setMessageSynchedL1Block(l1Block);
|