@aztec/sequencer-client 0.0.1-commit.d3ec352c → 0.0.1-commit.f295ac2
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 +12 -12
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +32 -25
- package/dest/config.d.ts +12 -5
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +75 -30
- package/dest/global_variable_builder/global_builder.d.ts +21 -12
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +51 -41
- package/dest/index.d.ts +2 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/config.d.ts +7 -4
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +9 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts +5 -4
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts +3 -3
- 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 +48 -40
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +564 -114
- package/dest/sequencer/checkpoint_proposal_job.d.ts +79 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job.js +1155 -0
- package/dest/sequencer/checkpoint_voter.d.ts +35 -0
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_voter.js +109 -0
- package/dest/sequencer/config.d.ts +3 -2
- package/dest/sequencer/config.d.ts.map +1 -1
- package/dest/sequencer/events.d.ts +46 -0
- package/dest/sequencer/events.d.ts.map +1 -0
- package/dest/sequencer/events.js +1 -0
- package/dest/sequencer/index.d.ts +4 -2
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +3 -1
- package/dest/sequencer/metrics.d.ts +22 -2
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +125 -62
- package/dest/sequencer/sequencer.d.ts +107 -131
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +690 -602
- package/dest/sequencer/timetable.d.ts +54 -14
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +148 -59
- package/dest/sequencer/types.d.ts +3 -0
- package/dest/sequencer/types.d.ts.map +1 -0
- package/dest/sequencer/types.js +1 -0
- package/dest/sequencer/utils.d.ts +14 -8
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +7 -4
- package/dest/test/index.d.ts +4 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +92 -0
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
- package/dest/test/mock_checkpoint_builder.js +208 -0
- package/dest/test/utils.d.ts +53 -0
- package/dest/test/utils.d.ts.map +1 -0
- package/dest/test/utils.js +103 -0
- package/package.json +30 -28
- package/src/client/sequencer-client.ts +30 -41
- package/src/config.ts +80 -34
- package/src/global_variable_builder/global_builder.ts +63 -59
- package/src/index.ts +1 -7
- package/src/publisher/config.ts +12 -9
- package/src/publisher/sequencer-publisher-factory.ts +5 -4
- package/src/publisher/sequencer-publisher-metrics.ts +16 -72
- package/src/publisher/sequencer-publisher.ts +262 -155
- package/src/sequencer/README.md +531 -0
- package/src/sequencer/checkpoint_proposal_job.ts +836 -0
- package/src/sequencer/checkpoint_voter.ts +130 -0
- package/src/sequencer/config.ts +2 -1
- package/src/sequencer/events.ts +27 -0
- package/src/sequencer/index.ts +3 -1
- package/src/sequencer/metrics.ts +164 -70
- package/src/sequencer/sequencer.ts +430 -804
- package/src/sequencer/timetable.ts +173 -79
- package/src/sequencer/types.ts +6 -0
- package/src/sequencer/utils.ts +18 -9
- package/src/test/index.ts +3 -2
- package/src/test/mock_checkpoint_builder.ts +295 -0
- package/src/test/utils.ts +158 -0
- package/dest/sequencer/block_builder.d.ts +0 -28
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -134
- 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 -222
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -133
|
@@ -1,9 +1,385 @@
|
|
|
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);
|
|
372
|
+
}
|
|
373
|
+
var _dec, _dec1, _dec2, _initProto;
|
|
1
374
|
import { Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
375
|
+
import { MULTI_CALL_3_ADDRESS, Multicall3, RollupContract } from '@aztec/ethereum/contracts';
|
|
376
|
+
import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
377
|
+
import { WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
|
|
378
|
+
import { FormattedViemError, formatViemError, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
4
379
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
5
380
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
6
|
-
import {
|
|
381
|
+
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
382
|
+
import { pick } from '@aztec/foundation/collection';
|
|
7
383
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
8
384
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
9
385
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -11,8 +387,8 @@ import { bufferToHex } from '@aztec/foundation/string';
|
|
|
11
387
|
import { Timer } from '@aztec/foundation/timer';
|
|
12
388
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
13
389
|
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
14
|
-
import {
|
|
15
|
-
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
390
|
+
import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
391
|
+
import { getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
16
392
|
import { encodeFunctionData, toHex } from 'viem';
|
|
17
393
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
18
394
|
export const Actions = [
|
|
@@ -28,18 +404,40 @@ export const Actions = [
|
|
|
28
404
|
];
|
|
29
405
|
// Sorting for actions such that invalidations go before proposals, and proposals go before votes
|
|
30
406
|
export const compareActions = (a, b)=>Actions.indexOf(a) - Actions.indexOf(b);
|
|
407
|
+
_dec = trackSpan('SequencerPublisher.sendRequests'), _dec1 = trackSpan('SequencerPublisher.validateBlockHeader'), _dec2 = trackSpan('SequencerPublisher.validateCheckpointForSubmission');
|
|
31
408
|
export class SequencerPublisher {
|
|
32
409
|
config;
|
|
410
|
+
static{
|
|
411
|
+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
412
|
+
[
|
|
413
|
+
_dec,
|
|
414
|
+
2,
|
|
415
|
+
"sendRequests"
|
|
416
|
+
],
|
|
417
|
+
[
|
|
418
|
+
_dec1,
|
|
419
|
+
2,
|
|
420
|
+
"validateBlockHeader"
|
|
421
|
+
],
|
|
422
|
+
[
|
|
423
|
+
_dec2,
|
|
424
|
+
2,
|
|
425
|
+
"validateCheckpointForSubmission"
|
|
426
|
+
]
|
|
427
|
+
], []));
|
|
428
|
+
}
|
|
33
429
|
interrupted;
|
|
34
430
|
metrics;
|
|
35
431
|
epochCache;
|
|
36
432
|
governanceLog;
|
|
37
433
|
slashingLog;
|
|
38
434
|
lastActions;
|
|
435
|
+
isPayloadEmptyCache;
|
|
39
436
|
log;
|
|
40
437
|
ethereumSlotDuration;
|
|
41
|
-
|
|
438
|
+
blobClient;
|
|
42
439
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
440
|
+
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
43
441
|
// @note - with blobs, the below estimate seems too large.
|
|
44
442
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
45
443
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -53,23 +451,24 @@ export class SequencerPublisher {
|
|
|
53
451
|
govProposerContract;
|
|
54
452
|
slashingProposerContract;
|
|
55
453
|
slashFactoryContract;
|
|
454
|
+
tracer;
|
|
56
455
|
requests;
|
|
57
456
|
constructor(config, deps){
|
|
58
457
|
this.config = config;
|
|
59
|
-
this.interrupted = false;
|
|
458
|
+
this.interrupted = (_initProto(this), false);
|
|
60
459
|
this.governanceLog = createLogger('sequencer:publisher:governance');
|
|
61
460
|
this.slashingLog = createLogger('sequencer:publisher:slashing');
|
|
62
461
|
this.lastActions = {};
|
|
462
|
+
this.isPayloadEmptyCache = new Map();
|
|
63
463
|
this.requests = [];
|
|
64
464
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
65
465
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
66
466
|
this.epochCache = deps.epochCache;
|
|
67
467
|
this.lastActions = deps.lastActions;
|
|
68
|
-
this.
|
|
69
|
-
logger: createLogger('sequencer:blob-sink:client')
|
|
70
|
-
});
|
|
468
|
+
this.blobClient = deps.blobClient;
|
|
71
469
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
72
470
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
471
|
+
this.tracer = telemetry.getTracer('SequencerPublisher');
|
|
73
472
|
this.l1TxUtils = deps.l1TxUtils;
|
|
74
473
|
this.rollupContract = deps.rollupContract;
|
|
75
474
|
this.govProposerContract = deps.governanceProposerContract;
|
|
@@ -80,6 +479,10 @@ export class SequencerPublisher {
|
|
|
80
479
|
this.slashingProposerContract = newSlashingProposer;
|
|
81
480
|
});
|
|
82
481
|
this.slashFactoryContract = deps.slashFactoryContract;
|
|
482
|
+
// Initialize L1 fee analyzer for fisherman mode
|
|
483
|
+
if (config.fishermanMode) {
|
|
484
|
+
this.l1FeeAnalyzer = new L1FeeAnalyzer(this.l1TxUtils.client, deps.dateProvider, createLogger('sequencer:publisher:fee-analyzer'));
|
|
485
|
+
}
|
|
83
486
|
}
|
|
84
487
|
getRollupContract() {
|
|
85
488
|
return this.rollupContract;
|
|
@@ -88,6 +491,11 @@ export class SequencerPublisher {
|
|
|
88
491
|
return this.l1TxUtils.getSenderAddress();
|
|
89
492
|
}
|
|
90
493
|
/**
|
|
494
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
495
|
+
*/ getL1FeeAnalyzer() {
|
|
496
|
+
return this.l1FeeAnalyzer;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
91
499
|
* Sets the proposer address to use for simulations in fisherman mode.
|
|
92
500
|
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
93
501
|
*/ setProposerAddressForSimulation(proposerAddress) {
|
|
@@ -109,6 +517,46 @@ export class SequencerPublisher {
|
|
|
109
517
|
}
|
|
110
518
|
}
|
|
111
519
|
/**
|
|
520
|
+
* Analyzes L1 fees for the pending requests without sending them.
|
|
521
|
+
* This is used in fisherman mode to validate fee calculations.
|
|
522
|
+
* @param l2SlotNumber - The L2 slot number for this analysis
|
|
523
|
+
* @param onComplete - Optional callback to invoke when analysis completes (after block is mined)
|
|
524
|
+
* @returns The analysis result (incomplete until block mines), or undefined if no requests
|
|
525
|
+
*/ async analyzeL1Fees(l2SlotNumber, onComplete) {
|
|
526
|
+
if (!this.l1FeeAnalyzer) {
|
|
527
|
+
this.log.warn('L1 fee analyzer not available (not in fisherman mode)');
|
|
528
|
+
return undefined;
|
|
529
|
+
}
|
|
530
|
+
const requestsToAnalyze = [
|
|
531
|
+
...this.requests
|
|
532
|
+
];
|
|
533
|
+
if (requestsToAnalyze.length === 0) {
|
|
534
|
+
this.log.debug('No requests to analyze for L1 fees');
|
|
535
|
+
return undefined;
|
|
536
|
+
}
|
|
537
|
+
// Extract blob config from requests (if any)
|
|
538
|
+
const blobConfigs = requestsToAnalyze.filter((request)=>request.blobConfig).map((request)=>request.blobConfig);
|
|
539
|
+
const blobConfig = blobConfigs[0];
|
|
540
|
+
// Get gas configs
|
|
541
|
+
const gasConfigs = requestsToAnalyze.filter((request)=>request.gasConfig).map((request)=>request.gasConfig);
|
|
542
|
+
const gasLimits = gasConfigs.map((g)=>g?.gasLimit).filter((g)=>g !== undefined);
|
|
543
|
+
const gasLimit = gasLimits.length > 0 ? gasLimits.reduce((sum, g)=>sum + g, 0n) : 0n;
|
|
544
|
+
// Get the transaction requests
|
|
545
|
+
const l1Requests = requestsToAnalyze.map((r)=>r.request);
|
|
546
|
+
// Start the analysis
|
|
547
|
+
const analysisId = await this.l1FeeAnalyzer.startAnalysis(l2SlotNumber, gasLimit > 0n ? gasLimit : SequencerPublisher.PROPOSE_GAS_GUESS, l1Requests, blobConfig, onComplete);
|
|
548
|
+
this.log.info('Started L1 fee analysis', {
|
|
549
|
+
analysisId,
|
|
550
|
+
l2SlotNumber: l2SlotNumber.toString(),
|
|
551
|
+
requestCount: requestsToAnalyze.length,
|
|
552
|
+
hasBlobConfig: !!blobConfig,
|
|
553
|
+
gasLimit: gasLimit.toString(),
|
|
554
|
+
actions: requestsToAnalyze.map((r)=>r.action)
|
|
555
|
+
});
|
|
556
|
+
// Return the analysis result (will be incomplete until block mines)
|
|
557
|
+
return this.l1FeeAnalyzer.getAnalysis(analysisId);
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
112
560
|
* Sends all requests that are still valid.
|
|
113
561
|
* @returns one of:
|
|
114
562
|
* - A receipt and stats if the tx succeeded
|
|
@@ -119,7 +567,7 @@ export class SequencerPublisher {
|
|
|
119
567
|
...this.requests
|
|
120
568
|
];
|
|
121
569
|
this.requests = [];
|
|
122
|
-
if (this.interrupted) {
|
|
570
|
+
if (this.interrupted || requestsToProcess.length === 0) {
|
|
123
571
|
return undefined;
|
|
124
572
|
}
|
|
125
573
|
const currentL2Slot = this.getCurrentL2Slot();
|
|
@@ -229,7 +677,7 @@ export class SequencerPublisher {
|
|
|
229
677
|
'InvalidArchive'
|
|
230
678
|
];
|
|
231
679
|
return this.rollupContract.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), Number(this.ethereumSlotDuration), {
|
|
232
|
-
forcePendingCheckpointNumber: opts.
|
|
680
|
+
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber
|
|
233
681
|
}).catch((err)=>{
|
|
234
682
|
if (err instanceof FormattedViemError && ignoredErrors.find((e)=>err.message.includes(e))) {
|
|
235
683
|
this.log.warn(`Failed canProposeAtTime check with ${ignoredErrors.find((e)=>err.message.includes(e))}`, {
|
|
@@ -257,12 +705,11 @@ export class SequencerPublisher {
|
|
|
257
705
|
[],
|
|
258
706
|
Signature.empty().toViemSignature(),
|
|
259
707
|
`0x${'0'.repeat(64)}`,
|
|
260
|
-
header.
|
|
708
|
+
header.blobsHash.toString(),
|
|
261
709
|
flags
|
|
262
710
|
];
|
|
263
711
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
264
|
-
const
|
|
265
|
-
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(optsForcePendingCheckpointNumber);
|
|
712
|
+
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(opts?.forcePendingCheckpointNumber);
|
|
266
713
|
let balance = 0n;
|
|
267
714
|
if (this.config.fishermanMode) {
|
|
268
715
|
// In fisherman mode, we can't know where the proposer is publishing from
|
|
@@ -289,34 +736,34 @@ export class SequencerPublisher {
|
|
|
289
736
|
this.log.debug(`Simulated validateHeader`);
|
|
290
737
|
}
|
|
291
738
|
/**
|
|
292
|
-
* Simulate making a call to invalidate a
|
|
293
|
-
* @param
|
|
294
|
-
*/ async
|
|
739
|
+
* Simulate making a call to invalidate a checkpoint with invalid attestations. Returns undefined if no need to invalidate.
|
|
740
|
+
* @param validationResult - The validation result indicating which checkpoint to invalidate (as returned by the archiver)
|
|
741
|
+
*/ async simulateInvalidateCheckpoint(validationResult) {
|
|
295
742
|
if (validationResult.valid) {
|
|
296
743
|
return undefined;
|
|
297
744
|
}
|
|
298
|
-
const { reason,
|
|
299
|
-
const
|
|
745
|
+
const { reason, checkpoint } = validationResult;
|
|
746
|
+
const checkpointNumber = checkpoint.checkpointNumber;
|
|
300
747
|
const logData = {
|
|
301
|
-
...
|
|
748
|
+
...checkpoint,
|
|
302
749
|
reason
|
|
303
750
|
};
|
|
304
|
-
const
|
|
305
|
-
if (
|
|
306
|
-
this.log.verbose(`Skipping
|
|
307
|
-
|
|
751
|
+
const currentCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
752
|
+
if (currentCheckpointNumber < checkpointNumber) {
|
|
753
|
+
this.log.verbose(`Skipping checkpoint ${checkpointNumber} invalidation since it has already been removed from the pending chain`, {
|
|
754
|
+
currentCheckpointNumber,
|
|
308
755
|
...logData
|
|
309
756
|
});
|
|
310
757
|
return undefined;
|
|
311
758
|
}
|
|
312
|
-
const request = this.
|
|
313
|
-
this.log.debug(`Simulating invalidate
|
|
759
|
+
const request = this.buildInvalidateCheckpointRequest(validationResult);
|
|
760
|
+
this.log.debug(`Simulating invalidate checkpoint ${checkpointNumber}`, {
|
|
314
761
|
...logData,
|
|
315
762
|
request
|
|
316
763
|
});
|
|
317
764
|
try {
|
|
318
765
|
const { gasUsed } = await this.l1TxUtils.simulate(request, undefined, undefined, ErrorsAbi);
|
|
319
|
-
this.log.verbose(`Simulation for invalidate
|
|
766
|
+
this.log.verbose(`Simulation for invalidate checkpoint ${checkpointNumber} succeeded`, {
|
|
320
767
|
...logData,
|
|
321
768
|
request,
|
|
322
769
|
gasUsed
|
|
@@ -324,88 +771,83 @@ export class SequencerPublisher {
|
|
|
324
771
|
return {
|
|
325
772
|
request,
|
|
326
773
|
gasUsed,
|
|
327
|
-
|
|
328
|
-
|
|
774
|
+
checkpointNumber,
|
|
775
|
+
forcePendingCheckpointNumber: CheckpointNumber(checkpointNumber - 1),
|
|
329
776
|
reason
|
|
330
777
|
};
|
|
331
778
|
} catch (err) {
|
|
332
779
|
const viemError = formatViemError(err);
|
|
333
|
-
// If the error is due to the
|
|
334
|
-
// we can safely ignore it and return undefined so we go ahead with
|
|
780
|
+
// If the error is due to the checkpoint not being in the pending chain, and it was indeed removed by someone else,
|
|
781
|
+
// we can safely ignore it and return undefined so we go ahead with checkpoint building.
|
|
335
782
|
if (viemError.message?.includes('Rollup__BlockNotInPendingChain')) {
|
|
336
|
-
this.log.verbose(`Simulation for invalidate
|
|
783
|
+
this.log.verbose(`Simulation for invalidate checkpoint ${checkpointNumber} failed due to checkpoint not being in pending chain`, {
|
|
337
784
|
...logData,
|
|
338
785
|
request,
|
|
339
786
|
error: viemError.message
|
|
340
787
|
});
|
|
341
|
-
const
|
|
342
|
-
if (
|
|
343
|
-
this.log.verbose(`
|
|
788
|
+
const latestPendingCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
789
|
+
if (latestPendingCheckpointNumber < checkpointNumber) {
|
|
790
|
+
this.log.verbose(`Checkpoint ${checkpointNumber} has already been invalidated`, {
|
|
344
791
|
...logData
|
|
345
792
|
});
|
|
346
793
|
return undefined;
|
|
347
794
|
} else {
|
|
348
|
-
this.log.error(`Simulation for invalidate ${
|
|
349
|
-
throw new Error(`Failed to simulate invalidate
|
|
795
|
+
this.log.error(`Simulation for invalidate checkpoint ${checkpointNumber} failed and it is still in pending chain`, viemError, logData);
|
|
796
|
+
throw new Error(`Failed to simulate invalidate checkpoint ${checkpointNumber} while it is still in pending chain`, {
|
|
350
797
|
cause: viemError
|
|
351
798
|
});
|
|
352
799
|
}
|
|
353
800
|
}
|
|
354
|
-
// Otherwise, throw. We cannot build the next
|
|
355
|
-
this.log.error(`Simulation for invalidate
|
|
356
|
-
throw new Error(`Failed to simulate invalidate
|
|
801
|
+
// Otherwise, throw. We cannot build the next checkpoint if we cannot invalidate the previous one.
|
|
802
|
+
this.log.error(`Simulation for invalidate checkpoint ${checkpointNumber} failed`, viemError, logData);
|
|
803
|
+
throw new Error(`Failed to simulate invalidate checkpoint ${checkpointNumber}`, {
|
|
357
804
|
cause: viemError
|
|
358
805
|
});
|
|
359
806
|
}
|
|
360
807
|
}
|
|
361
|
-
|
|
808
|
+
buildInvalidateCheckpointRequest(validationResult) {
|
|
362
809
|
if (validationResult.valid) {
|
|
363
|
-
throw new Error('Cannot invalidate a valid
|
|
810
|
+
throw new Error('Cannot invalidate a valid checkpoint');
|
|
364
811
|
}
|
|
365
|
-
const {
|
|
812
|
+
const { checkpoint, committee, reason } = validationResult;
|
|
366
813
|
const logData = {
|
|
367
|
-
...
|
|
814
|
+
...checkpoint,
|
|
368
815
|
reason
|
|
369
816
|
};
|
|
370
|
-
this.log.debug(`
|
|
817
|
+
this.log.debug(`Building invalidate checkpoint ${checkpoint.checkpointNumber} request`, logData);
|
|
371
818
|
const attestationsAndSigners = new CommitteeAttestationsAndSigners(validationResult.attestations).getPackedAttestations();
|
|
372
819
|
if (reason === 'invalid-attestation') {
|
|
373
|
-
return this.rollupContract.buildInvalidateBadAttestationRequest(
|
|
820
|
+
return this.rollupContract.buildInvalidateBadAttestationRequest(checkpoint.checkpointNumber, attestationsAndSigners, committee, validationResult.invalidIndex);
|
|
374
821
|
} else if (reason === 'insufficient-attestations') {
|
|
375
|
-
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(
|
|
822
|
+
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(checkpoint.checkpointNumber, attestationsAndSigners, committee);
|
|
376
823
|
} else {
|
|
377
824
|
const _ = reason;
|
|
378
825
|
throw new Error(`Unknown reason for invalidation`);
|
|
379
826
|
}
|
|
380
827
|
}
|
|
381
|
-
/**
|
|
382
|
-
* @notice Will simulate `propose` to make sure that the block is valid for submission
|
|
383
|
-
*
|
|
384
|
-
* @dev Throws if unable to propose
|
|
385
|
-
*
|
|
386
|
-
* @param block - The block to propose
|
|
387
|
-
* @param attestationData - The block's attestation data
|
|
388
|
-
*
|
|
389
|
-
*/ async validateBlockForSubmission(block, attestationsAndSigners, attestationsAndSignersSignature, options) {
|
|
828
|
+
/** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, options) {
|
|
390
829
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
830
|
+
// TODO(palla/mbps): This should not be needed, there's no flow where we propose with zero attestations. Or is there?
|
|
391
831
|
// If we have no attestations, we still need to provide the empty attestations
|
|
392
832
|
// so that the committee is recalculated correctly
|
|
393
|
-
const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
394
|
-
if (ignoreSignatures) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
833
|
+
// const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
834
|
+
// if (ignoreSignatures) {
|
|
835
|
+
// const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
|
|
836
|
+
// if (!committee) {
|
|
837
|
+
// this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
838
|
+
// throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
839
|
+
// }
|
|
840
|
+
// attestationsAndSigners.attestations = committee.map(committeeMember =>
|
|
841
|
+
// CommitteeAttestation.fromAddress(committeeMember),
|
|
842
|
+
// );
|
|
843
|
+
// }
|
|
844
|
+
const blobFields = checkpoint.toBlobFields();
|
|
403
845
|
const blobs = getBlobsPerL1Block(blobFields);
|
|
404
846
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
405
847
|
const args = [
|
|
406
848
|
{
|
|
407
|
-
header:
|
|
408
|
-
archive: toHex(
|
|
849
|
+
header: checkpoint.header.toViem(),
|
|
850
|
+
archive: toHex(checkpoint.archive.root.toBuffer()),
|
|
409
851
|
oracleInput: {
|
|
410
852
|
feeAssetPriceModifier: 0n
|
|
411
853
|
}
|
|
@@ -432,9 +874,16 @@ export class SequencerPublisher {
|
|
|
432
874
|
}
|
|
433
875
|
const round = await base.computeRound(slotNumber);
|
|
434
876
|
const roundInfo = await base.getRoundInfo(this.rollupContract.address, round);
|
|
877
|
+
if (roundInfo.quorumReached) {
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
435
880
|
if (roundInfo.lastSignalSlot >= slotNumber) {
|
|
436
881
|
return false;
|
|
437
882
|
}
|
|
883
|
+
if (await this.isPayloadEmpty(payload)) {
|
|
884
|
+
this.log.warn(`Skipping vote cast for payload with empty code`);
|
|
885
|
+
return false;
|
|
886
|
+
}
|
|
438
887
|
const cachedLastVote = this.lastActions[signalType];
|
|
439
888
|
this.lastActions[signalType] = slotNumber;
|
|
440
889
|
const action = signalType;
|
|
@@ -473,17 +922,27 @@ export class SequencerPublisher {
|
|
|
473
922
|
payload: payload.toString()
|
|
474
923
|
};
|
|
475
924
|
if (!success) {
|
|
476
|
-
this.log.error(`Signaling in
|
|
925
|
+
this.log.error(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} failed`, logData);
|
|
477
926
|
this.lastActions[signalType] = cachedLastVote;
|
|
478
927
|
return false;
|
|
479
928
|
} else {
|
|
480
|
-
this.log.info(`Signaling in
|
|
929
|
+
this.log.info(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} succeeded`, logData);
|
|
481
930
|
return true;
|
|
482
931
|
}
|
|
483
932
|
}
|
|
484
933
|
});
|
|
485
934
|
return true;
|
|
486
935
|
}
|
|
936
|
+
async isPayloadEmpty(payload) {
|
|
937
|
+
const key = payload.toString();
|
|
938
|
+
const cached = this.isPayloadEmptyCache.get(key);
|
|
939
|
+
if (cached) {
|
|
940
|
+
return cached;
|
|
941
|
+
}
|
|
942
|
+
const isEmpty = !await this.l1TxUtils.getCode(payload);
|
|
943
|
+
this.isPayloadEmptyCache.set(key, isEmpty);
|
|
944
|
+
return isEmpty;
|
|
945
|
+
}
|
|
487
946
|
/**
|
|
488
947
|
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
489
948
|
* @param slotNumber - The slot number to cast a signal for.
|
|
@@ -579,19 +1038,13 @@ export class SequencerPublisher {
|
|
|
579
1038
|
}
|
|
580
1039
|
return true;
|
|
581
1040
|
}
|
|
582
|
-
/**
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
* @param block - L2 block to propose.
|
|
586
|
-
* @returns True if the tx has been enqueued, throws otherwise. See #9315
|
|
587
|
-
*/ async enqueueProposeL2Block(block, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
588
|
-
const checkpointHeader = block.getCheckpointHeader();
|
|
589
|
-
const blobFields = block.getCheckpointBlobFields();
|
|
1041
|
+
/** Simulates and enqueues a proposal for a checkpoint on L1 */ async enqueueProposeCheckpoint(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
1042
|
+
const checkpointHeader = checkpoint.header;
|
|
1043
|
+
const blobFields = checkpoint.toBlobFields();
|
|
590
1044
|
const blobs = getBlobsPerL1Block(blobFields);
|
|
591
1045
|
const proposeTxArgs = {
|
|
592
1046
|
header: checkpointHeader,
|
|
593
|
-
archive:
|
|
594
|
-
body: block.body.toBuffer(),
|
|
1047
|
+
archive: checkpoint.archive.root.toBuffer(),
|
|
595
1048
|
blobs,
|
|
596
1049
|
attestationsAndSigners,
|
|
597
1050
|
attestationsAndSignersSignature
|
|
@@ -603,36 +1056,35 @@ export class SequencerPublisher {
|
|
|
603
1056
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
604
1057
|
// make time consistency checks break.
|
|
605
1058
|
// TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
|
|
606
|
-
ts = await this.
|
|
1059
|
+
ts = await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
|
|
607
1060
|
} catch (err) {
|
|
608
|
-
this.log.error(`
|
|
609
|
-
...
|
|
610
|
-
slotNumber:
|
|
611
|
-
|
|
1061
|
+
this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
1062
|
+
...checkpoint.getStats(),
|
|
1063
|
+
slotNumber: checkpoint.header.slotNumber,
|
|
1064
|
+
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber
|
|
612
1065
|
});
|
|
613
1066
|
throw err;
|
|
614
1067
|
}
|
|
615
|
-
this.log.verbose(`Enqueuing
|
|
616
|
-
...
|
|
1068
|
+
this.log.verbose(`Enqueuing checkpoint propose transaction`, {
|
|
1069
|
+
...checkpoint.toCheckpointInfo(),
|
|
617
1070
|
...opts
|
|
618
1071
|
});
|
|
619
|
-
await this.addProposeTx(
|
|
620
|
-
return true;
|
|
1072
|
+
await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
|
|
621
1073
|
}
|
|
622
|
-
|
|
1074
|
+
enqueueInvalidateCheckpoint(request, opts = {}) {
|
|
623
1075
|
if (!request) {
|
|
624
1076
|
return;
|
|
625
1077
|
}
|
|
626
1078
|
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
627
1079
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(request.gasUsed) * 64 / 63)));
|
|
628
|
-
const { gasUsed,
|
|
1080
|
+
const { gasUsed, checkpointNumber } = request;
|
|
629
1081
|
const logData = {
|
|
630
1082
|
gasUsed,
|
|
631
|
-
|
|
1083
|
+
checkpointNumber,
|
|
632
1084
|
gasLimit,
|
|
633
1085
|
opts
|
|
634
1086
|
};
|
|
635
|
-
this.log.verbose(`Enqueuing invalidate
|
|
1087
|
+
this.log.verbose(`Enqueuing invalidate checkpoint request`, logData);
|
|
636
1088
|
this.addRequest({
|
|
637
1089
|
action: `invalidate-by-${request.reason}`,
|
|
638
1090
|
request: request.request,
|
|
@@ -644,12 +1096,12 @@ export class SequencerPublisher {
|
|
|
644
1096
|
checkSuccess: (_req, result)=>{
|
|
645
1097
|
const success = result && result.receipt && result.receipt.status === 'success' && tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointInvalidated');
|
|
646
1098
|
if (!success) {
|
|
647
|
-
this.log.warn(`Invalidate
|
|
1099
|
+
this.log.warn(`Invalidate checkpoint ${request.checkpointNumber} failed`, {
|
|
648
1100
|
...result,
|
|
649
1101
|
...logData
|
|
650
1102
|
});
|
|
651
1103
|
} else {
|
|
652
|
-
this.log.info(`Invalidate
|
|
1104
|
+
this.log.info(`Invalidate checkpoint ${request.checkpointNumber} succeeded`, {
|
|
653
1105
|
...result,
|
|
654
1106
|
...logData
|
|
655
1107
|
});
|
|
@@ -799,8 +1251,7 @@ export class SequencerPublisher {
|
|
|
799
1251
|
args
|
|
800
1252
|
});
|
|
801
1253
|
// override the pending checkpoint number if requested
|
|
802
|
-
const
|
|
803
|
-
const forcePendingCheckpointNumberStateDiff = (optsForcePendingCheckpointNumber !== undefined ? await this.rollupContract.makePendingCheckpointNumberOverride(optsForcePendingCheckpointNumber) : []).flatMap((override)=>override.stateDiff ?? []);
|
|
1254
|
+
const forcePendingCheckpointNumberStateDiff = (options.forcePendingCheckpointNumber !== undefined ? await this.rollupContract.makePendingCheckpointNumberOverride(options.forcePendingCheckpointNumber) : []).flatMap((override)=>override.stateDiff ?? []);
|
|
804
1255
|
const stateOverrides = [
|
|
805
1256
|
{
|
|
806
1257
|
address: this.rollupContract.address,
|
|
@@ -855,24 +1306,25 @@ export class SequencerPublisher {
|
|
|
855
1306
|
simulationResult
|
|
856
1307
|
};
|
|
857
1308
|
}
|
|
858
|
-
async addProposeTx(
|
|
1309
|
+
async addProposeTx(checkpoint, encodedData, opts = {}, timestamp) {
|
|
1310
|
+
const slot = checkpoint.header.slotNumber;
|
|
859
1311
|
const timer = new Timer();
|
|
860
1312
|
const kzg = Blob.getViemKzgInstance();
|
|
861
1313
|
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, timestamp, opts);
|
|
862
1314
|
const startBlock = await this.l1TxUtils.getBlockNumber();
|
|
863
1315
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
|
|
864
|
-
// Send the blobs to the blob
|
|
865
|
-
// tx fails but it does get mined. We make sure that the blobs are sent to the blob
|
|
866
|
-
void this.
|
|
867
|
-
|
|
868
|
-
|
|
1316
|
+
// Send the blobs to the blob client preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
|
|
1317
|
+
// tx fails but it does get mined. We make sure that the blobs are sent to the blob client regardless of the tx outcome.
|
|
1318
|
+
void Promise.resolve().then(()=>this.blobClient.sendBlobsToFilestore(encodedData.blobs).catch((_err)=>{
|
|
1319
|
+
this.log.error('Failed to send blobs to blob client');
|
|
1320
|
+
}));
|
|
869
1321
|
return this.addRequest({
|
|
870
1322
|
action: 'propose',
|
|
871
1323
|
request: {
|
|
872
1324
|
to: this.rollupContract.address,
|
|
873
1325
|
data: rollupData
|
|
874
1326
|
},
|
|
875
|
-
lastValidL2Slot:
|
|
1327
|
+
lastValidL2Slot: checkpoint.header.slotNumber,
|
|
876
1328
|
gasConfig: {
|
|
877
1329
|
...opts,
|
|
878
1330
|
gasLimit
|
|
@@ -900,25 +1352,23 @@ export class SequencerPublisher {
|
|
|
900
1352
|
calldataGas,
|
|
901
1353
|
calldataSize,
|
|
902
1354
|
sender,
|
|
903
|
-
...
|
|
1355
|
+
...checkpoint.getStats(),
|
|
904
1356
|
eventName: 'rollup-published-to-l1',
|
|
905
1357
|
blobCount: encodedData.blobs.length,
|
|
906
1358
|
inclusionBlocks
|
|
907
1359
|
};
|
|
908
|
-
this.log.info(`Published
|
|
1360
|
+
this.log.info(`Published checkpoint ${checkpoint.number} at slot ${slot} to rollup contract`, {
|
|
909
1361
|
...stats,
|
|
910
|
-
...
|
|
911
|
-
...receipt
|
|
1362
|
+
...checkpoint.getStats(),
|
|
1363
|
+
...pick(receipt, 'transactionHash', 'blockHash')
|
|
912
1364
|
});
|
|
913
1365
|
this.metrics.recordProcessBlockTx(timer.ms(), publishStats);
|
|
914
1366
|
return true;
|
|
915
1367
|
} else {
|
|
916
1368
|
this.metrics.recordFailedTx('process');
|
|
917
|
-
this.log.error(`
|
|
918
|
-
...
|
|
919
|
-
receipt
|
|
920
|
-
txHash: receipt.transactionHash,
|
|
921
|
-
slotNumber: block.header.globalVariables.slotNumber
|
|
1369
|
+
this.log.error(`Publishing checkpoint at slot ${slot} failed with ${errorMsg ?? 'no error message'}`, undefined, {
|
|
1370
|
+
...checkpoint.getStats(),
|
|
1371
|
+
...receipt
|
|
922
1372
|
});
|
|
923
1373
|
return false;
|
|
924
1374
|
}
|