@aztec/sequencer-client 4.0.0-nightly.20250907 → 4.0.0-nightly.20260108
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/index.d.ts +1 -1
- package/dest/client/sequencer-client.d.ts +10 -8
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +40 -28
- package/dest/config.d.ts +13 -5
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +82 -25
- package/dest/global_variable_builder/global_builder.d.ts +22 -16
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +52 -39
- package/dest/global_variable_builder/index.d.ts +1 -1
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/config.d.ts +11 -8
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +21 -13
- package/dest/publisher/index.d.ts +2 -2
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/index.js +1 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts +11 -5
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +9 -2
- package/dest/publisher/sequencer-publisher-metrics.d.ts +4 -4
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +1 -1
- package/dest/publisher/sequencer-publisher.d.ts +78 -70
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +687 -182
- package/dest/sequencer/block_builder.d.ts +6 -10
- package/dest/sequencer/block_builder.d.ts.map +1 -1
- package/dest/sequencer/block_builder.js +21 -10
- package/dest/sequencer/checkpoint_builder.d.ts +63 -0
- package/dest/sequencer/checkpoint_builder.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_builder.js +131 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts +76 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job.js +1070 -0
- package/dest/sequencer/checkpoint_voter.d.ts +34 -0
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_voter.js +85 -0
- package/dest/sequencer/config.d.ts +3 -2
- package/dest/sequencer/config.d.ts.map +1 -1
- package/dest/sequencer/errors.d.ts +11 -0
- package/dest/sequencer/errors.d.ts.map +1 -0
- package/dest/sequencer/errors.js +15 -0
- 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 +5 -1
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +4 -0
- package/dest/sequencer/metrics.d.ts +37 -20
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +211 -85
- package/dest/sequencer/sequencer.d.ts +110 -121
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +809 -524
- package/dest/sequencer/timetable.d.ts +57 -21
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +150 -68
- 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 +20 -28
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +12 -24
- package/dest/test/index.d.ts +4 -2
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +83 -0
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
- package/dest/test/mock_checkpoint_builder.js +179 -0
- package/dest/test/utils.d.ts +49 -0
- package/dest/test/utils.d.ts.map +1 -0
- package/dest/test/utils.js +94 -0
- package/dest/tx_validator/nullifier_cache.d.ts +1 -1
- package/dest/tx_validator/nullifier_cache.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.d.ts +4 -3
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +12 -9
- package/package.json +32 -31
- package/src/client/sequencer-client.ts +34 -40
- package/src/config.ts +89 -29
- package/src/global_variable_builder/global_builder.ts +67 -59
- package/src/index.ts +2 -0
- package/src/publisher/config.ts +32 -19
- package/src/publisher/index.ts +1 -1
- package/src/publisher/sequencer-publisher-factory.ts +19 -6
- package/src/publisher/sequencer-publisher-metrics.ts +3 -3
- package/src/publisher/sequencer-publisher.ts +418 -242
- package/src/sequencer/README.md +531 -0
- package/src/sequencer/block_builder.ts +28 -30
- package/src/sequencer/checkpoint_builder.ts +217 -0
- package/src/sequencer/checkpoint_proposal_job.ts +722 -0
- package/src/sequencer/checkpoint_voter.ts +105 -0
- package/src/sequencer/config.ts +2 -1
- package/src/sequencer/errors.ts +21 -0
- package/src/sequencer/events.ts +27 -0
- package/src/sequencer/index.ts +4 -0
- package/src/sequencer/metrics.ts +269 -94
- package/src/sequencer/sequencer.ts +508 -675
- package/src/sequencer/timetable.ts +181 -91
- package/src/sequencer/types.ts +6 -0
- package/src/sequencer/utils.ts +24 -29
- package/src/test/index.ts +3 -1
- package/src/test/mock_checkpoint_builder.ts +247 -0
- package/src/test/utils.ts +137 -0
- package/src/tx_validator/tx_validator_factory.ts +13 -7
|
@@ -1,25 +1,396 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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;
|
|
374
|
+
import { Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
|
|
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';
|
|
381
|
+
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
382
|
+
import { pick } from '@aztec/foundation/collection';
|
|
6
383
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
384
|
+
import { Signature } from '@aztec/foundation/eth-signature';
|
|
7
385
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
386
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
9
387
|
import { Timer } from '@aztec/foundation/timer';
|
|
10
388
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
11
389
|
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
15
|
-
import pick from 'lodash.pick';
|
|
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
|
-
export var SignalType = /*#__PURE__*/ function(SignalType) {
|
|
19
|
-
SignalType[SignalType["GOVERNANCE"] = 0] = "GOVERNANCE";
|
|
20
|
-
SignalType[SignalType["SLASHING"] = 1] = "SLASHING";
|
|
21
|
-
return SignalType;
|
|
22
|
-
}({});
|
|
23
394
|
export const Actions = [
|
|
24
395
|
'invalidate-by-invalid-attestation',
|
|
25
396
|
'invalidate-by-insufficient-attestations',
|
|
@@ -33,17 +404,40 @@ export const Actions = [
|
|
|
33
404
|
];
|
|
34
405
|
// Sorting for actions such that invalidations go before proposals, and proposals go before votes
|
|
35
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');
|
|
36
408
|
export class SequencerPublisher {
|
|
37
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
|
+
}
|
|
38
429
|
interrupted;
|
|
39
430
|
metrics;
|
|
40
431
|
epochCache;
|
|
41
432
|
governanceLog;
|
|
42
433
|
slashingLog;
|
|
43
|
-
|
|
434
|
+
lastActions;
|
|
435
|
+
isPayloadEmptyCache;
|
|
44
436
|
log;
|
|
45
437
|
ethereumSlotDuration;
|
|
46
|
-
|
|
438
|
+
blobClient;
|
|
439
|
+
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
440
|
+
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
47
441
|
// @note - with blobs, the below estimate seems too large.
|
|
48
442
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
49
443
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -57,25 +451,24 @@ export class SequencerPublisher {
|
|
|
57
451
|
govProposerContract;
|
|
58
452
|
slashingProposerContract;
|
|
59
453
|
slashFactoryContract;
|
|
454
|
+
tracer;
|
|
60
455
|
requests;
|
|
61
456
|
constructor(config, deps){
|
|
62
457
|
this.config = config;
|
|
63
|
-
this.interrupted = false;
|
|
458
|
+
this.interrupted = (_initProto(this), false);
|
|
64
459
|
this.governanceLog = createLogger('sequencer:publisher:governance');
|
|
65
460
|
this.slashingLog = createLogger('sequencer:publisher:slashing');
|
|
66
|
-
this.
|
|
67
|
-
|
|
68
|
-
[1]: 0n
|
|
69
|
-
};
|
|
70
|
-
this.log = createLogger('sequencer:publisher');
|
|
461
|
+
this.lastActions = {};
|
|
462
|
+
this.isPayloadEmptyCache = new Map();
|
|
71
463
|
this.requests = [];
|
|
464
|
+
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
72
465
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
73
466
|
this.epochCache = deps.epochCache;
|
|
74
|
-
this.
|
|
75
|
-
|
|
76
|
-
});
|
|
467
|
+
this.lastActions = deps.lastActions;
|
|
468
|
+
this.blobClient = deps.blobClient;
|
|
77
469
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
78
470
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
471
|
+
this.tracer = telemetry.getTracer('SequencerPublisher');
|
|
79
472
|
this.l1TxUtils = deps.l1TxUtils;
|
|
80
473
|
this.rollupContract = deps.rollupContract;
|
|
81
474
|
this.govProposerContract = deps.governanceProposerContract;
|
|
@@ -86,6 +479,10 @@ export class SequencerPublisher {
|
|
|
86
479
|
this.slashingProposerContract = newSlashingProposer;
|
|
87
480
|
});
|
|
88
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
|
+
}
|
|
89
486
|
}
|
|
90
487
|
getRollupContract() {
|
|
91
488
|
return this.rollupContract;
|
|
@@ -93,6 +490,17 @@ export class SequencerPublisher {
|
|
|
93
490
|
getSenderAddress() {
|
|
94
491
|
return this.l1TxUtils.getSenderAddress();
|
|
95
492
|
}
|
|
493
|
+
/**
|
|
494
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
495
|
+
*/ getL1FeeAnalyzer() {
|
|
496
|
+
return this.l1FeeAnalyzer;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Sets the proposer address to use for simulations in fisherman mode.
|
|
500
|
+
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
501
|
+
*/ setProposerAddressForSimulation(proposerAddress) {
|
|
502
|
+
this.proposerAddressForSimulation = proposerAddress;
|
|
503
|
+
}
|
|
96
504
|
addRequest(request) {
|
|
97
505
|
this.requests.push(request);
|
|
98
506
|
}
|
|
@@ -100,6 +508,55 @@ export class SequencerPublisher {
|
|
|
100
508
|
return this.epochCache.getEpochAndSlotNow().slot;
|
|
101
509
|
}
|
|
102
510
|
/**
|
|
511
|
+
* Clears all pending requests without sending them.
|
|
512
|
+
*/ clearPendingRequests() {
|
|
513
|
+
const count = this.requests.length;
|
|
514
|
+
this.requests = [];
|
|
515
|
+
if (count > 0) {
|
|
516
|
+
this.log.debug(`Cleared ${count} pending request(s)`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
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
|
+
/**
|
|
103
560
|
* Sends all requests that are still valid.
|
|
104
561
|
* @returns one of:
|
|
105
562
|
* - A receipt and stats if the tx succeeded
|
|
@@ -110,7 +567,7 @@ export class SequencerPublisher {
|
|
|
110
567
|
...this.requests
|
|
111
568
|
];
|
|
112
569
|
this.requests = [];
|
|
113
|
-
if (this.interrupted) {
|
|
570
|
+
if (this.interrupted || requestsToProcess.length === 0) {
|
|
114
571
|
return undefined;
|
|
115
572
|
}
|
|
116
573
|
const currentL2Slot = this.getCurrentL2Slot();
|
|
@@ -148,7 +605,7 @@ export class SequencerPublisher {
|
|
|
148
605
|
const gasLimit = gasLimits.length > 0 ? sumBigint(gasLimits) : undefined; // sum
|
|
149
606
|
const txTimeoutAts = gasConfigs.map((g)=>g?.txTimeoutAt).filter((g)=>g !== undefined);
|
|
150
607
|
const txTimeoutAt = txTimeoutAts.length > 0 ? new Date(Math.min(...txTimeoutAts.map((g)=>g.getTime()))) : undefined; // earliest
|
|
151
|
-
const
|
|
608
|
+
const txConfig = {
|
|
152
609
|
gasLimit,
|
|
153
610
|
txTimeoutAt
|
|
154
611
|
};
|
|
@@ -157,9 +614,10 @@ export class SequencerPublisher {
|
|
|
157
614
|
validRequests.sort((a, b)=>compareActions(a.action, b.action));
|
|
158
615
|
try {
|
|
159
616
|
this.log.debug('Forwarding transactions', {
|
|
160
|
-
validRequests: validRequests.map((request)=>request.action)
|
|
617
|
+
validRequests: validRequests.map((request)=>request.action),
|
|
618
|
+
txConfig
|
|
161
619
|
});
|
|
162
|
-
const result = await Multicall3.forward(validRequests.map((request)=>request.request), this.l1TxUtils,
|
|
620
|
+
const result = await Multicall3.forward(validRequests.map((request)=>request.request), this.l1TxUtils, txConfig, blobConfig, this.rollupContract.address, this.log);
|
|
163
621
|
const { successfulActions = [], failedActions = [] } = this.callbackBundledTransactions(validRequests, result);
|
|
164
622
|
return {
|
|
165
623
|
result,
|
|
@@ -218,7 +676,9 @@ export class SequencerPublisher {
|
|
|
218
676
|
'InvalidProposer',
|
|
219
677
|
'InvalidArchive'
|
|
220
678
|
];
|
|
221
|
-
return this.rollupContract.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), this.ethereumSlotDuration,
|
|
679
|
+
return this.rollupContract.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), Number(this.ethereumSlotDuration), {
|
|
680
|
+
forcePendingCheckpointNumber: opts.forcePendingBlockNumber !== undefined ? CheckpointNumber.fromBlockNumber(opts.forcePendingBlockNumber) : undefined
|
|
681
|
+
}).catch((err)=>{
|
|
222
682
|
if (err instanceof FormattedViemError && ignoredErrors.find((e)=>err.message.includes(e))) {
|
|
223
683
|
this.log.warn(`Failed canProposeAtTime check with ${ignoredErrors.find((e)=>err.message.includes(e))}`, {
|
|
224
684
|
error: err.message
|
|
@@ -241,16 +701,28 @@ export class SequencerPublisher {
|
|
|
241
701
|
};
|
|
242
702
|
const args = [
|
|
243
703
|
header.toViem(),
|
|
244
|
-
|
|
704
|
+
CommitteeAttestationsAndSigners.empty().getPackedAttestations(),
|
|
245
705
|
[],
|
|
706
|
+
Signature.empty().toViemSignature(),
|
|
246
707
|
`0x${'0'.repeat(64)}`,
|
|
247
708
|
header.contentCommitment.blobsHash.toString(),
|
|
248
709
|
flags
|
|
249
710
|
];
|
|
250
711
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
712
|
+
const optsForcePendingCheckpointNumber = opts?.forcePendingBlockNumber !== undefined ? CheckpointNumber.fromBlockNumber(opts.forcePendingBlockNumber) : undefined;
|
|
713
|
+
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(optsForcePendingCheckpointNumber);
|
|
714
|
+
let balance = 0n;
|
|
715
|
+
if (this.config.fishermanMode) {
|
|
716
|
+
// In fisherman mode, we can't know where the proposer is publishing from
|
|
717
|
+
// so we just add sufficient balance to the multicall3 address
|
|
718
|
+
balance = 10n * WEI_CONST * WEI_CONST; // 10 ETH
|
|
719
|
+
} else {
|
|
720
|
+
balance = await this.l1TxUtils.getSenderBalance();
|
|
721
|
+
}
|
|
722
|
+
stateOverrides.push({
|
|
723
|
+
address: MULTI_CALL_3_ADDRESS,
|
|
724
|
+
balance
|
|
725
|
+
});
|
|
254
726
|
await this.l1TxUtils.simulate({
|
|
255
727
|
to: this.rollupContract.address,
|
|
256
728
|
data: encodeFunctionData({
|
|
@@ -261,13 +733,7 @@ export class SequencerPublisher {
|
|
|
261
733
|
from: MULTI_CALL_3_ADDRESS
|
|
262
734
|
}, {
|
|
263
735
|
time: ts + 1n
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
address: MULTI_CALL_3_ADDRESS,
|
|
267
|
-
balance
|
|
268
|
-
},
|
|
269
|
-
...await this.rollupContract.makePendingBlockNumberOverride(opts?.forcePendingBlockNumber)
|
|
270
|
-
]);
|
|
736
|
+
}, stateOverrides);
|
|
271
737
|
this.log.debug(`Simulated validateHeader`);
|
|
272
738
|
}
|
|
273
739
|
/**
|
|
@@ -278,13 +744,13 @@ export class SequencerPublisher {
|
|
|
278
744
|
return undefined;
|
|
279
745
|
}
|
|
280
746
|
const { reason, block } = validationResult;
|
|
281
|
-
const blockNumber = block.
|
|
747
|
+
const blockNumber = block.blockNumber;
|
|
282
748
|
const logData = {
|
|
283
|
-
...block
|
|
749
|
+
...block,
|
|
284
750
|
reason
|
|
285
751
|
};
|
|
286
|
-
const currentBlockNumber = await this.rollupContract.
|
|
287
|
-
if (currentBlockNumber < validationResult.block.
|
|
752
|
+
const currentBlockNumber = await this.rollupContract.getCheckpointNumber();
|
|
753
|
+
if (currentBlockNumber < validationResult.block.blockNumber) {
|
|
288
754
|
this.log.verbose(`Skipping block ${blockNumber} invalidation since it has already been removed from the pending chain`, {
|
|
289
755
|
currentBlockNumber,
|
|
290
756
|
...logData
|
|
@@ -292,7 +758,10 @@ export class SequencerPublisher {
|
|
|
292
758
|
return undefined;
|
|
293
759
|
}
|
|
294
760
|
const request = this.buildInvalidateBlockRequest(validationResult);
|
|
295
|
-
this.log.debug(`Simulating invalidate block ${blockNumber}`,
|
|
761
|
+
this.log.debug(`Simulating invalidate block ${blockNumber}`, {
|
|
762
|
+
...logData,
|
|
763
|
+
request
|
|
764
|
+
});
|
|
296
765
|
try {
|
|
297
766
|
const { gasUsed } = await this.l1TxUtils.simulate(request, undefined, undefined, ErrorsAbi);
|
|
298
767
|
this.log.verbose(`Simulation for invalidate block ${blockNumber} succeeded`, {
|
|
@@ -304,7 +773,7 @@ export class SequencerPublisher {
|
|
|
304
773
|
request,
|
|
305
774
|
gasUsed,
|
|
306
775
|
blockNumber,
|
|
307
|
-
forcePendingBlockNumber: blockNumber - 1,
|
|
776
|
+
forcePendingBlockNumber: BlockNumber(blockNumber - 1),
|
|
308
777
|
reason
|
|
309
778
|
};
|
|
310
779
|
} catch (err) {
|
|
@@ -317,7 +786,7 @@ export class SequencerPublisher {
|
|
|
317
786
|
request,
|
|
318
787
|
error: viemError.message
|
|
319
788
|
});
|
|
320
|
-
const latestPendingBlockNumber = await this.rollupContract.
|
|
789
|
+
const latestPendingBlockNumber = await this.rollupContract.getCheckpointNumber();
|
|
321
790
|
if (latestPendingBlockNumber < blockNumber) {
|
|
322
791
|
this.log.verbose(`Block number ${blockNumber} has already been invalidated`, {
|
|
323
792
|
...logData
|
|
@@ -343,66 +812,58 @@ export class SequencerPublisher {
|
|
|
343
812
|
}
|
|
344
813
|
const { block, committee, reason } = validationResult;
|
|
345
814
|
const logData = {
|
|
346
|
-
...block
|
|
815
|
+
...block,
|
|
347
816
|
reason
|
|
348
817
|
};
|
|
349
|
-
this.log.debug(`Simulating invalidate block ${block.
|
|
818
|
+
this.log.debug(`Simulating invalidate block ${block.blockNumber}`, logData);
|
|
819
|
+
const attestationsAndSigners = new CommitteeAttestationsAndSigners(validationResult.attestations).getPackedAttestations();
|
|
350
820
|
if (reason === 'invalid-attestation') {
|
|
351
|
-
return this.rollupContract.buildInvalidateBadAttestationRequest(
|
|
821
|
+
return this.rollupContract.buildInvalidateBadAttestationRequest(CheckpointNumber.fromBlockNumber(block.blockNumber), attestationsAndSigners, committee, validationResult.invalidIndex);
|
|
352
822
|
} else if (reason === 'insufficient-attestations') {
|
|
353
|
-
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(
|
|
823
|
+
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(CheckpointNumber.fromBlockNumber(block.blockNumber), attestationsAndSigners, committee);
|
|
354
824
|
} else {
|
|
355
825
|
const _ = reason;
|
|
356
826
|
throw new Error(`Unknown reason for invalidation`);
|
|
357
827
|
}
|
|
358
828
|
}
|
|
359
|
-
/**
|
|
360
|
-
* @notice Will simulate `propose` to make sure that the block is valid for submission
|
|
361
|
-
*
|
|
362
|
-
* @dev Throws if unable to propose
|
|
363
|
-
*
|
|
364
|
-
* @param block - The block to propose
|
|
365
|
-
* @param attestationData - The block's attestation data
|
|
366
|
-
*
|
|
367
|
-
*/ async validateBlockForSubmission(block, attestationData = {
|
|
368
|
-
digest: Buffer.alloc(32),
|
|
369
|
-
attestations: []
|
|
370
|
-
}, options) {
|
|
829
|
+
/** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, options) {
|
|
371
830
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
831
|
+
// TODO(palla/mbps): This should not be needed, there's no flow where we propose with zero attestations. Or is there?
|
|
372
832
|
// If we have no attestations, we still need to provide the empty attestations
|
|
373
833
|
// so that the committee is recalculated correctly
|
|
374
|
-
const ignoreSignatures =
|
|
375
|
-
if (ignoreSignatures) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
const
|
|
834
|
+
// const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
835
|
+
// if (ignoreSignatures) {
|
|
836
|
+
// const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
|
|
837
|
+
// if (!committee) {
|
|
838
|
+
// this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
839
|
+
// throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
840
|
+
// }
|
|
841
|
+
// attestationsAndSigners.attestations = committee.map(committeeMember =>
|
|
842
|
+
// CommitteeAttestation.fromAddress(committeeMember),
|
|
843
|
+
// );
|
|
844
|
+
// }
|
|
845
|
+
const blobFields = checkpoint.toBlobFields();
|
|
846
|
+
const blobs = getBlobsPerL1Block(blobFields);
|
|
847
|
+
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
387
848
|
const args = [
|
|
388
849
|
{
|
|
389
|
-
header:
|
|
390
|
-
archive: toHex(
|
|
391
|
-
stateReference: block.header.state.toViem(),
|
|
392
|
-
txHashes: block.body.txEffects.map((txEffect)=>txEffect.txHash.toString()),
|
|
850
|
+
header: checkpoint.header.toViem(),
|
|
851
|
+
archive: toHex(checkpoint.archive.root.toBuffer()),
|
|
393
852
|
oracleInput: {
|
|
394
853
|
feeAssetPriceModifier: 0n
|
|
395
854
|
}
|
|
396
855
|
},
|
|
397
|
-
|
|
398
|
-
|
|
856
|
+
attestationsAndSigners.getPackedAttestations(),
|
|
857
|
+
attestationsAndSigners.getSigners().map((signer)=>signer.toString()),
|
|
858
|
+
attestationsAndSignersSignature.toViemSignature(),
|
|
399
859
|
blobInput
|
|
400
860
|
];
|
|
401
861
|
await this.simulateProposeTx(args, ts, options);
|
|
402
862
|
return ts;
|
|
403
863
|
}
|
|
404
864
|
async enqueueCastSignalHelper(slotNumber, timestamp, signalType, payload, base, signerAddress, signer) {
|
|
405
|
-
if (this.
|
|
865
|
+
if (this.lastActions[signalType] && this.lastActions[signalType] === slotNumber) {
|
|
866
|
+
this.log.debug(`Skipping duplicate vote cast signal ${signalType} for slot ${slotNumber}`);
|
|
406
867
|
return false;
|
|
407
868
|
}
|
|
408
869
|
if (payload.equals(EthAddress.ZERO)) {
|
|
@@ -414,12 +875,19 @@ export class SequencerPublisher {
|
|
|
414
875
|
}
|
|
415
876
|
const round = await base.computeRound(slotNumber);
|
|
416
877
|
const roundInfo = await base.getRoundInfo(this.rollupContract.address, round);
|
|
878
|
+
if (roundInfo.quorumReached) {
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
417
881
|
if (roundInfo.lastSignalSlot >= slotNumber) {
|
|
418
882
|
return false;
|
|
419
883
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
884
|
+
if (await this.isPayloadEmpty(payload)) {
|
|
885
|
+
this.log.warn(`Skipping vote cast for payload with empty code`);
|
|
886
|
+
return false;
|
|
887
|
+
}
|
|
888
|
+
const cachedLastVote = this.lastActions[signalType];
|
|
889
|
+
this.lastActions[signalType] = slotNumber;
|
|
890
|
+
const action = signalType;
|
|
423
891
|
const request = await base.createSignalRequestWithSignature(payload.toString(), slotNumber, this.config.l1ChainId, signerAddress.toString(), signer);
|
|
424
892
|
this.log.debug(`Created ${action} request with signature`, {
|
|
425
893
|
request,
|
|
@@ -455,24 +923,34 @@ export class SequencerPublisher {
|
|
|
455
923
|
payload: payload.toString()
|
|
456
924
|
};
|
|
457
925
|
if (!success) {
|
|
458
|
-
this.log.error(`Signaling in
|
|
459
|
-
this.
|
|
926
|
+
this.log.error(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} failed`, logData);
|
|
927
|
+
this.lastActions[signalType] = cachedLastVote;
|
|
460
928
|
return false;
|
|
461
929
|
} else {
|
|
462
|
-
this.log.info(`Signaling in
|
|
930
|
+
this.log.info(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} succeeded`, logData);
|
|
463
931
|
return true;
|
|
464
932
|
}
|
|
465
933
|
}
|
|
466
934
|
});
|
|
467
935
|
return true;
|
|
468
936
|
}
|
|
937
|
+
async isPayloadEmpty(payload) {
|
|
938
|
+
const key = payload.toString();
|
|
939
|
+
const cached = this.isPayloadEmptyCache.get(key);
|
|
940
|
+
if (cached) {
|
|
941
|
+
return cached;
|
|
942
|
+
}
|
|
943
|
+
const isEmpty = !await this.l1TxUtils.getCode(payload);
|
|
944
|
+
this.isPayloadEmptyCache.set(key, isEmpty);
|
|
945
|
+
return isEmpty;
|
|
946
|
+
}
|
|
469
947
|
/**
|
|
470
948
|
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
471
949
|
* @param slotNumber - The slot number to cast a signal for.
|
|
472
950
|
* @param timestamp - The timestamp of the slot to cast a signal for.
|
|
473
951
|
* @returns True if the signal was successfully enqueued, false otherwise.
|
|
474
952
|
*/ enqueueGovernanceCastSignal(governancePayload, slotNumber, timestamp, signerAddress, signer) {
|
|
475
|
-
return this.enqueueCastSignalHelper(slotNumber, timestamp,
|
|
953
|
+
return this.enqueueCastSignalHelper(slotNumber, timestamp, 'governance-signal', governancePayload, this.govProposerContract, signerAddress, signer);
|
|
476
954
|
}
|
|
477
955
|
/** Enqueues all slashing actions as returned by the slasher client. */ async enqueueSlashingActions(actions, slotNumber, timestamp, signerAddress, signer) {
|
|
478
956
|
if (actions.length === 0) {
|
|
@@ -490,7 +968,7 @@ export class SequencerPublisher {
|
|
|
490
968
|
this.log.debug(`Enqueuing slashing vote for payload ${action.payload} at slot ${slotNumber}`, {
|
|
491
969
|
signerAddress
|
|
492
970
|
});
|
|
493
|
-
await this.enqueueCastSignalHelper(slotNumber, timestamp,
|
|
971
|
+
await this.enqueueCastSignalHelper(slotNumber, timestamp, 'empire-slashing-signal', action.payload, this.slashingProposerContract, signerAddress, signer);
|
|
494
972
|
break;
|
|
495
973
|
}
|
|
496
974
|
case 'create-empire-payload':
|
|
@@ -561,24 +1039,16 @@ export class SequencerPublisher {
|
|
|
561
1039
|
}
|
|
562
1040
|
return true;
|
|
563
1041
|
}
|
|
564
|
-
/**
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
* @returns True if the tx has been enqueued, throws otherwise. See #9315
|
|
569
|
-
*/ async enqueueProposeL2Block(block, attestations, txHashes, opts = {}) {
|
|
570
|
-
const proposedBlockHeader = block.header.toPropose();
|
|
571
|
-
const consensusPayload = ConsensusPayload.fromBlock(block);
|
|
572
|
-
const digest = getHashedSignaturePayload(consensusPayload, SignatureDomainSeparator.blockAttestation);
|
|
573
|
-
const blobs = await Blob.getBlobsPerBlock(block.body.toBlobFields());
|
|
1042
|
+
/** Simulates and enqueues a proposal for a checkpoint on L1 */ async enqueueProposeCheckpoint(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
1043
|
+
const checkpointHeader = checkpoint.header;
|
|
1044
|
+
const blobFields = checkpoint.toBlobFields();
|
|
1045
|
+
const blobs = getBlobsPerL1Block(blobFields);
|
|
574
1046
|
const proposeTxArgs = {
|
|
575
|
-
header:
|
|
576
|
-
archive:
|
|
577
|
-
stateReference: block.header.state,
|
|
578
|
-
body: block.body.toBuffer(),
|
|
1047
|
+
header: checkpointHeader,
|
|
1048
|
+
archive: checkpoint.archive.root.toBuffer(),
|
|
579
1049
|
blobs,
|
|
580
|
-
|
|
581
|
-
|
|
1050
|
+
attestationsAndSigners,
|
|
1051
|
+
attestationsAndSignersSignature
|
|
582
1052
|
};
|
|
583
1053
|
let ts;
|
|
584
1054
|
try {
|
|
@@ -586,26 +1056,21 @@ export class SequencerPublisher {
|
|
|
586
1056
|
// This means that we can avoid the simulation issues in later checks.
|
|
587
1057
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
588
1058
|
// make time consistency checks break.
|
|
589
|
-
const attestationData = {
|
|
590
|
-
digest: digest.toBuffer(),
|
|
591
|
-
attestations: attestations ?? []
|
|
592
|
-
};
|
|
593
1059
|
// TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
|
|
594
|
-
ts = await this.
|
|
1060
|
+
ts = await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
|
|
595
1061
|
} catch (err) {
|
|
596
|
-
this.log.error(`
|
|
597
|
-
...
|
|
598
|
-
slotNumber:
|
|
1062
|
+
this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
1063
|
+
...checkpoint.getStats(),
|
|
1064
|
+
slotNumber: checkpoint.header.slotNumber,
|
|
599
1065
|
forcePendingBlockNumber: opts.forcePendingBlockNumber
|
|
600
1066
|
});
|
|
601
1067
|
throw err;
|
|
602
1068
|
}
|
|
603
|
-
this.log.verbose(`Enqueuing
|
|
604
|
-
...
|
|
1069
|
+
this.log.verbose(`Enqueuing checkpoint propose transaction`, {
|
|
1070
|
+
...checkpoint.toCheckpointInfo(),
|
|
605
1071
|
...opts
|
|
606
1072
|
});
|
|
607
|
-
await this.addProposeTx(
|
|
608
|
-
return true;
|
|
1073
|
+
await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
|
|
609
1074
|
}
|
|
610
1075
|
enqueueInvalidateBlock(request, opts = {}) {
|
|
611
1076
|
if (!request) {
|
|
@@ -613,8 +1078,10 @@ export class SequencerPublisher {
|
|
|
613
1078
|
}
|
|
614
1079
|
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
615
1080
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(request.gasUsed) * 64 / 63)));
|
|
1081
|
+
const { gasUsed, blockNumber } = request;
|
|
616
1082
|
const logData = {
|
|
617
|
-
|
|
1083
|
+
gasUsed,
|
|
1084
|
+
blockNumber,
|
|
618
1085
|
gasLimit,
|
|
619
1086
|
opts
|
|
620
1087
|
};
|
|
@@ -626,9 +1093,9 @@ export class SequencerPublisher {
|
|
|
626
1093
|
gasLimit,
|
|
627
1094
|
txTimeoutAt: opts.txTimeoutAt
|
|
628
1095
|
},
|
|
629
|
-
lastValidL2Slot: this.getCurrentL2Slot() +
|
|
1096
|
+
lastValidL2Slot: SlotNumber(this.getCurrentL2Slot() + 2),
|
|
630
1097
|
checkSuccess: (_req, result)=>{
|
|
631
|
-
const success = result && result.receipt && result.receipt.status === 'success' && tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, '
|
|
1098
|
+
const success = result && result.receipt && result.receipt.status === 'success' && tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointInvalidated');
|
|
632
1099
|
if (!success) {
|
|
633
1100
|
this.log.warn(`Invalidate block ${request.blockNumber} failed`, {
|
|
634
1101
|
...result,
|
|
@@ -650,8 +1117,14 @@ export class SequencerPublisher {
|
|
|
650
1117
|
timestamp,
|
|
651
1118
|
gasLimit: undefined
|
|
652
1119
|
};
|
|
1120
|
+
if (this.lastActions[action] && this.lastActions[action] === slotNumber) {
|
|
1121
|
+
this.log.debug(`Skipping duplicate action ${action} for slot ${slotNumber}`);
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
const cachedLastActionSlot = this.lastActions[action];
|
|
1125
|
+
this.lastActions[action] = slotNumber;
|
|
1126
|
+
this.log.debug(`Simulating ${action} for slot ${slotNumber}`, logData);
|
|
653
1127
|
let gasUsed;
|
|
654
|
-
this.log.debug(`Simulating ${action}`, logData);
|
|
655
1128
|
try {
|
|
656
1129
|
({ gasUsed } = await this.l1TxUtils.simulate(request, {
|
|
657
1130
|
time: timestamp
|
|
@@ -684,6 +1157,7 @@ export class SequencerPublisher {
|
|
|
684
1157
|
...result,
|
|
685
1158
|
...logData
|
|
686
1159
|
});
|
|
1160
|
+
this.lastActions[action] = cachedLastActionSlot;
|
|
687
1161
|
} else {
|
|
688
1162
|
this.log.info(`Action ${action} at ${slotNumber} succeeded`, {
|
|
689
1163
|
...result,
|
|
@@ -710,45 +1184,52 @@ export class SequencerPublisher {
|
|
|
710
1184
|
}
|
|
711
1185
|
async prepareProposeTx(encodedData, timestamp, options) {
|
|
712
1186
|
const kzg = Blob.getViemKzgInstance();
|
|
713
|
-
const blobInput =
|
|
1187
|
+
const blobInput = getPrefixedEthBlobCommitments(encodedData.blobs);
|
|
714
1188
|
this.log.debug('Validating blob input', {
|
|
715
1189
|
blobInput
|
|
716
1190
|
});
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
1191
|
+
// Get blob evaluation gas
|
|
1192
|
+
let blobEvaluationGas;
|
|
1193
|
+
if (this.config.fishermanMode) {
|
|
1194
|
+
// In fisherman mode, we can't estimate blob gas because estimateGas doesn't support state overrides
|
|
1195
|
+
// Use a fixed estimate.
|
|
1196
|
+
blobEvaluationGas = BigInt(encodedData.blobs.length) * 21_000n;
|
|
1197
|
+
this.log.debug(`Using fixed blob evaluation gas estimate in fisherman mode: ${blobEvaluationGas}`);
|
|
1198
|
+
} else {
|
|
1199
|
+
// Normal mode - use estimateGas with blob inputs
|
|
1200
|
+
blobEvaluationGas = await this.l1TxUtils.estimateGas(this.getSenderAddress().toString(), {
|
|
1201
|
+
to: this.rollupContract.address,
|
|
1202
|
+
data: encodeFunctionData({
|
|
1203
|
+
abi: RollupAbi,
|
|
1204
|
+
functionName: 'validateBlobs',
|
|
1205
|
+
args: [
|
|
1206
|
+
blobInput
|
|
1207
|
+
]
|
|
1208
|
+
})
|
|
1209
|
+
}, {}, {
|
|
1210
|
+
blobs: encodedData.blobs.map((b)=>b.data),
|
|
1211
|
+
kzg
|
|
1212
|
+
}).catch((err)=>{
|
|
1213
|
+
const { message, metaMessages } = formatViemError(err);
|
|
1214
|
+
this.log.error(`Failed to validate blobs`, message, {
|
|
1215
|
+
metaMessages
|
|
1216
|
+
});
|
|
1217
|
+
throw new Error('Failed to validate blobs');
|
|
733
1218
|
});
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
const attestations = encodedData.attestations ? encodedData.attestations.map((attest)=>attest.toViem()) : [];
|
|
737
|
-
const txHashes = encodedData.txHashes ? encodedData.txHashes.map((txHash)=>txHash.toString()) : [];
|
|
738
|
-
const signers = encodedData.attestations?.filter((attest)=>!attest.signature.isEmpty()).map((attest)=>attest.address.toString());
|
|
1219
|
+
}
|
|
1220
|
+
const signers = encodedData.attestationsAndSigners.getSigners().map((signer)=>signer.toString());
|
|
739
1221
|
const args = [
|
|
740
1222
|
{
|
|
741
1223
|
header: encodedData.header.toViem(),
|
|
742
1224
|
archive: toHex(encodedData.archive),
|
|
743
|
-
stateReference: encodedData.stateReference.toViem(),
|
|
744
1225
|
oracleInput: {
|
|
745
1226
|
// We are currently not modifying these. See #9963
|
|
746
1227
|
feeAssetPriceModifier: 0n
|
|
747
|
-
}
|
|
748
|
-
txHashes
|
|
1228
|
+
}
|
|
749
1229
|
},
|
|
750
|
-
|
|
751
|
-
signers
|
|
1230
|
+
encodedData.attestationsAndSigners.getPackedAttestations(),
|
|
1231
|
+
signers,
|
|
1232
|
+
encodedData.attestationsAndSignersSignature.toViemSignature(),
|
|
752
1233
|
blobInput
|
|
753
1234
|
];
|
|
754
1235
|
const { rollupData, simulationResult } = await this.simulateProposeTx(args, timestamp, options);
|
|
@@ -770,18 +1251,10 @@ export class SequencerPublisher {
|
|
|
770
1251
|
functionName: 'propose',
|
|
771
1252
|
args
|
|
772
1253
|
});
|
|
773
|
-
// override the pending
|
|
774
|
-
const
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
data: rollupData,
|
|
778
|
-
gas: SequencerPublisher.PROPOSE_GAS_GUESS
|
|
779
|
-
}, {
|
|
780
|
-
// @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
|
|
781
|
-
time: timestamp + 1n,
|
|
782
|
-
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
|
|
783
|
-
gasLimit: SequencerPublisher.PROPOSE_GAS_GUESS * 2n
|
|
784
|
-
}, [
|
|
1254
|
+
// override the pending checkpoint number if requested
|
|
1255
|
+
const optsForcePendingCheckpointNumber = options.forcePendingBlockNumber !== undefined ? CheckpointNumber.fromBlockNumber(options.forcePendingBlockNumber) : undefined;
|
|
1256
|
+
const forcePendingCheckpointNumberStateDiff = (optsForcePendingCheckpointNumber !== undefined ? await this.rollupContract.makePendingCheckpointNumberOverride(optsForcePendingCheckpointNumber) : []).flatMap((override)=>override.stateDiff ?? []);
|
|
1257
|
+
const stateOverrides = [
|
|
785
1258
|
{
|
|
786
1259
|
address: this.rollupContract.address,
|
|
787
1260
|
// @note we override checkBlob to false since blobs are not part simulate()
|
|
@@ -790,14 +1263,44 @@ export class SequencerPublisher {
|
|
|
790
1263
|
slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true),
|
|
791
1264
|
value: toPaddedHex(0n, true)
|
|
792
1265
|
},
|
|
793
|
-
...
|
|
1266
|
+
...forcePendingCheckpointNumberStateDiff
|
|
794
1267
|
]
|
|
795
1268
|
}
|
|
796
|
-
]
|
|
1269
|
+
];
|
|
1270
|
+
// In fisherman mode, simulate as the proposer but with sufficient balance
|
|
1271
|
+
if (this.proposerAddressForSimulation) {
|
|
1272
|
+
stateOverrides.push({
|
|
1273
|
+
address: this.proposerAddressForSimulation.toString(),
|
|
1274
|
+
balance: 10n * WEI_CONST * WEI_CONST
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
const simulationResult = await this.l1TxUtils.simulate({
|
|
1278
|
+
to: this.rollupContract.address,
|
|
1279
|
+
data: rollupData,
|
|
1280
|
+
gas: SequencerPublisher.PROPOSE_GAS_GUESS,
|
|
1281
|
+
...this.proposerAddressForSimulation && {
|
|
1282
|
+
from: this.proposerAddressForSimulation.toString()
|
|
1283
|
+
}
|
|
1284
|
+
}, {
|
|
1285
|
+
// @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
|
|
1286
|
+
time: timestamp + 1n,
|
|
1287
|
+
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
|
|
1288
|
+
gasLimit: SequencerPublisher.PROPOSE_GAS_GUESS * 2n
|
|
1289
|
+
}, stateOverrides, RollupAbi, {
|
|
797
1290
|
// @note fallback gas estimate to use if the node doesn't support simulation API
|
|
798
1291
|
fallbackGasEstimate: SequencerPublisher.PROPOSE_GAS_GUESS
|
|
799
1292
|
}).catch((err)=>{
|
|
800
|
-
|
|
1293
|
+
// In fisherman mode, we expect ValidatorSelection__MissingProposerSignature since fisherman doesn't have proposer signature
|
|
1294
|
+
const viemError = formatViemError(err);
|
|
1295
|
+
if (this.config.fishermanMode && viemError.message?.includes('ValidatorSelection__MissingProposerSignature')) {
|
|
1296
|
+
this.log.debug(`Ignoring expected ValidatorSelection__MissingProposerSignature error in fisherman mode`);
|
|
1297
|
+
// Return a minimal simulation result with the fallback gas estimate
|
|
1298
|
+
return {
|
|
1299
|
+
gasUsed: SequencerPublisher.PROPOSE_GAS_GUESS,
|
|
1300
|
+
logs: []
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
this.log.error(`Failed to simulate propose tx`, viemError);
|
|
801
1304
|
throw err;
|
|
802
1305
|
});
|
|
803
1306
|
return {
|
|
@@ -805,24 +1308,25 @@ export class SequencerPublisher {
|
|
|
805
1308
|
simulationResult
|
|
806
1309
|
};
|
|
807
1310
|
}
|
|
808
|
-
async addProposeTx(
|
|
1311
|
+
async addProposeTx(checkpoint, encodedData, opts = {}, timestamp) {
|
|
1312
|
+
const slot = checkpoint.header.slotNumber;
|
|
809
1313
|
const timer = new Timer();
|
|
810
1314
|
const kzg = Blob.getViemKzgInstance();
|
|
811
1315
|
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, timestamp, opts);
|
|
812
1316
|
const startBlock = await this.l1TxUtils.getBlockNumber();
|
|
813
1317
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
|
|
814
|
-
// Send the blobs to the blob
|
|
815
|
-
// tx fails but it does get mined. We make sure that the blobs are sent to the blob
|
|
816
|
-
void this.
|
|
817
|
-
|
|
818
|
-
|
|
1318
|
+
// Send the blobs to the blob client preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
|
|
1319
|
+
// tx fails but it does get mined. We make sure that the blobs are sent to the blob client regardless of the tx outcome.
|
|
1320
|
+
void Promise.resolve().then(()=>this.blobClient.sendBlobsToFilestore(encodedData.blobs).catch((_err)=>{
|
|
1321
|
+
this.log.error('Failed to send blobs to blob client');
|
|
1322
|
+
}));
|
|
819
1323
|
return this.addRequest({
|
|
820
1324
|
action: 'propose',
|
|
821
1325
|
request: {
|
|
822
1326
|
to: this.rollupContract.address,
|
|
823
1327
|
data: rollupData
|
|
824
1328
|
},
|
|
825
|
-
lastValidL2Slot:
|
|
1329
|
+
lastValidL2Slot: checkpoint.header.slotNumber,
|
|
826
1330
|
gasConfig: {
|
|
827
1331
|
...opts,
|
|
828
1332
|
gasLimit
|
|
@@ -836,36 +1340,37 @@ export class SequencerPublisher {
|
|
|
836
1340
|
return false;
|
|
837
1341
|
}
|
|
838
1342
|
const { receipt, stats, errorMsg } = result;
|
|
839
|
-
const success = receipt && receipt.status === 'success' && tryExtractEvent(receipt.logs, this.rollupContract.address, RollupAbi, '
|
|
1343
|
+
const success = receipt && receipt.status === 'success' && tryExtractEvent(receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointProposed');
|
|
840
1344
|
if (success) {
|
|
841
1345
|
const endBlock = receipt.blockNumber;
|
|
842
1346
|
const inclusionBlocks = Number(endBlock - startBlock);
|
|
1347
|
+
const { calldataGas, calldataSize, sender } = stats;
|
|
843
1348
|
const publishStats = {
|
|
844
1349
|
gasPrice: receipt.effectiveGasPrice,
|
|
845
1350
|
gasUsed: receipt.gasUsed,
|
|
846
1351
|
blobGasUsed: receipt.blobGasUsed ?? 0n,
|
|
847
1352
|
blobDataGas: receipt.blobGasPrice ?? 0n,
|
|
848
1353
|
transactionHash: receipt.transactionHash,
|
|
849
|
-
|
|
850
|
-
|
|
1354
|
+
calldataGas,
|
|
1355
|
+
calldataSize,
|
|
1356
|
+
sender,
|
|
1357
|
+
...checkpoint.getStats(),
|
|
851
1358
|
eventName: 'rollup-published-to-l1',
|
|
852
1359
|
blobCount: encodedData.blobs.length,
|
|
853
1360
|
inclusionBlocks
|
|
854
1361
|
};
|
|
855
|
-
this.log.info(`Published
|
|
1362
|
+
this.log.info(`Published checkpoint ${checkpoint.number} at slot ${slot} to rollup contract`, {
|
|
856
1363
|
...stats,
|
|
857
|
-
...
|
|
858
|
-
...receipt
|
|
1364
|
+
...checkpoint.getStats(),
|
|
1365
|
+
...pick(receipt, 'transactionHash', 'blockHash')
|
|
859
1366
|
});
|
|
860
1367
|
this.metrics.recordProcessBlockTx(timer.ms(), publishStats);
|
|
861
1368
|
return true;
|
|
862
1369
|
} else {
|
|
863
1370
|
this.metrics.recordFailedTx('process');
|
|
864
|
-
this.log.error(`
|
|
865
|
-
...
|
|
866
|
-
receipt
|
|
867
|
-
txHash: receipt.transactionHash,
|
|
868
|
-
slotNumber: block.header.globalVariables.slotNumber.toBigInt()
|
|
1371
|
+
this.log.error(`Publishing checkpoint at slot ${slot} failed with ${errorMsg ?? 'no error message'}`, undefined, {
|
|
1372
|
+
...checkpoint.getStats(),
|
|
1373
|
+
...receipt
|
|
869
1374
|
});
|
|
870
1375
|
return false;
|
|
871
1376
|
}
|