@aztec/sequencer-client 0.0.1-commit.03f7ef2 → 0.0.1-commit.0b941701
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 +5 -6
- package/dest/client/sequencer-client.d.ts.map +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-factory.d.ts +2 -2
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- 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 +15 -86
- package/dest/publisher/sequencer-publisher.d.ts +19 -18
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +443 -53
- package/dest/sequencer/checkpoint_proposal_job.d.ts +14 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +565 -40
- 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 +3 -3
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +30 -121
- 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-factory.ts +1 -1
- package/src/publisher/sequencer-publisher-metrics.ts +14 -70
- package/src/publisher/sequencer-publisher.ts +87 -77
- package/src/sequencer/checkpoint_proposal_job.ts +201 -59
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/metrics.ts +23 -131
- package/src/sequencer/sequencer.ts +124 -41
- 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,6 +63,380 @@ 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';
|
|
@@ -74,31 +448,44 @@ import { unfreeze } from '@aztec/foundation/types';
|
|
|
74
448
|
import { CommitteeAttestationsAndSigners, MaliciousCommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
75
449
|
import { getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
76
450
|
import { Gas } from '@aztec/stdlib/gas';
|
|
451
|
+
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
77
452
|
import { orderAttestations } from '@aztec/stdlib/p2p';
|
|
78
453
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
454
|
+
import { Attributes, trackSpan } from '@aztec/telemetry-client';
|
|
455
|
+
import { DutyAlreadySignedError, SlashingProtectionError } from '@aztec/validator-ha-signer/errors';
|
|
79
456
|
import { CheckpointVoter } from './checkpoint_voter.js';
|
|
80
457
|
import { SequencerInterruptedError } from './errors.js';
|
|
81
458
|
import { SequencerState } from './utils.js';
|
|
82
459
|
/** How much time to sleep while waiting for min transactions to accumulate for a block */ const TXS_POLLING_MS = 500;
|
|
460
|
+
_dec = trackSpan('CheckpointProposalJob.execute'), _dec1 = trackSpan('CheckpointProposalJob.proposeCheckpoint', function() {
|
|
461
|
+
return {
|
|
462
|
+
// nullish operator needed for tests
|
|
463
|
+
[Attributes.COINBASE]: this.validatorClient.getCoinbaseForAttestor(this.attestorAddress)?.toString(),
|
|
464
|
+
[Attributes.SLOT_NUMBER]: this.slot
|
|
465
|
+
};
|
|
466
|
+
}), _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
467
|
/**
|
|
84
468
|
* Handles the execution of a checkpoint proposal after the initial preparation phase.
|
|
85
469
|
* This includes building blocks, collecting attestations, and publishing the checkpoint to L1,
|
|
86
470
|
* as well as enqueueing votes for slashing and governance proposals. This class is created from
|
|
87
471
|
* the Sequencer once the check for being the proposer for the slot has succeeded.
|
|
88
472
|
*/ export class CheckpointProposalJob {
|
|
473
|
+
epoch;
|
|
89
474
|
slot;
|
|
90
475
|
checkpointNumber;
|
|
91
476
|
syncedToBlockNumber;
|
|
92
477
|
proposer;
|
|
93
478
|
publisher;
|
|
94
479
|
attestorAddress;
|
|
95
|
-
|
|
480
|
+
invalidateCheckpoint;
|
|
96
481
|
validatorClient;
|
|
97
482
|
globalsBuilder;
|
|
98
483
|
p2pClient;
|
|
99
484
|
worldState;
|
|
100
485
|
l1ToL2MessageSource;
|
|
486
|
+
l2BlockSource;
|
|
101
487
|
checkpointsBuilder;
|
|
488
|
+
blockSink;
|
|
102
489
|
l1Constants;
|
|
103
490
|
config;
|
|
104
491
|
timetable;
|
|
@@ -109,21 +496,69 @@ import { SequencerState } from './utils.js';
|
|
|
109
496
|
eventEmitter;
|
|
110
497
|
setStateFn;
|
|
111
498
|
log;
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
}
|
|
544
|
+
constructor(epoch, slot, checkpointNumber, syncedToBlockNumber, // TODO(palla/mbps): Can we remove the proposer in favor of attestorAddress? Need to check fisherman-node flows.
|
|
545
|
+
proposer, publisher, attestorAddress, invalidateCheckpoint, validatorClient, globalsBuilder, p2pClient, worldState, l1ToL2MessageSource, l2BlockSource, checkpointsBuilder, blockSink, l1Constants, config, timetable, slasherClient, epochCache, dateProvider, metrics, eventEmitter, setStateFn, log, tracer){
|
|
546
|
+
this.epoch = epoch;
|
|
114
547
|
this.slot = slot;
|
|
115
548
|
this.checkpointNumber = checkpointNumber;
|
|
116
549
|
this.syncedToBlockNumber = syncedToBlockNumber;
|
|
117
550
|
this.proposer = proposer;
|
|
118
551
|
this.publisher = publisher;
|
|
119
552
|
this.attestorAddress = attestorAddress;
|
|
120
|
-
this.
|
|
553
|
+
this.invalidateCheckpoint = invalidateCheckpoint;
|
|
121
554
|
this.validatorClient = validatorClient;
|
|
122
555
|
this.globalsBuilder = globalsBuilder;
|
|
123
556
|
this.p2pClient = p2pClient;
|
|
124
557
|
this.worldState = worldState;
|
|
125
558
|
this.l1ToL2MessageSource = l1ToL2MessageSource;
|
|
559
|
+
this.l2BlockSource = l2BlockSource;
|
|
126
560
|
this.checkpointsBuilder = checkpointsBuilder;
|
|
561
|
+
this.blockSink = blockSink;
|
|
127
562
|
this.l1Constants = l1Constants;
|
|
128
563
|
this.config = config;
|
|
129
564
|
this.timetable = timetable;
|
|
@@ -134,6 +569,8 @@ import { SequencerState } from './utils.js';
|
|
|
134
569
|
this.eventEmitter = eventEmitter;
|
|
135
570
|
this.setStateFn = setStateFn;
|
|
136
571
|
this.log = log;
|
|
572
|
+
this.tracer = tracer;
|
|
573
|
+
_initProto(this);
|
|
137
574
|
}
|
|
138
575
|
/**
|
|
139
576
|
* Executes the checkpoint proposal job.
|
|
@@ -147,6 +584,9 @@ import { SequencerState } from './utils.js';
|
|
|
147
584
|
const checkpoint = await this.proposeCheckpoint();
|
|
148
585
|
// Wait until the voting promises have resolved, so all requests are enqueued (not sent)
|
|
149
586
|
await Promise.all(votesPromises);
|
|
587
|
+
if (checkpoint) {
|
|
588
|
+
this.metrics.recordBlockProposalSuccess();
|
|
589
|
+
}
|
|
150
590
|
// Do not post anything to L1 if we are fishermen, but do perform L1 fee analysis
|
|
151
591
|
if (this.config.fishermanMode) {
|
|
152
592
|
await this.handleCheckpointEndAsFisherman(checkpoint);
|
|
@@ -185,26 +625,60 @@ import { SequencerState } from './utils.js';
|
|
|
185
625
|
// Start the checkpoint
|
|
186
626
|
this.setStateFn(SequencerState.INITIALIZING_CHECKPOINT, this.slot);
|
|
187
627
|
this.metrics.incOpenSlot(this.slot, this.proposer?.toString() ?? 'unknown');
|
|
188
|
-
// Enqueues
|
|
189
|
-
if (this.
|
|
190
|
-
this.publisher.
|
|
628
|
+
// Enqueues checkpoint invalidation (constant for the whole slot)
|
|
629
|
+
if (this.invalidateCheckpoint && !this.config.skipInvalidateBlockAsProposer) {
|
|
630
|
+
this.publisher.enqueueInvalidateCheckpoint(this.invalidateCheckpoint);
|
|
191
631
|
}
|
|
192
632
|
// Create checkpoint builder for the slot
|
|
193
633
|
const checkpointGlobalVariables = await this.globalsBuilder.buildCheckpointGlobalVariables(coinbase, feeRecipient, this.slot);
|
|
194
|
-
// Collect L1 to L2 messages for the checkpoint
|
|
634
|
+
// Collect L1 to L2 messages for the checkpoint and compute their hash
|
|
195
635
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(this.checkpointNumber);
|
|
636
|
+
const inHash = computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
637
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
638
|
+
const previousCheckpoints = (await this.l2BlockSource.getCheckpointsForEpoch(this.epoch)).filter((c)=>c.number < this.checkpointNumber);
|
|
639
|
+
const previousCheckpointOutHashes = previousCheckpoints.map((c)=>c.getCheckpointOutHash());
|
|
196
640
|
const fork = _ts_add_disposable_resource(env, await this.worldState.fork(this.syncedToBlockNumber, {
|
|
197
641
|
closeDelayMs: 12_000
|
|
198
642
|
}), false);
|
|
199
643
|
// Create checkpoint builder for the entire slot
|
|
200
|
-
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(this.checkpointNumber, checkpointGlobalVariables, l1ToL2Messages, fork);
|
|
644
|
+
const checkpointBuilder = await this.checkpointsBuilder.startCheckpoint(this.checkpointNumber, checkpointGlobalVariables, l1ToL2Messages, previousCheckpointOutHashes, fork);
|
|
201
645
|
// Options for the validator client when creating block and checkpoint proposals
|
|
202
646
|
const blockProposalOptions = {
|
|
203
647
|
publishFullTxs: !!this.config.publishTxsWithProposals,
|
|
204
648
|
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal
|
|
205
649
|
};
|
|
206
|
-
|
|
207
|
-
|
|
650
|
+
const checkpointProposalOptions = {
|
|
651
|
+
publishFullTxs: !!this.config.publishTxsWithProposals,
|
|
652
|
+
broadcastInvalidCheckpointProposal: this.config.broadcastInvalidBlockProposal
|
|
653
|
+
};
|
|
654
|
+
let blocksInCheckpoint = [];
|
|
655
|
+
let blockPendingBroadcast = undefined;
|
|
656
|
+
try {
|
|
657
|
+
// Main loop: build blocks for the checkpoint
|
|
658
|
+
const result = await this.buildBlocksForCheckpoint(checkpointBuilder, checkpointGlobalVariables.timestamp, inHash, blockProposalOptions);
|
|
659
|
+
blocksInCheckpoint = result.blocksInCheckpoint;
|
|
660
|
+
blockPendingBroadcast = result.blockPendingBroadcast;
|
|
661
|
+
} catch (err) {
|
|
662
|
+
// These errors are expected in HA mode, so we yield and let another HA node handle the slot
|
|
663
|
+
// The only distinction between the 2 errors is SlashingProtectionError throws when the payload is different,
|
|
664
|
+
// which is normal for block building (may have picked different txs)
|
|
665
|
+
if (err instanceof DutyAlreadySignedError) {
|
|
666
|
+
this.log.info(`Checkpoint proposal for slot ${this.slot} already signed by another HA node, yielding`, {
|
|
667
|
+
slot: this.slot,
|
|
668
|
+
signedByNode: err.signedByNode
|
|
669
|
+
});
|
|
670
|
+
return undefined;
|
|
671
|
+
}
|
|
672
|
+
if (err instanceof SlashingProtectionError) {
|
|
673
|
+
this.log.info(`Checkpoint proposal for slot ${this.slot} blocked by slashing protection, yielding`, {
|
|
674
|
+
slot: this.slot,
|
|
675
|
+
existingMessageHash: err.existingMessageHash,
|
|
676
|
+
attemptedMessageHash: err.attemptedMessageHash
|
|
677
|
+
});
|
|
678
|
+
return undefined;
|
|
679
|
+
}
|
|
680
|
+
throw err;
|
|
681
|
+
}
|
|
208
682
|
if (blocksInCheckpoint.length === 0) {
|
|
209
683
|
this.log.warn(`No blocks were built for slot ${this.slot}`, {
|
|
210
684
|
slot: this.slot
|
|
@@ -228,17 +702,45 @@ import { SequencerState } from './utils.js';
|
|
|
228
702
|
this.metrics.recordCheckpointSuccess();
|
|
229
703
|
return checkpoint;
|
|
230
704
|
}
|
|
231
|
-
//
|
|
232
|
-
const
|
|
705
|
+
// Include the block pending broadcast in the checkpoint proposal if any
|
|
706
|
+
const lastBlock = blockPendingBroadcast && {
|
|
707
|
+
blockHeader: blockPendingBroadcast.block.header,
|
|
708
|
+
indexWithinCheckpoint: blockPendingBroadcast.block.indexWithinCheckpoint,
|
|
709
|
+
txs: blockPendingBroadcast.txs
|
|
710
|
+
};
|
|
711
|
+
// Create the checkpoint proposal and broadcast it
|
|
712
|
+
const proposal = await this.validatorClient.createCheckpointProposal(checkpoint.header, checkpoint.archive.root, lastBlock, this.proposer, checkpointProposalOptions);
|
|
233
713
|
const blockProposedAt = this.dateProvider.now();
|
|
234
|
-
await this.p2pClient.
|
|
714
|
+
await this.p2pClient.broadcastCheckpointProposal(proposal);
|
|
235
715
|
this.setStateFn(SequencerState.COLLECTING_ATTESTATIONS, this.slot);
|
|
236
716
|
const attestations = await this.waitForAttestations(proposal);
|
|
237
717
|
const blockAttestedAt = this.dateProvider.now();
|
|
238
|
-
this.metrics.
|
|
718
|
+
this.metrics.recordCheckpointAttestationDelay(blockAttestedAt - blockProposedAt);
|
|
239
719
|
// Proposer must sign over the attestations before pushing them to L1
|
|
240
720
|
const signer = this.proposer ?? this.publisher.getSenderAddress();
|
|
241
|
-
|
|
721
|
+
let attestationsSignature;
|
|
722
|
+
try {
|
|
723
|
+
attestationsSignature = await this.validatorClient.signAttestationsAndSigners(attestations, signer, this.slot, this.checkpointNumber);
|
|
724
|
+
} catch (err) {
|
|
725
|
+
// We shouldn't really get here since we yield to another HA node
|
|
726
|
+
// as soon as we see these errors when creating block proposals.
|
|
727
|
+
if (err instanceof DutyAlreadySignedError) {
|
|
728
|
+
this.log.info(`Attestations signature for slot ${this.slot} already signed by another HA node, yielding`, {
|
|
729
|
+
slot: this.slot,
|
|
730
|
+
signedByNode: err.signedByNode
|
|
731
|
+
});
|
|
732
|
+
return undefined;
|
|
733
|
+
}
|
|
734
|
+
if (err instanceof SlashingProtectionError) {
|
|
735
|
+
this.log.info(`Attestations signature for slot ${this.slot} blocked by slashing protection, yielding`, {
|
|
736
|
+
slot: this.slot,
|
|
737
|
+
existingMessageHash: err.existingMessageHash,
|
|
738
|
+
attemptedMessageHash: err.attemptedMessageHash
|
|
739
|
+
});
|
|
740
|
+
return undefined;
|
|
741
|
+
}
|
|
742
|
+
throw err;
|
|
743
|
+
}
|
|
242
744
|
// Enqueue publishing the checkpoint to L1
|
|
243
745
|
this.setStateFn(SequencerState.PUBLISHING_CHECKPOINT, this.slot);
|
|
244
746
|
const aztecSlotDuration = this.l1Constants.slotDuration;
|
|
@@ -246,7 +748,7 @@ import { SequencerState } from './utils.js';
|
|
|
246
748
|
const txTimeoutAt = new Date((slotStartBuildTimestamp + aztecSlotDuration) * 1000);
|
|
247
749
|
await this.publisher.enqueueProposeCheckpoint(checkpoint, attestations, attestationsSignature, {
|
|
248
750
|
txTimeoutAt,
|
|
249
|
-
|
|
751
|
+
forcePendingCheckpointNumber: this.invalidateCheckpoint?.forcePendingCheckpointNumber
|
|
250
752
|
});
|
|
251
753
|
return checkpoint;
|
|
252
754
|
} catch (e) {
|
|
@@ -256,18 +758,24 @@ import { SequencerState } from './utils.js';
|
|
|
256
758
|
_ts_dispose_resources(env);
|
|
257
759
|
}
|
|
258
760
|
} catch (err) {
|
|
761
|
+
if (err && (err instanceof DutyAlreadySignedError || err instanceof SlashingProtectionError)) {
|
|
762
|
+
// swallow this error. It's already been logged by a function deeper in the stack
|
|
763
|
+
return undefined;
|
|
764
|
+
}
|
|
259
765
|
this.log.error(`Error building checkpoint at slot ${this.slot}`, err);
|
|
260
766
|
return undefined;
|
|
261
767
|
}
|
|
262
768
|
}
|
|
263
769
|
/**
|
|
264
770
|
* Builds blocks for a checkpoint within the current slot.
|
|
265
|
-
*/ async buildBlocksForCheckpoint(checkpointBuilder, timestamp, blockProposalOptions) {
|
|
771
|
+
*/ async buildBlocksForCheckpoint(checkpointBuilder, timestamp, inHash, blockProposalOptions) {
|
|
266
772
|
const blocksInCheckpoint = [];
|
|
267
773
|
const txHashesAlreadyIncluded = new Set();
|
|
268
774
|
const initialBlockNumber = BlockNumber(this.syncedToBlockNumber + 1);
|
|
775
|
+
// Remaining blob fields available for blocks (checkpoint end marker already subtracted)
|
|
776
|
+
let remainingBlobFields = BLOBS_PER_CHECKPOINT * FIELDS_PER_BLOB - NUM_CHECKPOINT_END_MARKER_FIELDS;
|
|
269
777
|
// Last block in the checkpoint will usually be flagged as pending broadcast, so we send it along with the checkpoint proposal
|
|
270
|
-
let
|
|
778
|
+
let blockPendingBroadcast = undefined;
|
|
271
779
|
while(true){
|
|
272
780
|
const blocksBuilt = blocksInCheckpoint.length;
|
|
273
781
|
const indexWithinCheckpoint = blocksBuilt;
|
|
@@ -291,7 +799,8 @@ import { SequencerState } from './utils.js';
|
|
|
291
799
|
buildDeadline: timingInfo.deadline ? new Date((this.getSlotStartBuildTimestamp() + timingInfo.deadline) * 1000) : undefined,
|
|
292
800
|
blockNumber,
|
|
293
801
|
indexWithinCheckpoint,
|
|
294
|
-
txHashesAlreadyIncluded
|
|
802
|
+
txHashesAlreadyIncluded,
|
|
803
|
+
remainingBlobFields
|
|
295
804
|
});
|
|
296
805
|
if (!buildResult && timingInfo.isLastBlock) {
|
|
297
806
|
break;
|
|
@@ -312,12 +821,21 @@ import { SequencerState } from './utils.js';
|
|
|
312
821
|
}
|
|
313
822
|
break;
|
|
314
823
|
}
|
|
315
|
-
const { block, usedTxs } = buildResult;
|
|
824
|
+
const { block, usedTxs, remainingBlobFields: newRemainingBlobFields } = buildResult;
|
|
316
825
|
blocksInCheckpoint.push(block);
|
|
826
|
+
// Update remaining blob fields for the next block
|
|
827
|
+
remainingBlobFields = newRemainingBlobFields;
|
|
317
828
|
// Sync the proposed block to the archiver to make it available
|
|
318
829
|
// Note that the checkpoint builder uses its own fork so it should not need to wait for this syncing
|
|
319
830
|
// Eventually we should refactor the checkpoint builder to not need a separate long-lived fork
|
|
320
|
-
|
|
831
|
+
// Fire and forget - don't block the critical path, but log errors
|
|
832
|
+
this.syncProposedBlockToArchiver(block).catch((err)=>{
|
|
833
|
+
this.log.error(`Failed to sync proposed block ${block.number} to archiver`, {
|
|
834
|
+
blockNumber: block.number,
|
|
835
|
+
err
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
usedTxs.forEach((tx)=>txHashesAlreadyIncluded.add(tx.txHash.toString()));
|
|
321
839
|
// If this is the last block, exit the loop now so we start collecting attestations
|
|
322
840
|
if (timingInfo.isLastBlock) {
|
|
323
841
|
this.log.verbose(`Completed final block ${blockNumber} for slot ${this.slot}`, {
|
|
@@ -325,7 +843,7 @@ import { SequencerState } from './utils.js';
|
|
|
325
843
|
blockNumber,
|
|
326
844
|
blocksBuilt
|
|
327
845
|
});
|
|
328
|
-
|
|
846
|
+
blockPendingBroadcast = {
|
|
329
847
|
block,
|
|
330
848
|
txs: usedTxs
|
|
331
849
|
};
|
|
@@ -334,8 +852,7 @@ import { SequencerState } from './utils.js';
|
|
|
334
852
|
// For non-last blocks, broadcast the block proposal (unless we're in fisherman mode)
|
|
335
853
|
// If the block is the last one, we'll broadcast it along with the checkpoint at the end of the loop
|
|
336
854
|
if (!this.config.fishermanMode) {
|
|
337
|
-
|
|
338
|
-
const proposal = await this.validatorClient.createBlockProposal(block.header.globalVariables.blockNumber, (await checkpointBuilder.getCheckpoint()).header, block.archive.root, usedTxs, this.proposer, blockProposalOptions);
|
|
855
|
+
const proposal = await this.validatorClient.createBlockProposal(block.header, block.indexWithinCheckpoint, inHash, block.archive.root, usedTxs, this.proposer, blockProposalOptions);
|
|
339
856
|
await this.p2pClient.broadcastProposal(proposal);
|
|
340
857
|
}
|
|
341
858
|
// Wait until the next block's start time
|
|
@@ -347,7 +864,7 @@ import { SequencerState } from './utils.js';
|
|
|
347
864
|
});
|
|
348
865
|
return {
|
|
349
866
|
blocksInCheckpoint,
|
|
350
|
-
|
|
867
|
+
blockPendingBroadcast
|
|
351
868
|
};
|
|
352
869
|
}
|
|
353
870
|
/** Sleeps until it is time to produce the next block in the slot */ async waitUntilNextSubslot(nextSubslotStart) {
|
|
@@ -358,7 +875,7 @@ import { SequencerState } from './utils.js';
|
|
|
358
875
|
await this.waitUntilTimeInSlot(nextSubslotStart);
|
|
359
876
|
}
|
|
360
877
|
/** Builds a single block. Called from the main block building loop. */ async buildSingleBlock(checkpointBuilder, opts) {
|
|
361
|
-
const { blockTimestamp, forceCreate, blockNumber, indexWithinCheckpoint, buildDeadline, txHashesAlreadyIncluded } = opts;
|
|
878
|
+
const { blockTimestamp, forceCreate, blockNumber, indexWithinCheckpoint, buildDeadline, txHashesAlreadyIncluded, remainingBlobFields } = opts;
|
|
362
879
|
this.log.verbose(`Preparing block ${blockNumber} index ${indexWithinCheckpoint} at checkpoint ${this.checkpointNumber} for slot ${this.slot}`, {
|
|
363
880
|
...checkpointBuilder.getConstantData(),
|
|
364
881
|
...opts
|
|
@@ -390,16 +907,19 @@ import { SequencerState } from './utils.js';
|
|
|
390
907
|
indexWithinCheckpoint
|
|
391
908
|
});
|
|
392
909
|
this.setStateFn(SequencerState.CREATING_BLOCK, this.slot);
|
|
910
|
+
// Calculate blob fields limit for txs (remaining capacity - this block's end overhead)
|
|
911
|
+
const blockEndOverhead = getNumBlockEndBlobFields(indexWithinCheckpoint === 0);
|
|
912
|
+
const maxBlobFieldsForTxs = remainingBlobFields - blockEndOverhead;
|
|
393
913
|
const blockBuilderOptions = {
|
|
394
914
|
maxTransactions: this.config.maxTxsPerBlock,
|
|
395
915
|
maxBlockSize: this.config.maxBlockSizeInBytes,
|
|
396
916
|
maxBlockGas: new Gas(this.config.maxDABlockGas, this.config.maxL2BlockGas),
|
|
397
|
-
maxBlobFields:
|
|
917
|
+
maxBlobFields: maxBlobFieldsForTxs,
|
|
398
918
|
deadline: buildDeadline
|
|
399
919
|
};
|
|
400
920
|
// Actually build the block by executing txs
|
|
401
921
|
const workTimer = new Timer();
|
|
402
|
-
const { publicGas, block, publicProcessorDuration, numTxs, blockBuildingTimer, usedTxs, failedTxs } = await checkpointBuilder.buildBlock(pendingTxs, blockNumber, blockTimestamp, blockBuilderOptions);
|
|
922
|
+
const { publicGas, block, publicProcessorDuration, numTxs, blockBuildingTimer, usedTxs, failedTxs, usedTxBlobFields } = await checkpointBuilder.buildBlock(pendingTxs, blockNumber, blockTimestamp, blockBuilderOptions);
|
|
403
923
|
const blockBuildDuration = workTimer.ms();
|
|
404
924
|
// If any txs failed during execution, drop them from the mempool so we don't pick them up again
|
|
405
925
|
await this.dropFailedTxsFromP2P(failedTxs);
|
|
@@ -445,7 +965,8 @@ import { SequencerState } from './utils.js';
|
|
|
445
965
|
this.metrics.recordBuiltBlock(blockBuildDuration, publicGas.l2Gas);
|
|
446
966
|
return {
|
|
447
967
|
block,
|
|
448
|
-
usedTxs
|
|
968
|
+
usedTxs,
|
|
969
|
+
remainingBlobFields: maxBlobFieldsForTxs - usedTxBlobFields
|
|
449
970
|
};
|
|
450
971
|
} catch (err) {
|
|
451
972
|
this.eventEmitter.emit('block-build-failed', {
|
|
@@ -531,8 +1052,7 @@ import { SequencerState } from './utils.js';
|
|
|
531
1052
|
const sorted = orderAttestations(attestations, committee);
|
|
532
1053
|
// Manipulate the attestations if we've been configured to do so
|
|
533
1054
|
if (this.config.injectFakeAttestation || this.config.shuffleAttestationOrdering) {
|
|
534
|
-
|
|
535
|
-
return this.manipulateAttestations(checkpoint, epoch, seed, committee, sorted);
|
|
1055
|
+
return this.manipulateAttestations(proposal.slotNumber, epoch, seed, committee, sorted);
|
|
536
1056
|
}
|
|
537
1057
|
return new CommitteeAttestationsAndSigners(sorted);
|
|
538
1058
|
} catch (err) {
|
|
@@ -544,10 +1064,9 @@ import { SequencerState } from './utils.js';
|
|
|
544
1064
|
this.metrics.recordCollectedAttestations(collectedAttestationsCount, collectAttestationsTimer.ms());
|
|
545
1065
|
}
|
|
546
1066
|
}
|
|
547
|
-
/** Breaks the attestations before publishing based on attack configs */ manipulateAttestations(
|
|
1067
|
+
/** Breaks the attestations before publishing based on attack configs */ manipulateAttestations(slotNumber, epoch, seed, committee, attestations) {
|
|
548
1068
|
// Compute the proposer index in the committee, since we dont want to tweak it.
|
|
549
1069
|
// Otherwise, the L1 rollup contract will reject the block outright.
|
|
550
|
-
const { slotNumber } = checkpoint;
|
|
551
1070
|
const proposerIndex = Number(this.epochCache.computeProposerIndex(slotNumber, epoch, seed, BigInt(committee.length)));
|
|
552
1071
|
if (this.config.injectFakeAttestation) {
|
|
553
1072
|
// Find non-empty attestations that are not from the proposer
|
|
@@ -592,15 +1111,22 @@ import { SequencerState } from './utils.js';
|
|
|
592
1111
|
await this.p2pClient.deleteTxs(failedTxHashes);
|
|
593
1112
|
}
|
|
594
1113
|
/**
|
|
595
|
-
*
|
|
596
|
-
*
|
|
1114
|
+
* Adds the proposed block to the archiver so it's available via P2P.
|
|
1115
|
+
* Gossip doesn't echo messages back to the sender, so the proposer's archiver/world-state
|
|
1116
|
+
* would never receive its own block without this explicit sync.
|
|
597
1117
|
*/ async syncProposedBlockToArchiver(block) {
|
|
598
|
-
this.
|
|
1118
|
+
if (this.config.skipPushProposedBlocksToArchiver !== false) {
|
|
1119
|
+
this.log.warn(`Skipping push of proposed block ${block.number} to archiver`, {
|
|
1120
|
+
blockNumber: block.number,
|
|
1121
|
+
slot: block.header.globalVariables.slotNumber
|
|
1122
|
+
});
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
this.log.debug(`Syncing proposed block ${block.number} to archiver`, {
|
|
599
1126
|
blockNumber: block.number,
|
|
600
1127
|
slot: block.header.globalVariables.slotNumber
|
|
601
1128
|
});
|
|
602
|
-
|
|
603
|
-
await Promise.resolve();
|
|
1129
|
+
await this.blockSink.addBlock(block);
|
|
604
1130
|
}
|
|
605
1131
|
/** Runs fee analysis and logs checkpoint outcome as fisherman */ async handleCheckpointEndAsFisherman(checkpoint) {
|
|
606
1132
|
// Perform L1 fee analysis before clearing requests
|
|
@@ -612,7 +1138,6 @@ import { SequencerState } from './utils.js';
|
|
|
612
1138
|
...checkpoint.getStats(),
|
|
613
1139
|
feeAnalysisId: feeAnalysis?.id
|
|
614
1140
|
});
|
|
615
|
-
this.metrics.recordBlockProposalSuccess();
|
|
616
1141
|
} else {
|
|
617
1142
|
this.log.warn(`Validation block building FAILED for slot ${this.slot}`, {
|
|
618
1143
|
slot: this.slot,
|