@aztec/sequencer-client 0.0.1-commit.c7c42ec → 0.0.1-commit.c80b6263
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/client/sequencer-client.d.ts +4 -5
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +1 -1
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -1
- package/dest/global_variable_builder/global_builder.d.ts +4 -4
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +13 -13
- package/dest/index.d.ts +2 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +23 -86
- package/dest/publisher/sequencer-publisher.d.ts +17 -16
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +442 -49
- package/dest/sequencer/checkpoint_proposal_job.d.ts +15 -10
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +568 -41
- package/dest/sequencer/checkpoint_voter.d.ts +3 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +34 -10
- package/dest/sequencer/index.d.ts +1 -3
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +0 -2
- package/dest/sequencer/metrics.d.ts +4 -4
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +48 -129
- package/dest/sequencer/sequencer.d.ts +25 -15
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +486 -42
- package/dest/test/index.d.ts +2 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +23 -11
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +50 -7
- package/dest/test/utils.d.ts +13 -9
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +26 -17
- package/package.json +30 -28
- package/src/client/sequencer-client.ts +4 -5
- package/src/config.ts +5 -0
- package/src/global_variable_builder/global_builder.ts +13 -13
- package/src/index.ts +1 -9
- package/src/publisher/sequencer-publisher-metrics.ts +17 -69
- package/src/publisher/sequencer-publisher.ts +84 -73
- package/src/sequencer/checkpoint_proposal_job.ts +206 -62
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/metrics.ts +48 -138
- package/src/sequencer/sequencer.ts +125 -42
- package/src/test/index.ts +1 -2
- package/src/test/mock_checkpoint_builder.ts +92 -28
- package/src/test/utils.ts +55 -28
- package/dest/sequencer/block_builder.d.ts +0 -26
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -129
- package/dest/sequencer/checkpoint_builder.d.ts +0 -63
- package/dest/sequencer/checkpoint_builder.d.ts.map +0 -1
- package/dest/sequencer/checkpoint_builder.js +0 -131
- package/dest/tx_validator/nullifier_cache.d.ts +0 -14
- package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
- package/dest/tx_validator/nullifier_cache.js +0 -24
- package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -53
- package/src/sequencer/block_builder.ts +0 -217
- package/src/sequencer/checkpoint_builder.ts +0 -217
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -133
|
@@ -63,42 +63,430 @@ function _ts_dispose_resources(env) {
|
|
|
63
63
|
return next();
|
|
64
64
|
})(env);
|
|
65
65
|
}
|
|
66
|
+
function applyDecs2203RFactory() {
|
|
67
|
+
function createAddInitializerMethod(initializers, decoratorFinishedRef) {
|
|
68
|
+
return function addInitializer(initializer) {
|
|
69
|
+
assertNotFinished(decoratorFinishedRef, "addInitializer");
|
|
70
|
+
assertCallable(initializer, "An initializer");
|
|
71
|
+
initializers.push(initializer);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
|
|
75
|
+
var kindStr;
|
|
76
|
+
switch(kind){
|
|
77
|
+
case 1:
|
|
78
|
+
kindStr = "accessor";
|
|
79
|
+
break;
|
|
80
|
+
case 2:
|
|
81
|
+
kindStr = "method";
|
|
82
|
+
break;
|
|
83
|
+
case 3:
|
|
84
|
+
kindStr = "getter";
|
|
85
|
+
break;
|
|
86
|
+
case 4:
|
|
87
|
+
kindStr = "setter";
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
kindStr = "field";
|
|
91
|
+
}
|
|
92
|
+
var ctx = {
|
|
93
|
+
kind: kindStr,
|
|
94
|
+
name: isPrivate ? "#" + name : name,
|
|
95
|
+
static: isStatic,
|
|
96
|
+
private: isPrivate,
|
|
97
|
+
metadata: metadata
|
|
98
|
+
};
|
|
99
|
+
var decoratorFinishedRef = {
|
|
100
|
+
v: false
|
|
101
|
+
};
|
|
102
|
+
ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
|
|
103
|
+
var get, set;
|
|
104
|
+
if (kind === 0) {
|
|
105
|
+
if (isPrivate) {
|
|
106
|
+
get = desc.get;
|
|
107
|
+
set = desc.set;
|
|
108
|
+
} else {
|
|
109
|
+
get = function() {
|
|
110
|
+
return this[name];
|
|
111
|
+
};
|
|
112
|
+
set = function(v) {
|
|
113
|
+
this[name] = v;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
} else if (kind === 2) {
|
|
117
|
+
get = function() {
|
|
118
|
+
return desc.value;
|
|
119
|
+
};
|
|
120
|
+
} else {
|
|
121
|
+
if (kind === 1 || kind === 3) {
|
|
122
|
+
get = function() {
|
|
123
|
+
return desc.get.call(this);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (kind === 1 || kind === 4) {
|
|
127
|
+
set = function(v) {
|
|
128
|
+
desc.set.call(this, v);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
ctx.access = get && set ? {
|
|
133
|
+
get: get,
|
|
134
|
+
set: set
|
|
135
|
+
} : get ? {
|
|
136
|
+
get: get
|
|
137
|
+
} : {
|
|
138
|
+
set: set
|
|
139
|
+
};
|
|
140
|
+
try {
|
|
141
|
+
return dec(value, ctx);
|
|
142
|
+
} finally{
|
|
143
|
+
decoratorFinishedRef.v = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function assertNotFinished(decoratorFinishedRef, fnName) {
|
|
147
|
+
if (decoratorFinishedRef.v) {
|
|
148
|
+
throw new Error("attempted to call " + fnName + " after decoration was finished");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function assertCallable(fn, hint) {
|
|
152
|
+
if (typeof fn !== "function") {
|
|
153
|
+
throw new TypeError(hint + " must be a function");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function assertValidReturnValue(kind, value) {
|
|
157
|
+
var type = typeof value;
|
|
158
|
+
if (kind === 1) {
|
|
159
|
+
if (type !== "object" || value === null) {
|
|
160
|
+
throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
|
|
161
|
+
}
|
|
162
|
+
if (value.get !== undefined) {
|
|
163
|
+
assertCallable(value.get, "accessor.get");
|
|
164
|
+
}
|
|
165
|
+
if (value.set !== undefined) {
|
|
166
|
+
assertCallable(value.set, "accessor.set");
|
|
167
|
+
}
|
|
168
|
+
if (value.init !== undefined) {
|
|
169
|
+
assertCallable(value.init, "accessor.init");
|
|
170
|
+
}
|
|
171
|
+
} else if (type !== "function") {
|
|
172
|
+
var hint;
|
|
173
|
+
if (kind === 0) {
|
|
174
|
+
hint = "field";
|
|
175
|
+
} else if (kind === 10) {
|
|
176
|
+
hint = "class";
|
|
177
|
+
} else {
|
|
178
|
+
hint = "method";
|
|
179
|
+
}
|
|
180
|
+
throw new TypeError(hint + " decorators must return a function or void 0");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
|
|
184
|
+
var decs = decInfo[0];
|
|
185
|
+
var desc, init, value;
|
|
186
|
+
if (isPrivate) {
|
|
187
|
+
if (kind === 0 || kind === 1) {
|
|
188
|
+
desc = {
|
|
189
|
+
get: decInfo[3],
|
|
190
|
+
set: decInfo[4]
|
|
191
|
+
};
|
|
192
|
+
} else if (kind === 3) {
|
|
193
|
+
desc = {
|
|
194
|
+
get: decInfo[3]
|
|
195
|
+
};
|
|
196
|
+
} else if (kind === 4) {
|
|
197
|
+
desc = {
|
|
198
|
+
set: decInfo[3]
|
|
199
|
+
};
|
|
200
|
+
} else {
|
|
201
|
+
desc = {
|
|
202
|
+
value: decInfo[3]
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
} else if (kind !== 0) {
|
|
206
|
+
desc = Object.getOwnPropertyDescriptor(base, name);
|
|
207
|
+
}
|
|
208
|
+
if (kind === 1) {
|
|
209
|
+
value = {
|
|
210
|
+
get: desc.get,
|
|
211
|
+
set: desc.set
|
|
212
|
+
};
|
|
213
|
+
} else if (kind === 2) {
|
|
214
|
+
value = desc.value;
|
|
215
|
+
} else if (kind === 3) {
|
|
216
|
+
value = desc.get;
|
|
217
|
+
} else if (kind === 4) {
|
|
218
|
+
value = desc.set;
|
|
219
|
+
}
|
|
220
|
+
var newValue, get, set;
|
|
221
|
+
if (typeof decs === "function") {
|
|
222
|
+
newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
|
|
223
|
+
if (newValue !== void 0) {
|
|
224
|
+
assertValidReturnValue(kind, newValue);
|
|
225
|
+
if (kind === 0) {
|
|
226
|
+
init = newValue;
|
|
227
|
+
} else if (kind === 1) {
|
|
228
|
+
init = newValue.init;
|
|
229
|
+
get = newValue.get || value.get;
|
|
230
|
+
set = newValue.set || value.set;
|
|
231
|
+
value = {
|
|
232
|
+
get: get,
|
|
233
|
+
set: set
|
|
234
|
+
};
|
|
235
|
+
} else {
|
|
236
|
+
value = newValue;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
for(var i = decs.length - 1; i >= 0; i--){
|
|
241
|
+
var dec = decs[i];
|
|
242
|
+
newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
|
|
243
|
+
if (newValue !== void 0) {
|
|
244
|
+
assertValidReturnValue(kind, newValue);
|
|
245
|
+
var newInit;
|
|
246
|
+
if (kind === 0) {
|
|
247
|
+
newInit = newValue;
|
|
248
|
+
} else if (kind === 1) {
|
|
249
|
+
newInit = newValue.init;
|
|
250
|
+
get = newValue.get || value.get;
|
|
251
|
+
set = newValue.set || value.set;
|
|
252
|
+
value = {
|
|
253
|
+
get: get,
|
|
254
|
+
set: set
|
|
255
|
+
};
|
|
256
|
+
} else {
|
|
257
|
+
value = newValue;
|
|
258
|
+
}
|
|
259
|
+
if (newInit !== void 0) {
|
|
260
|
+
if (init === void 0) {
|
|
261
|
+
init = newInit;
|
|
262
|
+
} else if (typeof init === "function") {
|
|
263
|
+
init = [
|
|
264
|
+
init,
|
|
265
|
+
newInit
|
|
266
|
+
];
|
|
267
|
+
} else {
|
|
268
|
+
init.push(newInit);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (kind === 0 || kind === 1) {
|
|
275
|
+
if (init === void 0) {
|
|
276
|
+
init = function(instance, init) {
|
|
277
|
+
return init;
|
|
278
|
+
};
|
|
279
|
+
} else if (typeof init !== "function") {
|
|
280
|
+
var ownInitializers = init;
|
|
281
|
+
init = function(instance, init) {
|
|
282
|
+
var value = init;
|
|
283
|
+
for(var i = 0; i < ownInitializers.length; i++){
|
|
284
|
+
value = ownInitializers[i].call(instance, value);
|
|
285
|
+
}
|
|
286
|
+
return value;
|
|
287
|
+
};
|
|
288
|
+
} else {
|
|
289
|
+
var originalInitializer = init;
|
|
290
|
+
init = function(instance, init) {
|
|
291
|
+
return originalInitializer.call(instance, init);
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
ret.push(init);
|
|
295
|
+
}
|
|
296
|
+
if (kind !== 0) {
|
|
297
|
+
if (kind === 1) {
|
|
298
|
+
desc.get = value.get;
|
|
299
|
+
desc.set = value.set;
|
|
300
|
+
} else if (kind === 2) {
|
|
301
|
+
desc.value = value;
|
|
302
|
+
} else if (kind === 3) {
|
|
303
|
+
desc.get = value;
|
|
304
|
+
} else if (kind === 4) {
|
|
305
|
+
desc.set = value;
|
|
306
|
+
}
|
|
307
|
+
if (isPrivate) {
|
|
308
|
+
if (kind === 1) {
|
|
309
|
+
ret.push(function(instance, args) {
|
|
310
|
+
return value.get.call(instance, args);
|
|
311
|
+
});
|
|
312
|
+
ret.push(function(instance, args) {
|
|
313
|
+
return value.set.call(instance, args);
|
|
314
|
+
});
|
|
315
|
+
} else if (kind === 2) {
|
|
316
|
+
ret.push(value);
|
|
317
|
+
} else {
|
|
318
|
+
ret.push(function(instance, args) {
|
|
319
|
+
return value.call(instance, args);
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
Object.defineProperty(base, name, desc);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function applyMemberDecs(Class, decInfos, metadata) {
|
|
328
|
+
var ret = [];
|
|
329
|
+
var protoInitializers;
|
|
330
|
+
var staticInitializers;
|
|
331
|
+
var existingProtoNonFields = new Map();
|
|
332
|
+
var existingStaticNonFields = new Map();
|
|
333
|
+
for(var i = 0; i < decInfos.length; i++){
|
|
334
|
+
var decInfo = decInfos[i];
|
|
335
|
+
if (!Array.isArray(decInfo)) continue;
|
|
336
|
+
var kind = decInfo[1];
|
|
337
|
+
var name = decInfo[2];
|
|
338
|
+
var isPrivate = decInfo.length > 3;
|
|
339
|
+
var isStatic = kind >= 5;
|
|
340
|
+
var base;
|
|
341
|
+
var initializers;
|
|
342
|
+
if (isStatic) {
|
|
343
|
+
base = Class;
|
|
344
|
+
kind = kind - 5;
|
|
345
|
+
staticInitializers = staticInitializers || [];
|
|
346
|
+
initializers = staticInitializers;
|
|
347
|
+
} else {
|
|
348
|
+
base = Class.prototype;
|
|
349
|
+
protoInitializers = protoInitializers || [];
|
|
350
|
+
initializers = protoInitializers;
|
|
351
|
+
}
|
|
352
|
+
if (kind !== 0 && !isPrivate) {
|
|
353
|
+
var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
|
|
354
|
+
var existingKind = existingNonFields.get(name) || 0;
|
|
355
|
+
if (existingKind === true || existingKind === 3 && kind !== 4 || existingKind === 4 && kind !== 3) {
|
|
356
|
+
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);
|
|
357
|
+
} else if (!existingKind && kind > 2) {
|
|
358
|
+
existingNonFields.set(name, kind);
|
|
359
|
+
} else {
|
|
360
|
+
existingNonFields.set(name, true);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
|
|
364
|
+
}
|
|
365
|
+
pushInitializers(ret, protoInitializers);
|
|
366
|
+
pushInitializers(ret, staticInitializers);
|
|
367
|
+
return ret;
|
|
368
|
+
}
|
|
369
|
+
function pushInitializers(ret, initializers) {
|
|
370
|
+
if (initializers) {
|
|
371
|
+
ret.push(function(instance) {
|
|
372
|
+
for(var i = 0; i < initializers.length; i++){
|
|
373
|
+
initializers[i].call(instance);
|
|
374
|
+
}
|
|
375
|
+
return instance;
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function applyClassDecs(targetClass, classDecs, metadata) {
|
|
380
|
+
if (classDecs.length > 0) {
|
|
381
|
+
var initializers = [];
|
|
382
|
+
var newClass = targetClass;
|
|
383
|
+
var name = targetClass.name;
|
|
384
|
+
for(var i = classDecs.length - 1; i >= 0; i--){
|
|
385
|
+
var decoratorFinishedRef = {
|
|
386
|
+
v: false
|
|
387
|
+
};
|
|
388
|
+
try {
|
|
389
|
+
var nextNewClass = classDecs[i](newClass, {
|
|
390
|
+
kind: "class",
|
|
391
|
+
name: name,
|
|
392
|
+
addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
|
|
393
|
+
metadata
|
|
394
|
+
});
|
|
395
|
+
} finally{
|
|
396
|
+
decoratorFinishedRef.v = true;
|
|
397
|
+
}
|
|
398
|
+
if (nextNewClass !== undefined) {
|
|
399
|
+
assertValidReturnValue(10, nextNewClass);
|
|
400
|
+
newClass = nextNewClass;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return [
|
|
404
|
+
defineMetadata(newClass, metadata),
|
|
405
|
+
function() {
|
|
406
|
+
for(var i = 0; i < initializers.length; i++){
|
|
407
|
+
initializers[i].call(newClass);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
];
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function defineMetadata(Class, metadata) {
|
|
414
|
+
return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
|
|
415
|
+
configurable: true,
|
|
416
|
+
enumerable: true,
|
|
417
|
+
value: metadata
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
|
|
421
|
+
if (parentClass !== void 0) {
|
|
422
|
+
var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
|
|
423
|
+
}
|
|
424
|
+
var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata);
|
|
425
|
+
var e = applyMemberDecs(targetClass, memberDecs, metadata);
|
|
426
|
+
if (!classDecs.length) defineMetadata(targetClass, metadata);
|
|
427
|
+
return {
|
|
428
|
+
e: e,
|
|
429
|
+
get c () {
|
|
430
|
+
return applyClassDecs(targetClass, classDecs, metadata);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
436
|
+
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
437
|
+
}
|
|
438
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _initProto;
|
|
439
|
+
import { NUM_CHECKPOINT_END_MARKER_FIELDS, getNumBlockEndBlobFields } from '@aztec/blob-lib/encoding';
|
|
66
440
|
import { BLOBS_PER_CHECKPOINT, FIELDS_PER_BLOB } from '@aztec/constants';
|
|
67
441
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
68
442
|
import { randomInt } from '@aztec/foundation/crypto/random';
|
|
69
443
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
70
444
|
import { filter } from '@aztec/foundation/iterator';
|
|
445
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
71
446
|
import { sleep, sleepUntil } from '@aztec/foundation/sleep';
|
|
72
447
|
import { Timer } from '@aztec/foundation/timer';
|
|
73
448
|
import { unfreeze } from '@aztec/foundation/types';
|
|
74
449
|
import { CommitteeAttestationsAndSigners, MaliciousCommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
75
450
|
import { getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
76
451
|
import { Gas } from '@aztec/stdlib/gas';
|
|
452
|
+
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
77
453
|
import { orderAttestations } from '@aztec/stdlib/p2p';
|
|
78
454
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
455
|
+
import { Attributes, trackSpan } from '@aztec/telemetry-client';
|
|
456
|
+
import { DutyAlreadySignedError, SlashingProtectionError } from '@aztec/validator-ha-signer/errors';
|
|
79
457
|
import { CheckpointVoter } from './checkpoint_voter.js';
|
|
80
458
|
import { SequencerInterruptedError } from './errors.js';
|
|
81
459
|
import { SequencerState } from './utils.js';
|
|
82
460
|
/** How much time to sleep while waiting for min transactions to accumulate for a block */ const TXS_POLLING_MS = 500;
|
|
461
|
+
_dec = trackSpan('CheckpointProposalJob.execute'), _dec1 = trackSpan('CheckpointProposalJob.proposeCheckpoint', function() {
|
|
462
|
+
return {
|
|
463
|
+
// nullish operator needed for tests
|
|
464
|
+
[Attributes.COINBASE]: this.validatorClient.getCoinbaseForAttestor(this.attestorAddress)?.toString(),
|
|
465
|
+
[Attributes.SLOT_NUMBER]: this.slot
|
|
466
|
+
};
|
|
467
|
+
}), _dec2 = trackSpan('CheckpointProposalJob.buildBlocksForCheckpoint'), _dec3 = trackSpan('CheckpointProposalJob.waitUntilNextSubslot'), _dec4 = trackSpan('CheckpointProposalJob.buildSingleBlock'), _dec5 = trackSpan('CheckpointProposalJob.waitForMinTxs'), _dec6 = trackSpan('CheckpointProposalJob.waitForAttestations'), _dec7 = trackSpan('CheckpointProposalJob.waitUntilTimeInSlot');
|
|
83
468
|
/**
|
|
84
469
|
* Handles the execution of a checkpoint proposal after the initial preparation phase.
|
|
85
470
|
* This includes building blocks, collecting attestations, and publishing the checkpoint to L1,
|
|
86
471
|
* as well as enqueueing votes for slashing and governance proposals. This class is created from
|
|
87
472
|
* the Sequencer once the check for being the proposer for the slot has succeeded.
|
|
88
473
|
*/ export class CheckpointProposalJob {
|
|
474
|
+
epoch;
|
|
89
475
|
slot;
|
|
90
476
|
checkpointNumber;
|
|
91
477
|
syncedToBlockNumber;
|
|
92
478
|
proposer;
|
|
93
479
|
publisher;
|
|
94
480
|
attestorAddress;
|
|
95
|
-
|
|
481
|
+
invalidateCheckpoint;
|
|
96
482
|
validatorClient;
|
|
97
483
|
globalsBuilder;
|
|
98
484
|
p2pClient;
|
|
99
485
|
worldState;
|
|
100
486
|
l1ToL2MessageSource;
|
|
487
|
+
l2BlockSource;
|
|
101
488
|
checkpointsBuilder;
|
|
489
|
+
blockSink;
|
|
102
490
|
l1Constants;
|
|
103
491
|
config;
|
|
104
492
|
timetable;
|
|
@@ -108,22 +496,70 @@ import { SequencerState } from './utils.js';
|
|
|
108
496
|
metrics;
|
|
109
497
|
eventEmitter;
|
|
110
498
|
setStateFn;
|
|
499
|
+
tracer;
|
|
500
|
+
static{
|
|
501
|
+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
502
|
+
[
|
|
503
|
+
_dec,
|
|
504
|
+
2,
|
|
505
|
+
"execute"
|
|
506
|
+
],
|
|
507
|
+
[
|
|
508
|
+
_dec1,
|
|
509
|
+
2,
|
|
510
|
+
"proposeCheckpoint"
|
|
511
|
+
],
|
|
512
|
+
[
|
|
513
|
+
_dec2,
|
|
514
|
+
2,
|
|
515
|
+
"buildBlocksForCheckpoint"
|
|
516
|
+
],
|
|
517
|
+
[
|
|
518
|
+
_dec3,
|
|
519
|
+
2,
|
|
520
|
+
"waitUntilNextSubslot"
|
|
521
|
+
],
|
|
522
|
+
[
|
|
523
|
+
_dec4,
|
|
524
|
+
2,
|
|
525
|
+
"buildSingleBlock"
|
|
526
|
+
],
|
|
527
|
+
[
|
|
528
|
+
_dec5,
|
|
529
|
+
2,
|
|
530
|
+
"waitForMinTxs"
|
|
531
|
+
],
|
|
532
|
+
[
|
|
533
|
+
_dec6,
|
|
534
|
+
2,
|
|
535
|
+
"waitForAttestations"
|
|
536
|
+
],
|
|
537
|
+
[
|
|
538
|
+
_dec7,
|
|
539
|
+
2,
|
|
540
|
+
"waitUntilTimeInSlot"
|
|
541
|
+
]
|
|
542
|
+
], []));
|
|
543
|
+
}
|
|
111
544
|
log;
|
|
112
|
-
constructor(slot, checkpointNumber, syncedToBlockNumber, // TODO(palla/mbps): Can we remove the proposer in favor of attestorAddress? Need to check fisherman-node flows.
|
|
113
|
-
proposer, publisher, attestorAddress,
|
|
545
|
+
constructor(epoch, slot, checkpointNumber, syncedToBlockNumber, // TODO(palla/mbps): Can we remove the proposer in favor of attestorAddress? Need to check fisherman-node flows.
|
|
546
|
+
proposer, publisher, attestorAddress, invalidateCheckpoint, validatorClient, globalsBuilder, p2pClient, worldState, l1ToL2MessageSource, l2BlockSource, checkpointsBuilder, blockSink, l1Constants, config, timetable, slasherClient, epochCache, dateProvider, metrics, eventEmitter, setStateFn, tracer, bindings){
|
|
547
|
+
this.epoch = epoch;
|
|
114
548
|
this.slot = slot;
|
|
115
549
|
this.checkpointNumber = checkpointNumber;
|
|
116
550
|
this.syncedToBlockNumber = syncedToBlockNumber;
|
|
117
551
|
this.proposer = proposer;
|
|
118
552
|
this.publisher = publisher;
|
|
119
553
|
this.attestorAddress = attestorAddress;
|
|
120
|
-
this.
|
|
554
|
+
this.invalidateCheckpoint = invalidateCheckpoint;
|
|
121
555
|
this.validatorClient = validatorClient;
|
|
122
556
|
this.globalsBuilder = globalsBuilder;
|
|
123
557
|
this.p2pClient = p2pClient;
|
|
124
558
|
this.worldState = worldState;
|
|
125
559
|
this.l1ToL2MessageSource = l1ToL2MessageSource;
|
|
560
|
+
this.l2BlockSource = l2BlockSource;
|
|
126
561
|
this.checkpointsBuilder = checkpointsBuilder;
|
|
562
|
+
this.blockSink = blockSink;
|
|
127
563
|
this.l1Constants = l1Constants;
|
|
128
564
|
this.config = config;
|
|
129
565
|
this.timetable = timetable;
|
|
@@ -133,7 +569,12 @@ import { SequencerState } from './utils.js';
|
|
|
133
569
|
this.metrics = metrics;
|
|
134
570
|
this.eventEmitter = eventEmitter;
|
|
135
571
|
this.setStateFn = setStateFn;
|
|
136
|
-
this.
|
|
572
|
+
this.tracer = tracer;
|
|
573
|
+
_initProto(this);
|
|
574
|
+
this.log = createLogger('sequencer:checkpoint-proposal', {
|
|
575
|
+
...bindings,
|
|
576
|
+
instanceId: `slot-${slot}`
|
|
577
|
+
});
|
|
137
578
|
}
|
|
138
579
|
/**
|
|
139
580
|
* Executes the checkpoint proposal job.
|
|
@@ -188,26 +629,60 @@ import { SequencerState } from './utils.js';
|
|
|
188
629
|
// Start the checkpoint
|
|
189
630
|
this.setStateFn(SequencerState.INITIALIZING_CHECKPOINT, this.slot);
|
|
190
631
|
this.metrics.incOpenSlot(this.slot, this.proposer?.toString() ?? 'unknown');
|
|
191
|
-
// Enqueues
|
|
192
|
-
if (this.
|
|
193
|
-
this.publisher.
|
|
632
|
+
// Enqueues checkpoint invalidation (constant for the whole slot)
|
|
633
|
+
if (this.invalidateCheckpoint && !this.config.skipInvalidateBlockAsProposer) {
|
|
634
|
+
this.publisher.enqueueInvalidateCheckpoint(this.invalidateCheckpoint);
|
|
194
635
|
}
|
|
195
636
|
// Create checkpoint builder for the slot
|
|
196
637
|
const checkpointGlobalVariables = await this.globalsBuilder.buildCheckpointGlobalVariables(coinbase, feeRecipient, this.slot);
|
|
197
|
-
// Collect L1 to L2 messages for the checkpoint
|
|
638
|
+
// Collect L1 to L2 messages for the checkpoint and compute their hash
|
|
198
639
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(this.checkpointNumber);
|
|
640
|
+
const inHash = computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
641
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
642
|
+
const previousCheckpoints = (await this.l2BlockSource.getCheckpointsForEpoch(this.epoch)).filter((c)=>c.number < this.checkpointNumber);
|
|
643
|
+
const previousCheckpointOutHashes = previousCheckpoints.map((c)=>c.getCheckpointOutHash());
|
|
199
644
|
const fork = _ts_add_disposable_resource(env, await this.worldState.fork(this.syncedToBlockNumber, {
|
|
200
645
|
closeDelayMs: 12_000
|
|
201
646
|
}), false);
|
|
202
647
|
// Create checkpoint builder for the entire slot
|
|
203
|
-
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(this.checkpointNumber, checkpointGlobalVariables, l1ToL2Messages, fork);
|
|
648
|
+
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(this.checkpointNumber, checkpointGlobalVariables, l1ToL2Messages, previousCheckpointOutHashes, fork, this.log.getBindings());
|
|
204
649
|
// Options for the validator client when creating block and checkpoint proposals
|
|
205
650
|
const blockProposalOptions = {
|
|
206
651
|
publishFullTxs: !!this.config.publishTxsWithProposals,
|
|
207
652
|
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal
|
|
208
653
|
};
|
|
209
|
-
|
|
210
|
-
|
|
654
|
+
const checkpointProposalOptions = {
|
|
655
|
+
publishFullTxs: !!this.config.publishTxsWithProposals,
|
|
656
|
+
broadcastInvalidCheckpointProposal: this.config.broadcastInvalidBlockProposal
|
|
657
|
+
};
|
|
658
|
+
let blocksInCheckpoint = [];
|
|
659
|
+
let blockPendingBroadcast = undefined;
|
|
660
|
+
try {
|
|
661
|
+
// Main loop: build blocks for the checkpoint
|
|
662
|
+
const result = await this.buildBlocksForCheckpoint(checkpointBuilder, checkpointGlobalVariables.timestamp, inHash, blockProposalOptions);
|
|
663
|
+
blocksInCheckpoint = result.blocksInCheckpoint;
|
|
664
|
+
blockPendingBroadcast = result.blockPendingBroadcast;
|
|
665
|
+
} catch (err) {
|
|
666
|
+
// These errors are expected in HA mode, so we yield and let another HA node handle the slot
|
|
667
|
+
// The only distinction between the 2 errors is SlashingProtectionError throws when the payload is different,
|
|
668
|
+
// which is normal for block building (may have picked different txs)
|
|
669
|
+
if (err instanceof DutyAlreadySignedError) {
|
|
670
|
+
this.log.info(`Checkpoint proposal for slot ${this.slot} already signed by another HA node, yielding`, {
|
|
671
|
+
slot: this.slot,
|
|
672
|
+
signedByNode: err.signedByNode
|
|
673
|
+
});
|
|
674
|
+
return undefined;
|
|
675
|
+
}
|
|
676
|
+
if (err instanceof SlashingProtectionError) {
|
|
677
|
+
this.log.info(`Checkpoint proposal for slot ${this.slot} blocked by slashing protection, yielding`, {
|
|
678
|
+
slot: this.slot,
|
|
679
|
+
existingMessageHash: err.existingMessageHash,
|
|
680
|
+
attemptedMessageHash: err.attemptedMessageHash
|
|
681
|
+
});
|
|
682
|
+
return undefined;
|
|
683
|
+
}
|
|
684
|
+
throw err;
|
|
685
|
+
}
|
|
211
686
|
if (blocksInCheckpoint.length === 0) {
|
|
212
687
|
this.log.warn(`No blocks were built for slot ${this.slot}`, {
|
|
213
688
|
slot: this.slot
|
|
@@ -231,17 +706,45 @@ import { SequencerState } from './utils.js';
|
|
|
231
706
|
this.metrics.recordCheckpointSuccess();
|
|
232
707
|
return checkpoint;
|
|
233
708
|
}
|
|
234
|
-
//
|
|
235
|
-
const
|
|
709
|
+
// Include the block pending broadcast in the checkpoint proposal if any
|
|
710
|
+
const lastBlock = blockPendingBroadcast && {
|
|
711
|
+
blockHeader: blockPendingBroadcast.block.header,
|
|
712
|
+
indexWithinCheckpoint: blockPendingBroadcast.block.indexWithinCheckpoint,
|
|
713
|
+
txs: blockPendingBroadcast.txs
|
|
714
|
+
};
|
|
715
|
+
// Create the checkpoint proposal and broadcast it
|
|
716
|
+
const proposal = await this.validatorClient.createCheckpointProposal(checkpoint.header, checkpoint.archive.root, lastBlock, this.proposer, checkpointProposalOptions);
|
|
236
717
|
const blockProposedAt = this.dateProvider.now();
|
|
237
|
-
await this.p2pClient.
|
|
718
|
+
await this.p2pClient.broadcastCheckpointProposal(proposal);
|
|
238
719
|
this.setStateFn(SequencerState.COLLECTING_ATTESTATIONS, this.slot);
|
|
239
720
|
const attestations = await this.waitForAttestations(proposal);
|
|
240
721
|
const blockAttestedAt = this.dateProvider.now();
|
|
241
|
-
this.metrics.
|
|
722
|
+
this.metrics.recordCheckpointAttestationDelay(blockAttestedAt - blockProposedAt);
|
|
242
723
|
// Proposer must sign over the attestations before pushing them to L1
|
|
243
724
|
const signer = this.proposer ?? this.publisher.getSenderAddress();
|
|
244
|
-
|
|
725
|
+
let attestationsSignature;
|
|
726
|
+
try {
|
|
727
|
+
attestationsSignature = await this.validatorClient.signAttestationsAndSigners(attestations, signer, this.slot, this.checkpointNumber);
|
|
728
|
+
} catch (err) {
|
|
729
|
+
// We shouldn't really get here since we yield to another HA node
|
|
730
|
+
// as soon as we see these errors when creating block proposals.
|
|
731
|
+
if (err instanceof DutyAlreadySignedError) {
|
|
732
|
+
this.log.info(`Attestations signature for slot ${this.slot} already signed by another HA node, yielding`, {
|
|
733
|
+
slot: this.slot,
|
|
734
|
+
signedByNode: err.signedByNode
|
|
735
|
+
});
|
|
736
|
+
return undefined;
|
|
737
|
+
}
|
|
738
|
+
if (err instanceof SlashingProtectionError) {
|
|
739
|
+
this.log.info(`Attestations signature for slot ${this.slot} blocked by slashing protection, yielding`, {
|
|
740
|
+
slot: this.slot,
|
|
741
|
+
existingMessageHash: err.existingMessageHash,
|
|
742
|
+
attemptedMessageHash: err.attemptedMessageHash
|
|
743
|
+
});
|
|
744
|
+
return undefined;
|
|
745
|
+
}
|
|
746
|
+
throw err;
|
|
747
|
+
}
|
|
245
748
|
// Enqueue publishing the checkpoint to L1
|
|
246
749
|
this.setStateFn(SequencerState.PUBLISHING_CHECKPOINT, this.slot);
|
|
247
750
|
const aztecSlotDuration = this.l1Constants.slotDuration;
|
|
@@ -249,7 +752,7 @@ import { SequencerState } from './utils.js';
|
|
|
249
752
|
const txTimeoutAt = new Date((slotStartBuildTimestamp + aztecSlotDuration) * 1000);
|
|
250
753
|
await this.publisher.enqueueProposeCheckpoint(checkpoint, attestations, attestationsSignature, {
|
|
251
754
|
txTimeoutAt,
|
|
252
|
-
|
|
755
|
+
forcePendingCheckpointNumber: this.invalidateCheckpoint?.forcePendingCheckpointNumber
|
|
253
756
|
});
|
|
254
757
|
return checkpoint;
|
|
255
758
|
} catch (e) {
|
|
@@ -259,18 +762,24 @@ import { SequencerState } from './utils.js';
|
|
|
259
762
|
_ts_dispose_resources(env);
|
|
260
763
|
}
|
|
261
764
|
} catch (err) {
|
|
765
|
+
if (err && (err instanceof DutyAlreadySignedError || err instanceof SlashingProtectionError)) {
|
|
766
|
+
// swallow this error. It's already been logged by a function deeper in the stack
|
|
767
|
+
return undefined;
|
|
768
|
+
}
|
|
262
769
|
this.log.error(`Error building checkpoint at slot ${this.slot}`, err);
|
|
263
770
|
return undefined;
|
|
264
771
|
}
|
|
265
772
|
}
|
|
266
773
|
/**
|
|
267
774
|
* Builds blocks for a checkpoint within the current slot.
|
|
268
|
-
*/ async buildBlocksForCheckpoint(checkpointBuilder, timestamp, blockProposalOptions) {
|
|
775
|
+
*/ async buildBlocksForCheckpoint(checkpointBuilder, timestamp, inHash, blockProposalOptions) {
|
|
269
776
|
const blocksInCheckpoint = [];
|
|
270
777
|
const txHashesAlreadyIncluded = new Set();
|
|
271
778
|
const initialBlockNumber = BlockNumber(this.syncedToBlockNumber + 1);
|
|
779
|
+
// Remaining blob fields available for blocks (checkpoint end marker already subtracted)
|
|
780
|
+
let remainingBlobFields = BLOBS_PER_CHECKPOINT * FIELDS_PER_BLOB - NUM_CHECKPOINT_END_MARKER_FIELDS;
|
|
272
781
|
// Last block in the checkpoint will usually be flagged as pending broadcast, so we send it along with the checkpoint proposal
|
|
273
|
-
let
|
|
782
|
+
let blockPendingBroadcast = undefined;
|
|
274
783
|
while(true){
|
|
275
784
|
const blocksBuilt = blocksInCheckpoint.length;
|
|
276
785
|
const indexWithinCheckpoint = blocksBuilt;
|
|
@@ -294,7 +803,8 @@ import { SequencerState } from './utils.js';
|
|
|
294
803
|
buildDeadline: timingInfo.deadline ? new Date((this.getSlotStartBuildTimestamp() + timingInfo.deadline) * 1000) : undefined,
|
|
295
804
|
blockNumber,
|
|
296
805
|
indexWithinCheckpoint,
|
|
297
|
-
txHashesAlreadyIncluded
|
|
806
|
+
txHashesAlreadyIncluded,
|
|
807
|
+
remainingBlobFields
|
|
298
808
|
});
|
|
299
809
|
if (!buildResult && timingInfo.isLastBlock) {
|
|
300
810
|
break;
|
|
@@ -315,12 +825,21 @@ import { SequencerState } from './utils.js';
|
|
|
315
825
|
}
|
|
316
826
|
break;
|
|
317
827
|
}
|
|
318
|
-
const { block, usedTxs } = buildResult;
|
|
828
|
+
const { block, usedTxs, remainingBlobFields: newRemainingBlobFields } = buildResult;
|
|
319
829
|
blocksInCheckpoint.push(block);
|
|
830
|
+
// Update remaining blob fields for the next block
|
|
831
|
+
remainingBlobFields = newRemainingBlobFields;
|
|
320
832
|
// Sync the proposed block to the archiver to make it available
|
|
321
833
|
// Note that the checkpoint builder uses its own fork so it should not need to wait for this syncing
|
|
322
834
|
// Eventually we should refactor the checkpoint builder to not need a separate long-lived fork
|
|
323
|
-
|
|
835
|
+
// Fire and forget - don't block the critical path, but log errors
|
|
836
|
+
this.syncProposedBlockToArchiver(block).catch((err)=>{
|
|
837
|
+
this.log.error(`Failed to sync proposed block ${block.number} to archiver`, {
|
|
838
|
+
blockNumber: block.number,
|
|
839
|
+
err
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
usedTxs.forEach((tx)=>txHashesAlreadyIncluded.add(tx.txHash.toString()));
|
|
324
843
|
// If this is the last block, exit the loop now so we start collecting attestations
|
|
325
844
|
if (timingInfo.isLastBlock) {
|
|
326
845
|
this.log.verbose(`Completed final block ${blockNumber} for slot ${this.slot}`, {
|
|
@@ -328,7 +847,7 @@ import { SequencerState } from './utils.js';
|
|
|
328
847
|
blockNumber,
|
|
329
848
|
blocksBuilt
|
|
330
849
|
});
|
|
331
|
-
|
|
850
|
+
blockPendingBroadcast = {
|
|
332
851
|
block,
|
|
333
852
|
txs: usedTxs
|
|
334
853
|
};
|
|
@@ -337,8 +856,7 @@ import { SequencerState } from './utils.js';
|
|
|
337
856
|
// For non-last blocks, broadcast the block proposal (unless we're in fisherman mode)
|
|
338
857
|
// If the block is the last one, we'll broadcast it along with the checkpoint at the end of the loop
|
|
339
858
|
if (!this.config.fishermanMode) {
|
|
340
|
-
|
|
341
|
-
const proposal = await this.validatorClient.createBlockProposal(block.header.globalVariables.blockNumber, (await checkpointBuilder.getCheckpoint()).header, block.archive.root, usedTxs, this.proposer, blockProposalOptions);
|
|
859
|
+
const proposal = await this.validatorClient.createBlockProposal(block.header, block.indexWithinCheckpoint, inHash, block.archive.root, usedTxs, this.proposer, blockProposalOptions);
|
|
342
860
|
await this.p2pClient.broadcastProposal(proposal);
|
|
343
861
|
}
|
|
344
862
|
// Wait until the next block's start time
|
|
@@ -350,7 +868,7 @@ import { SequencerState } from './utils.js';
|
|
|
350
868
|
});
|
|
351
869
|
return {
|
|
352
870
|
blocksInCheckpoint,
|
|
353
|
-
|
|
871
|
+
blockPendingBroadcast
|
|
354
872
|
};
|
|
355
873
|
}
|
|
356
874
|
/** Sleeps until it is time to produce the next block in the slot */ async waitUntilNextSubslot(nextSubslotStart) {
|
|
@@ -361,7 +879,7 @@ import { SequencerState } from './utils.js';
|
|
|
361
879
|
await this.waitUntilTimeInSlot(nextSubslotStart);
|
|
362
880
|
}
|
|
363
881
|
/** Builds a single block. Called from the main block building loop. */ async buildSingleBlock(checkpointBuilder, opts) {
|
|
364
|
-
const { blockTimestamp, forceCreate, blockNumber, indexWithinCheckpoint, buildDeadline, txHashesAlreadyIncluded } = opts;
|
|
882
|
+
const { blockTimestamp, forceCreate, blockNumber, indexWithinCheckpoint, buildDeadline, txHashesAlreadyIncluded, remainingBlobFields } = opts;
|
|
365
883
|
this.log.verbose(`Preparing block ${blockNumber} index ${indexWithinCheckpoint} at checkpoint ${this.checkpointNumber} for slot ${this.slot}`, {
|
|
366
884
|
...checkpointBuilder.getConstantData(),
|
|
367
885
|
...opts
|
|
@@ -393,16 +911,19 @@ import { SequencerState } from './utils.js';
|
|
|
393
911
|
indexWithinCheckpoint
|
|
394
912
|
});
|
|
395
913
|
this.setStateFn(SequencerState.CREATING_BLOCK, this.slot);
|
|
914
|
+
// Calculate blob fields limit for txs (remaining capacity - this block's end overhead)
|
|
915
|
+
const blockEndOverhead = getNumBlockEndBlobFields(indexWithinCheckpoint === 0);
|
|
916
|
+
const maxBlobFieldsForTxs = remainingBlobFields - blockEndOverhead;
|
|
396
917
|
const blockBuilderOptions = {
|
|
397
918
|
maxTransactions: this.config.maxTxsPerBlock,
|
|
398
919
|
maxBlockSize: this.config.maxBlockSizeInBytes,
|
|
399
920
|
maxBlockGas: new Gas(this.config.maxDABlockGas, this.config.maxL2BlockGas),
|
|
400
|
-
maxBlobFields:
|
|
921
|
+
maxBlobFields: maxBlobFieldsForTxs,
|
|
401
922
|
deadline: buildDeadline
|
|
402
923
|
};
|
|
403
924
|
// Actually build the block by executing txs
|
|
404
925
|
const workTimer = new Timer();
|
|
405
|
-
const { publicGas, block, publicProcessorDuration, numTxs, blockBuildingTimer, usedTxs, failedTxs } = await checkpointBuilder.buildBlock(pendingTxs, blockNumber, blockTimestamp, blockBuilderOptions);
|
|
926
|
+
const { publicGas, block, publicProcessorDuration, numTxs, blockBuildingTimer, usedTxs, failedTxs, usedTxBlobFields } = await checkpointBuilder.buildBlock(pendingTxs, blockNumber, blockTimestamp, blockBuilderOptions);
|
|
406
927
|
const blockBuildDuration = workTimer.ms();
|
|
407
928
|
// If any txs failed during execution, drop them from the mempool so we don't pick them up again
|
|
408
929
|
await this.dropFailedTxsFromP2P(failedTxs);
|
|
@@ -448,7 +969,8 @@ import { SequencerState } from './utils.js';
|
|
|
448
969
|
this.metrics.recordBuiltBlock(blockBuildDuration, publicGas.l2Gas);
|
|
449
970
|
return {
|
|
450
971
|
block,
|
|
451
|
-
usedTxs
|
|
972
|
+
usedTxs,
|
|
973
|
+
remainingBlobFields: maxBlobFieldsForTxs - usedTxBlobFields
|
|
452
974
|
};
|
|
453
975
|
} catch (err) {
|
|
454
976
|
this.eventEmitter.emit('block-build-failed', {
|
|
@@ -523,7 +1045,7 @@ import { SequencerState } from './utils.js';
|
|
|
523
1045
|
return new CommitteeAttestationsAndSigners(orderAttestations(attestations ?? [], committee));
|
|
524
1046
|
}
|
|
525
1047
|
const attestationTimeAllowed = this.config.enforceTimeTable ? this.timetable.getMaxAllowedTime(SequencerState.PUBLISHING_CHECKPOINT) : this.l1Constants.slotDuration;
|
|
526
|
-
const attestationDeadline = new Date(this.
|
|
1048
|
+
const attestationDeadline = new Date((this.getSlotStartBuildTimestamp() + attestationTimeAllowed) * 1000);
|
|
527
1049
|
this.metrics.recordRequiredAttestations(numberOfRequiredAttestations, attestationTimeAllowed);
|
|
528
1050
|
const collectAttestationsTimer = new Timer();
|
|
529
1051
|
let collectedAttestationsCount = 0;
|
|
@@ -534,8 +1056,7 @@ import { SequencerState } from './utils.js';
|
|
|
534
1056
|
const sorted = orderAttestations(attestations, committee);
|
|
535
1057
|
// Manipulate the attestations if we've been configured to do so
|
|
536
1058
|
if (this.config.injectFakeAttestation || this.config.shuffleAttestationOrdering) {
|
|
537
|
-
|
|
538
|
-
return this.manipulateAttestations(checkpoint, epoch, seed, committee, sorted);
|
|
1059
|
+
return this.manipulateAttestations(proposal.slotNumber, epoch, seed, committee, sorted);
|
|
539
1060
|
}
|
|
540
1061
|
return new CommitteeAttestationsAndSigners(sorted);
|
|
541
1062
|
} catch (err) {
|
|
@@ -547,10 +1068,9 @@ import { SequencerState } from './utils.js';
|
|
|
547
1068
|
this.metrics.recordCollectedAttestations(collectedAttestationsCount, collectAttestationsTimer.ms());
|
|
548
1069
|
}
|
|
549
1070
|
}
|
|
550
|
-
/** Breaks the attestations before publishing based on attack configs */ manipulateAttestations(
|
|
1071
|
+
/** Breaks the attestations before publishing based on attack configs */ manipulateAttestations(slotNumber, epoch, seed, committee, attestations) {
|
|
551
1072
|
// Compute the proposer index in the committee, since we dont want to tweak it.
|
|
552
1073
|
// Otherwise, the L1 rollup contract will reject the block outright.
|
|
553
|
-
const { slotNumber } = checkpoint;
|
|
554
1074
|
const proposerIndex = Number(this.epochCache.computeProposerIndex(slotNumber, epoch, seed, BigInt(committee.length)));
|
|
555
1075
|
if (this.config.injectFakeAttestation) {
|
|
556
1076
|
// Find non-empty attestations that are not from the proposer
|
|
@@ -595,15 +1115,22 @@ import { SequencerState } from './utils.js';
|
|
|
595
1115
|
await this.p2pClient.deleteTxs(failedTxHashes);
|
|
596
1116
|
}
|
|
597
1117
|
/**
|
|
598
|
-
*
|
|
599
|
-
*
|
|
1118
|
+
* Adds the proposed block to the archiver so it's available via P2P.
|
|
1119
|
+
* Gossip doesn't echo messages back to the sender, so the proposer's archiver/world-state
|
|
1120
|
+
* would never receive its own block without this explicit sync.
|
|
600
1121
|
*/ async syncProposedBlockToArchiver(block) {
|
|
601
|
-
this.
|
|
1122
|
+
if (this.config.skipPushProposedBlocksToArchiver !== false) {
|
|
1123
|
+
this.log.warn(`Skipping push of proposed block ${block.number} to archiver`, {
|
|
1124
|
+
blockNumber: block.number,
|
|
1125
|
+
slot: block.header.globalVariables.slotNumber
|
|
1126
|
+
});
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
this.log.debug(`Syncing proposed block ${block.number} to archiver`, {
|
|
602
1130
|
blockNumber: block.number,
|
|
603
1131
|
slot: block.header.globalVariables.slotNumber
|
|
604
1132
|
});
|
|
605
|
-
|
|
606
|
-
await Promise.resolve();
|
|
1133
|
+
await this.blockSink.addBlock(block);
|
|
607
1134
|
}
|
|
608
1135
|
/** Runs fee analysis and logs checkpoint outcome as fisherman */ async handleCheckpointEndAsFisherman(checkpoint) {
|
|
609
1136
|
// Perform L1 fee analysis before clearing requests
|