@aztec/sequencer-client 0.0.1-commit.c7c42ec → 0.0.1-commit.c949de6bc
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 +14 -10
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +15 -4
- package/dest/config.d.ts +3 -4
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +22 -12
- package/dest/global_variable_builder/global_builder.d.ts +5 -7
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +13 -13
- package/dest/index.d.ts +2 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/config.d.ts +35 -17
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +106 -42
- package/dest/publisher/index.d.ts +2 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/l1_tx_failed_store/factory.d.ts +11 -0
- package/dest/publisher/l1_tx_failed_store/factory.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/factory.js +22 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +59 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.js +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts +15 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/file_store_failed_tx_store.js +34 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts +4 -0
- package/dest/publisher/l1_tx_failed_store/index.d.ts.map +1 -0
- package/dest/publisher/l1_tx_failed_store/index.js +2 -0
- package/dest/publisher/sequencer-publisher-factory.d.ts +11 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +13 -2
- package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +23 -86
- package/dest/publisher/sequencer-publisher.d.ts +38 -23
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +739 -96
- package/dest/sequencer/checkpoint_proposal_job.d.ts +40 -12
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +641 -64
- package/dest/sequencer/checkpoint_voter.d.ts +3 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +34 -10
- package/dest/sequencer/index.d.ts +1 -3
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +0 -2
- package/dest/sequencer/metrics.d.ts +19 -7
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +131 -141
- package/dest/sequencer/sequencer.d.ts +38 -18
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +513 -66
- package/dest/sequencer/timetable.d.ts +1 -4
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +2 -5
- package/dest/test/index.d.ts +4 -7
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +25 -11
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +52 -9
- package/dest/test/utils.d.ts +13 -9
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +27 -17
- package/package.json +30 -28
- package/src/client/sequencer-client.ts +28 -11
- package/src/config.ts +31 -19
- package/src/global_variable_builder/global_builder.ts +14 -14
- package/src/index.ts +1 -9
- package/src/publisher/config.ts +121 -43
- package/src/publisher/index.ts +3 -0
- package/src/publisher/l1_tx_failed_store/factory.ts +32 -0
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +55 -0
- package/src/publisher/l1_tx_failed_store/file_store_failed_tx_store.ts +46 -0
- package/src/publisher/l1_tx_failed_store/index.ts +3 -0
- package/src/publisher/sequencer-publisher-factory.ts +23 -6
- package/src/publisher/sequencer-publisher-metrics.ts +17 -69
- package/src/publisher/sequencer-publisher.ts +358 -126
- package/src/sequencer/checkpoint_proposal_job.ts +313 -93
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/metrics.ts +132 -148
- package/src/sequencer/sequencer.ts +159 -68
- package/src/sequencer/timetable.ts +7 -6
- package/src/test/index.ts +3 -6
- package/src/test/mock_checkpoint_builder.ts +102 -29
- package/src/test/utils.ts +58 -28
- package/dest/sequencer/block_builder.d.ts +0 -26
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -129
- package/dest/sequencer/checkpoint_builder.d.ts +0 -63
- package/dest/sequencer/checkpoint_builder.d.ts.map +0 -1
- package/dest/sequencer/checkpoint_builder.js +0 -131
- package/dest/tx_validator/nullifier_cache.d.ts +0 -14
- package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
- package/dest/tx_validator/nullifier_cache.js +0 -24
- package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -53
- package/src/sequencer/block_builder.ts +0 -217
- package/src/sequencer/checkpoint_builder.ts +0 -217
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -133
|
@@ -1,22 +1,397 @@
|
|
|
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 { MULTI_CALL_3_ADDRESS, Multicall3, RollupContract } from '@aztec/ethereum/contracts';
|
|
375
|
+
import { FeeAssetPriceOracle, MULTI_CALL_3_ADDRESS, Multicall3, RollupContract } from '@aztec/ethereum/contracts';
|
|
3
376
|
import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
4
|
-
import { WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
|
|
5
|
-
import { FormattedViemError, formatViemError, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
377
|
+
import { MAX_L1_TX_LIMIT, WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
|
|
378
|
+
import { FormattedViemError, formatViemError, mergeAbis, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
6
379
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
7
380
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
8
|
-
import {
|
|
381
|
+
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
9
382
|
import { pick } from '@aztec/foundation/collection';
|
|
10
383
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
11
384
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
12
385
|
import { createLogger } from '@aztec/foundation/log';
|
|
386
|
+
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
13
387
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
14
388
|
import { Timer } from '@aztec/foundation/timer';
|
|
15
389
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
16
390
|
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
17
391
|
import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
18
|
-
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
19
|
-
import { encodeFunctionData, toHex } from 'viem';
|
|
392
|
+
import { getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
393
|
+
import { encodeFunctionData, keccak256, multicall3Abi, toHex } from 'viem';
|
|
394
|
+
import { createL1TxFailedStore } from './l1_tx_failed_store/index.js';
|
|
20
395
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
21
396
|
export const Actions = [
|
|
22
397
|
'invalidate-by-invalid-attestation',
|
|
@@ -31,24 +406,43 @@ export const Actions = [
|
|
|
31
406
|
];
|
|
32
407
|
// Sorting for actions such that invalidations go before proposals, and proposals go before votes
|
|
33
408
|
export const compareActions = (a, b)=>Actions.indexOf(a) - Actions.indexOf(b);
|
|
409
|
+
_dec = trackSpan('SequencerPublisher.sendRequests'), _dec1 = trackSpan('SequencerPublisher.validateBlockHeader'), _dec2 = trackSpan('SequencerPublisher.validateCheckpointForSubmission');
|
|
34
410
|
export class SequencerPublisher {
|
|
35
411
|
config;
|
|
412
|
+
static{
|
|
413
|
+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
414
|
+
[
|
|
415
|
+
_dec,
|
|
416
|
+
2,
|
|
417
|
+
"sendRequests"
|
|
418
|
+
],
|
|
419
|
+
[
|
|
420
|
+
_dec1,
|
|
421
|
+
2,
|
|
422
|
+
"validateBlockHeader"
|
|
423
|
+
],
|
|
424
|
+
[
|
|
425
|
+
_dec2,
|
|
426
|
+
2,
|
|
427
|
+
"validateCheckpointForSubmission"
|
|
428
|
+
]
|
|
429
|
+
], []));
|
|
430
|
+
}
|
|
36
431
|
interrupted;
|
|
37
432
|
metrics;
|
|
38
433
|
epochCache;
|
|
434
|
+
failedTxStore;
|
|
39
435
|
governanceLog;
|
|
40
436
|
slashingLog;
|
|
41
437
|
lastActions;
|
|
42
438
|
isPayloadEmptyCache;
|
|
439
|
+
payloadProposedCache;
|
|
43
440
|
log;
|
|
44
441
|
ethereumSlotDuration;
|
|
45
442
|
blobClient;
|
|
46
443
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
47
444
|
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
48
|
-
|
|
49
|
-
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
50
|
-
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
51
|
-
static PROPOSE_GAS_GUESS = 12_000_000n;
|
|
445
|
+
/** Fee asset price oracle for computing price modifiers from Uniswap V4 */ feeAssetPriceOracle;
|
|
52
446
|
// A CALL to a cold address is 2700 gas
|
|
53
447
|
static MULTICALL_OVERHEAD_GAS_GUESS = 5000n;
|
|
54
448
|
// Gas report for VotingWithSigTest shows a max gas of 100k, but we've seen it cost 700k+ in testnet
|
|
@@ -58,14 +452,16 @@ export class SequencerPublisher {
|
|
|
58
452
|
govProposerContract;
|
|
59
453
|
slashingProposerContract;
|
|
60
454
|
slashFactoryContract;
|
|
455
|
+
tracer;
|
|
61
456
|
requests;
|
|
62
457
|
constructor(config, deps){
|
|
63
458
|
this.config = config;
|
|
64
|
-
this.interrupted = false;
|
|
459
|
+
this.interrupted = (_initProto(this), false);
|
|
65
460
|
this.governanceLog = createLogger('sequencer:publisher:governance');
|
|
66
461
|
this.slashingLog = createLogger('sequencer:publisher:slashing');
|
|
67
462
|
this.lastActions = {};
|
|
68
463
|
this.isPayloadEmptyCache = new Map();
|
|
464
|
+
this.payloadProposedCache = new Set();
|
|
69
465
|
this.requests = [];
|
|
70
466
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
71
467
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
@@ -74,6 +470,7 @@ export class SequencerPublisher {
|
|
|
74
470
|
this.blobClient = deps.blobClient;
|
|
75
471
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
76
472
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
473
|
+
this.tracer = telemetry.getTracer('SequencerPublisher');
|
|
77
474
|
this.l1TxUtils = deps.l1TxUtils;
|
|
78
475
|
this.rollupContract = deps.rollupContract;
|
|
79
476
|
this.govProposerContract = deps.governanceProposerContract;
|
|
@@ -88,10 +485,36 @@ export class SequencerPublisher {
|
|
|
88
485
|
if (config.fishermanMode) {
|
|
89
486
|
this.l1FeeAnalyzer = new L1FeeAnalyzer(this.l1TxUtils.client, deps.dateProvider, createLogger('sequencer:publisher:fee-analyzer'));
|
|
90
487
|
}
|
|
488
|
+
// Initialize fee asset price oracle
|
|
489
|
+
this.feeAssetPriceOracle = new FeeAssetPriceOracle(this.l1TxUtils.client, this.rollupContract, createLogger('sequencer:publisher:price-oracle'));
|
|
490
|
+
// Initialize failed L1 tx store (optional, for test networks)
|
|
491
|
+
this.failedTxStore = createL1TxFailedStore(config.l1TxFailedStore, this.log);
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Backs up a failed L1 transaction to the configured store for debugging.
|
|
495
|
+
* Does nothing if no store is configured.
|
|
496
|
+
*/ backupFailedTx(failedTx) {
|
|
497
|
+
if (!this.failedTxStore) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
const tx = {
|
|
501
|
+
...failedTx,
|
|
502
|
+
timestamp: Date.now()
|
|
503
|
+
};
|
|
504
|
+
// Fire and forget - don't block on backup
|
|
505
|
+
void this.failedTxStore.then((store)=>store?.saveFailedTx(tx)).catch((err)=>{
|
|
506
|
+
this.log.warn(`Failed to backup failed L1 tx to store`, err);
|
|
507
|
+
});
|
|
91
508
|
}
|
|
92
509
|
getRollupContract() {
|
|
93
510
|
return this.rollupContract;
|
|
94
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Gets the fee asset price modifier from the oracle.
|
|
514
|
+
* Returns 0n if the oracle query fails.
|
|
515
|
+
*/ getFeeAssetPriceModifier() {
|
|
516
|
+
return this.feeAssetPriceOracle.computePriceModifier();
|
|
517
|
+
}
|
|
95
518
|
getSenderAddress() {
|
|
96
519
|
return this.l1TxUtils.getSenderAddress();
|
|
97
520
|
}
|
|
@@ -149,7 +572,7 @@ export class SequencerPublisher {
|
|
|
149
572
|
// Get the transaction requests
|
|
150
573
|
const l1Requests = requestsToAnalyze.map((r)=>r.request);
|
|
151
574
|
// Start the analysis
|
|
152
|
-
const analysisId = await this.l1FeeAnalyzer.startAnalysis(l2SlotNumber, gasLimit > 0n ? gasLimit :
|
|
575
|
+
const analysisId = await this.l1FeeAnalyzer.startAnalysis(l2SlotNumber, gasLimit > 0n ? gasLimit : MAX_L1_TX_LIMIT, l1Requests, blobConfig, onComplete);
|
|
153
576
|
this.log.info('Started L1 fee analysis', {
|
|
154
577
|
analysisId,
|
|
155
578
|
l2SlotNumber: l2SlotNumber.toString(),
|
|
@@ -207,7 +630,16 @@ export class SequencerPublisher {
|
|
|
207
630
|
const blobConfig = blobConfigs[0];
|
|
208
631
|
// Merge gasConfigs. Yields the sum of gasLimits, and the earliest txTimeoutAt, or undefined if no gasConfig sets them.
|
|
209
632
|
const gasLimits = gasConfigs.map((g)=>g?.gasLimit).filter((g)=>g !== undefined);
|
|
210
|
-
|
|
633
|
+
let gasLimit = gasLimits.length > 0 ? sumBigint(gasLimits) : undefined; // sum
|
|
634
|
+
// Cap at L1 block gas limit so the node accepts the tx ("gas limit too high" otherwise).
|
|
635
|
+
const maxGas = MAX_L1_TX_LIMIT;
|
|
636
|
+
if (gasLimit !== undefined && gasLimit > maxGas) {
|
|
637
|
+
this.log.debug('Capping bundled tx gas limit to L1 max', {
|
|
638
|
+
requested: gasLimit,
|
|
639
|
+
capped: maxGas
|
|
640
|
+
});
|
|
641
|
+
gasLimit = maxGas;
|
|
642
|
+
}
|
|
211
643
|
const txTimeoutAts = gasConfigs.map((g)=>g?.txTimeoutAt).filter((g)=>g !== undefined);
|
|
212
644
|
const txTimeoutAt = txTimeoutAts.length > 0 ? new Date(Math.min(...txTimeoutAts.map((g)=>g.getTime()))) : undefined; // earliest
|
|
213
645
|
const txConfig = {
|
|
@@ -218,12 +650,31 @@ export class SequencerPublisher {
|
|
|
218
650
|
// This ensures the committee gets precomputed correctly
|
|
219
651
|
validRequests.sort((a, b)=>compareActions(a.action, b.action));
|
|
220
652
|
try {
|
|
653
|
+
// Capture context for failed tx backup before sending
|
|
654
|
+
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
655
|
+
const multicallData = encodeFunctionData({
|
|
656
|
+
abi: multicall3Abi,
|
|
657
|
+
functionName: 'aggregate3',
|
|
658
|
+
args: [
|
|
659
|
+
validRequests.map((r)=>({
|
|
660
|
+
target: r.request.to,
|
|
661
|
+
callData: r.request.data,
|
|
662
|
+
allowFailure: true
|
|
663
|
+
}))
|
|
664
|
+
]
|
|
665
|
+
});
|
|
666
|
+
const blobDataHex = blobConfig?.blobs?.map((b)=>toHex(b));
|
|
221
667
|
this.log.debug('Forwarding transactions', {
|
|
222
668
|
validRequests: validRequests.map((request)=>request.action),
|
|
223
669
|
txConfig
|
|
224
670
|
});
|
|
225
671
|
const result = await Multicall3.forward(validRequests.map((request)=>request.request), this.l1TxUtils, txConfig, blobConfig, this.rollupContract.address, this.log);
|
|
226
|
-
const
|
|
672
|
+
const txContext = {
|
|
673
|
+
multicallData,
|
|
674
|
+
blobData: blobDataHex,
|
|
675
|
+
l1BlockNumber
|
|
676
|
+
};
|
|
677
|
+
const { successfulActions = [], failedActions = [] } = this.callbackBundledTransactions(validRequests, result, txContext);
|
|
227
678
|
return {
|
|
228
679
|
result,
|
|
229
680
|
expiredActions,
|
|
@@ -243,10 +694,33 @@ export class SequencerPublisher {
|
|
|
243
694
|
}
|
|
244
695
|
}
|
|
245
696
|
}
|
|
246
|
-
callbackBundledTransactions(requests, result) {
|
|
697
|
+
callbackBundledTransactions(requests, result, txContext) {
|
|
247
698
|
const actionsListStr = requests.map((r)=>r.action).join(', ');
|
|
248
699
|
if (result instanceof FormattedViemError) {
|
|
249
700
|
this.log.error(`Failed to publish bundled transactions (${actionsListStr})`, result);
|
|
701
|
+
this.backupFailedTx({
|
|
702
|
+
id: keccak256(txContext.multicallData),
|
|
703
|
+
failureType: 'send-error',
|
|
704
|
+
request: {
|
|
705
|
+
to: MULTI_CALL_3_ADDRESS,
|
|
706
|
+
data: txContext.multicallData
|
|
707
|
+
},
|
|
708
|
+
blobData: txContext.blobData,
|
|
709
|
+
l1BlockNumber: txContext.l1BlockNumber.toString(),
|
|
710
|
+
error: {
|
|
711
|
+
message: result.message,
|
|
712
|
+
name: result.name
|
|
713
|
+
},
|
|
714
|
+
context: {
|
|
715
|
+
actions: requests.map((r)=>r.action),
|
|
716
|
+
requests: requests.map((r)=>({
|
|
717
|
+
action: r.action,
|
|
718
|
+
to: r.request.to,
|
|
719
|
+
data: r.request.data
|
|
720
|
+
})),
|
|
721
|
+
sender: this.getSenderAddress().toString()
|
|
722
|
+
}
|
|
723
|
+
});
|
|
250
724
|
return {
|
|
251
725
|
failedActions: requests.map((r)=>r.action)
|
|
252
726
|
};
|
|
@@ -264,6 +738,37 @@ export class SequencerPublisher {
|
|
|
264
738
|
failedActions.push(request.action);
|
|
265
739
|
}
|
|
266
740
|
}
|
|
741
|
+
// Single backup for the whole reverted tx
|
|
742
|
+
if (failedActions.length > 0 && result?.receipt?.status === 'reverted') {
|
|
743
|
+
this.backupFailedTx({
|
|
744
|
+
id: result.receipt.transactionHash,
|
|
745
|
+
failureType: 'revert',
|
|
746
|
+
request: {
|
|
747
|
+
to: MULTI_CALL_3_ADDRESS,
|
|
748
|
+
data: txContext.multicallData
|
|
749
|
+
},
|
|
750
|
+
blobData: txContext.blobData,
|
|
751
|
+
l1BlockNumber: result.receipt.blockNumber.toString(),
|
|
752
|
+
receipt: {
|
|
753
|
+
transactionHash: result.receipt.transactionHash,
|
|
754
|
+
blockNumber: result.receipt.blockNumber.toString(),
|
|
755
|
+
gasUsed: (result.receipt.gasUsed ?? 0n).toString(),
|
|
756
|
+
status: 'reverted'
|
|
757
|
+
},
|
|
758
|
+
error: {
|
|
759
|
+
message: result.errorMsg ?? 'Transaction reverted'
|
|
760
|
+
},
|
|
761
|
+
context: {
|
|
762
|
+
actions: failedActions,
|
|
763
|
+
requests: requests.filter((r)=>failedActions.includes(r.action)).map((r)=>({
|
|
764
|
+
action: r.action,
|
|
765
|
+
to: r.request.to,
|
|
766
|
+
data: r.request.data
|
|
767
|
+
})),
|
|
768
|
+
sender: this.getSenderAddress().toString()
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
267
772
|
return {
|
|
268
773
|
successfulActions,
|
|
269
774
|
failedActions
|
|
@@ -282,7 +787,7 @@ export class SequencerPublisher {
|
|
|
282
787
|
'InvalidArchive'
|
|
283
788
|
];
|
|
284
789
|
return this.rollupContract.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), Number(this.ethereumSlotDuration), {
|
|
285
|
-
forcePendingCheckpointNumber: opts.
|
|
790
|
+
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber
|
|
286
791
|
}).catch((err)=>{
|
|
287
792
|
if (err instanceof FormattedViemError && ignoredErrors.find((e)=>err.message.includes(e))) {
|
|
288
793
|
this.log.warn(`Failed canProposeAtTime check with ${ignoredErrors.find((e)=>err.message.includes(e))}`, {
|
|
@@ -310,12 +815,11 @@ export class SequencerPublisher {
|
|
|
310
815
|
[],
|
|
311
816
|
Signature.empty().toViemSignature(),
|
|
312
817
|
`0x${'0'.repeat(64)}`,
|
|
313
|
-
header.
|
|
818
|
+
header.blobsHash.toString(),
|
|
314
819
|
flags
|
|
315
820
|
];
|
|
316
821
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
317
|
-
const
|
|
318
|
-
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(optsForcePendingCheckpointNumber);
|
|
822
|
+
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(opts?.forcePendingCheckpointNumber);
|
|
319
823
|
let balance = 0n;
|
|
320
824
|
if (this.config.fishermanMode) {
|
|
321
825
|
// In fisherman mode, we can't know where the proposer is publishing from
|
|
@@ -342,34 +846,38 @@ export class SequencerPublisher {
|
|
|
342
846
|
this.log.debug(`Simulated validateHeader`);
|
|
343
847
|
}
|
|
344
848
|
/**
|
|
345
|
-
* Simulate making a call to invalidate a
|
|
346
|
-
* @param
|
|
347
|
-
*/ async
|
|
849
|
+
* Simulate making a call to invalidate a checkpoint with invalid attestations. Returns undefined if no need to invalidate.
|
|
850
|
+
* @param validationResult - The validation result indicating which checkpoint to invalidate (as returned by the archiver)
|
|
851
|
+
*/ async simulateInvalidateCheckpoint(validationResult) {
|
|
348
852
|
if (validationResult.valid) {
|
|
349
853
|
return undefined;
|
|
350
854
|
}
|
|
351
|
-
const { reason,
|
|
352
|
-
const
|
|
855
|
+
const { reason, checkpoint } = validationResult;
|
|
856
|
+
const checkpointNumber = checkpoint.checkpointNumber;
|
|
353
857
|
const logData = {
|
|
354
|
-
...
|
|
858
|
+
...checkpoint,
|
|
355
859
|
reason
|
|
356
860
|
};
|
|
357
|
-
const
|
|
358
|
-
if (
|
|
359
|
-
this.log.verbose(`Skipping
|
|
360
|
-
|
|
861
|
+
const currentCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
862
|
+
if (currentCheckpointNumber < checkpointNumber) {
|
|
863
|
+
this.log.verbose(`Skipping checkpoint ${checkpointNumber} invalidation since it has already been removed from the pending chain`, {
|
|
864
|
+
currentCheckpointNumber,
|
|
361
865
|
...logData
|
|
362
866
|
});
|
|
363
867
|
return undefined;
|
|
364
868
|
}
|
|
365
|
-
const request = this.
|
|
366
|
-
this.log.debug(`Simulating invalidate
|
|
869
|
+
const request = this.buildInvalidateCheckpointRequest(validationResult);
|
|
870
|
+
this.log.debug(`Simulating invalidate checkpoint ${checkpointNumber}`, {
|
|
367
871
|
...logData,
|
|
368
872
|
request
|
|
369
873
|
});
|
|
874
|
+
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
370
875
|
try {
|
|
371
|
-
const { gasUsed } = await this.l1TxUtils.simulate(request, undefined, undefined,
|
|
372
|
-
|
|
876
|
+
const { gasUsed } = await this.l1TxUtils.simulate(request, undefined, undefined, mergeAbis([
|
|
877
|
+
request.abi ?? [],
|
|
878
|
+
ErrorsAbi
|
|
879
|
+
]));
|
|
880
|
+
this.log.verbose(`Simulation for invalidate checkpoint ${checkpointNumber} succeeded`, {
|
|
373
881
|
...logData,
|
|
374
882
|
request,
|
|
375
883
|
gasUsed
|
|
@@ -377,55 +885,76 @@ export class SequencerPublisher {
|
|
|
377
885
|
return {
|
|
378
886
|
request,
|
|
379
887
|
gasUsed,
|
|
380
|
-
|
|
381
|
-
|
|
888
|
+
checkpointNumber,
|
|
889
|
+
forcePendingCheckpointNumber: CheckpointNumber(checkpointNumber - 1),
|
|
382
890
|
reason
|
|
383
891
|
};
|
|
384
892
|
} catch (err) {
|
|
385
893
|
const viemError = formatViemError(err);
|
|
386
|
-
// If the error is due to the
|
|
387
|
-
// we can safely ignore it and return undefined so we go ahead with
|
|
388
|
-
if (viemError.message?.includes('
|
|
389
|
-
this.log.verbose(`Simulation for invalidate
|
|
894
|
+
// If the error is due to the checkpoint not being in the pending chain, and it was indeed removed by someone else,
|
|
895
|
+
// we can safely ignore it and return undefined so we go ahead with checkpoint building.
|
|
896
|
+
if (viemError.message?.includes('Rollup__CheckpointNotInPendingChain')) {
|
|
897
|
+
this.log.verbose(`Simulation for invalidate checkpoint ${checkpointNumber} failed due to checkpoint not being in pending chain`, {
|
|
390
898
|
...logData,
|
|
391
899
|
request,
|
|
392
900
|
error: viemError.message
|
|
393
901
|
});
|
|
394
|
-
const
|
|
395
|
-
if (
|
|
396
|
-
this.log.verbose(`
|
|
902
|
+
const latestPendingCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
903
|
+
if (latestPendingCheckpointNumber < checkpointNumber) {
|
|
904
|
+
this.log.verbose(`Checkpoint ${checkpointNumber} has already been invalidated`, {
|
|
397
905
|
...logData
|
|
398
906
|
});
|
|
399
907
|
return undefined;
|
|
400
908
|
} else {
|
|
401
|
-
this.log.error(`Simulation for invalidate ${
|
|
402
|
-
throw new Error(`Failed to simulate invalidate
|
|
909
|
+
this.log.error(`Simulation for invalidate checkpoint ${checkpointNumber} failed and it is still in pending chain`, viemError, logData);
|
|
910
|
+
throw new Error(`Failed to simulate invalidate checkpoint ${checkpointNumber} while it is still in pending chain`, {
|
|
403
911
|
cause: viemError
|
|
404
912
|
});
|
|
405
913
|
}
|
|
406
914
|
}
|
|
407
|
-
// Otherwise, throw. We cannot build the next
|
|
408
|
-
this.log.error(`Simulation for invalidate
|
|
409
|
-
|
|
915
|
+
// Otherwise, throw. We cannot build the next checkpoint if we cannot invalidate the previous one.
|
|
916
|
+
this.log.error(`Simulation for invalidate checkpoint ${checkpointNumber} failed`, viemError, logData);
|
|
917
|
+
this.backupFailedTx({
|
|
918
|
+
id: keccak256(request.data),
|
|
919
|
+
failureType: 'simulation',
|
|
920
|
+
request: {
|
|
921
|
+
to: request.to,
|
|
922
|
+
data: request.data,
|
|
923
|
+
value: request.value?.toString()
|
|
924
|
+
},
|
|
925
|
+
l1BlockNumber: l1BlockNumber.toString(),
|
|
926
|
+
error: {
|
|
927
|
+
message: viemError.message,
|
|
928
|
+
name: viemError.name
|
|
929
|
+
},
|
|
930
|
+
context: {
|
|
931
|
+
actions: [
|
|
932
|
+
`invalidate-${reason}`
|
|
933
|
+
],
|
|
934
|
+
checkpointNumber,
|
|
935
|
+
sender: this.getSenderAddress().toString()
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
throw new Error(`Failed to simulate invalidate checkpoint ${checkpointNumber}`, {
|
|
410
939
|
cause: viemError
|
|
411
940
|
});
|
|
412
941
|
}
|
|
413
942
|
}
|
|
414
|
-
|
|
943
|
+
buildInvalidateCheckpointRequest(validationResult) {
|
|
415
944
|
if (validationResult.valid) {
|
|
416
|
-
throw new Error('Cannot invalidate a valid
|
|
945
|
+
throw new Error('Cannot invalidate a valid checkpoint');
|
|
417
946
|
}
|
|
418
|
-
const {
|
|
947
|
+
const { checkpoint, committee, reason } = validationResult;
|
|
419
948
|
const logData = {
|
|
420
|
-
...
|
|
949
|
+
...checkpoint,
|
|
421
950
|
reason
|
|
422
951
|
};
|
|
423
|
-
this.log.debug(`
|
|
952
|
+
this.log.debug(`Building invalidate checkpoint ${checkpoint.checkpointNumber} request`, logData);
|
|
424
953
|
const attestationsAndSigners = new CommitteeAttestationsAndSigners(validationResult.attestations).getPackedAttestations();
|
|
425
954
|
if (reason === 'invalid-attestation') {
|
|
426
|
-
return this.rollupContract.buildInvalidateBadAttestationRequest(
|
|
955
|
+
return this.rollupContract.buildInvalidateBadAttestationRequest(checkpoint.checkpointNumber, attestationsAndSigners, committee, validationResult.invalidIndex);
|
|
427
956
|
} else if (reason === 'insufficient-attestations') {
|
|
428
|
-
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(
|
|
957
|
+
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(checkpoint.checkpointNumber, attestationsAndSigners, committee);
|
|
429
958
|
} else {
|
|
430
959
|
const _ = reason;
|
|
431
960
|
throw new Error(`Unknown reason for invalidation`);
|
|
@@ -433,29 +962,15 @@ export class SequencerPublisher {
|
|
|
433
962
|
}
|
|
434
963
|
/** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, options) {
|
|
435
964
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
436
|
-
// TODO(palla/mbps): This should not be needed, there's no flow where we propose with zero attestations. Or is there?
|
|
437
|
-
// If we have no attestations, we still need to provide the empty attestations
|
|
438
|
-
// so that the committee is recalculated correctly
|
|
439
|
-
// const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
440
|
-
// if (ignoreSignatures) {
|
|
441
|
-
// const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
|
|
442
|
-
// if (!committee) {
|
|
443
|
-
// this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
444
|
-
// throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
445
|
-
// }
|
|
446
|
-
// attestationsAndSigners.attestations = committee.map(committeeMember =>
|
|
447
|
-
// CommitteeAttestation.fromAddress(committeeMember),
|
|
448
|
-
// );
|
|
449
|
-
// }
|
|
450
965
|
const blobFields = checkpoint.toBlobFields();
|
|
451
|
-
const blobs = getBlobsPerL1Block(blobFields);
|
|
966
|
+
const blobs = await getBlobsPerL1Block(blobFields);
|
|
452
967
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
453
968
|
const args = [
|
|
454
969
|
{
|
|
455
970
|
header: checkpoint.header.toViem(),
|
|
456
971
|
archive: toHex(checkpoint.archive.root.toBuffer()),
|
|
457
972
|
oracleInput: {
|
|
458
|
-
feeAssetPriceModifier:
|
|
973
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier
|
|
459
974
|
}
|
|
460
975
|
},
|
|
461
976
|
attestationsAndSigners.getPackedAttestations(),
|
|
@@ -490,6 +1005,28 @@ export class SequencerPublisher {
|
|
|
490
1005
|
this.log.warn(`Skipping vote cast for payload with empty code`);
|
|
491
1006
|
return false;
|
|
492
1007
|
}
|
|
1008
|
+
// Check if payload was already submitted to governance
|
|
1009
|
+
const cacheKey = payload.toString();
|
|
1010
|
+
if (!this.payloadProposedCache.has(cacheKey)) {
|
|
1011
|
+
try {
|
|
1012
|
+
const l1StartBlock = await this.rollupContract.getL1StartBlock();
|
|
1013
|
+
const proposed = await retry(()=>base.hasPayloadBeenProposed(payload.toString(), l1StartBlock), 'Check if payload was proposed', makeBackoff([
|
|
1014
|
+
0,
|
|
1015
|
+
1,
|
|
1016
|
+
2
|
|
1017
|
+
]), this.log, true);
|
|
1018
|
+
if (proposed) {
|
|
1019
|
+
this.payloadProposedCache.add(cacheKey);
|
|
1020
|
+
}
|
|
1021
|
+
} catch (err) {
|
|
1022
|
+
this.log.warn(`Failed to check if payload ${payload} was proposed after retries, skipping signal`, err);
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
if (this.payloadProposedCache.has(cacheKey)) {
|
|
1027
|
+
this.log.info(`Payload ${payload} was already proposed to governance, stopping signals`);
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
493
1030
|
const cachedLastVote = this.lastActions[signalType];
|
|
494
1031
|
this.lastActions[signalType] = slotNumber;
|
|
495
1032
|
const action = signalType;
|
|
@@ -500,15 +1037,41 @@ export class SequencerPublisher {
|
|
|
500
1037
|
signer: this.l1TxUtils.client.account?.address,
|
|
501
1038
|
lastValidL2Slot: slotNumber
|
|
502
1039
|
});
|
|
1040
|
+
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
503
1041
|
try {
|
|
504
1042
|
await this.l1TxUtils.simulate(request, {
|
|
505
1043
|
time: timestamp
|
|
506
|
-
}, [],
|
|
1044
|
+
}, [], mergeAbis([
|
|
1045
|
+
request.abi ?? [],
|
|
1046
|
+
ErrorsAbi
|
|
1047
|
+
]));
|
|
507
1048
|
this.log.debug(`Simulation for ${action} at slot ${slotNumber} succeeded`, {
|
|
508
1049
|
request
|
|
509
1050
|
});
|
|
510
1051
|
} catch (err) {
|
|
511
|
-
|
|
1052
|
+
const viemError = formatViemError(err);
|
|
1053
|
+
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError);
|
|
1054
|
+
this.backupFailedTx({
|
|
1055
|
+
id: keccak256(request.data),
|
|
1056
|
+
failureType: 'simulation',
|
|
1057
|
+
request: {
|
|
1058
|
+
to: request.to,
|
|
1059
|
+
data: request.data,
|
|
1060
|
+
value: request.value?.toString()
|
|
1061
|
+
},
|
|
1062
|
+
l1BlockNumber: l1BlockNumber.toString(),
|
|
1063
|
+
error: {
|
|
1064
|
+
message: viemError.message,
|
|
1065
|
+
name: viemError.name
|
|
1066
|
+
},
|
|
1067
|
+
context: {
|
|
1068
|
+
actions: [
|
|
1069
|
+
action
|
|
1070
|
+
],
|
|
1071
|
+
slot: slotNumber,
|
|
1072
|
+
sender: this.getSenderAddress().toString()
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
512
1075
|
// Yes, we enqueue the request anyway, in case there was a bug with the simulation itself
|
|
513
1076
|
}
|
|
514
1077
|
// TODO(palla/slash): All votes (governance and slashing) should txTimeoutAt at the end of the slot.
|
|
@@ -647,13 +1210,14 @@ export class SequencerPublisher {
|
|
|
647
1210
|
/** Simulates and enqueues a proposal for a checkpoint on L1 */ async enqueueProposeCheckpoint(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
648
1211
|
const checkpointHeader = checkpoint.header;
|
|
649
1212
|
const blobFields = checkpoint.toBlobFields();
|
|
650
|
-
const blobs = getBlobsPerL1Block(blobFields);
|
|
1213
|
+
const blobs = await getBlobsPerL1Block(blobFields);
|
|
651
1214
|
const proposeTxArgs = {
|
|
652
1215
|
header: checkpointHeader,
|
|
653
1216
|
archive: checkpoint.archive.root.toBuffer(),
|
|
654
1217
|
blobs,
|
|
655
1218
|
attestationsAndSigners,
|
|
656
|
-
attestationsAndSignersSignature
|
|
1219
|
+
attestationsAndSignersSignature,
|
|
1220
|
+
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier
|
|
657
1221
|
};
|
|
658
1222
|
let ts;
|
|
659
1223
|
try {
|
|
@@ -667,7 +1231,7 @@ export class SequencerPublisher {
|
|
|
667
1231
|
this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
668
1232
|
...checkpoint.getStats(),
|
|
669
1233
|
slotNumber: checkpoint.header.slotNumber,
|
|
670
|
-
|
|
1234
|
+
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber
|
|
671
1235
|
});
|
|
672
1236
|
throw err;
|
|
673
1237
|
}
|
|
@@ -677,20 +1241,20 @@ export class SequencerPublisher {
|
|
|
677
1241
|
});
|
|
678
1242
|
await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
|
|
679
1243
|
}
|
|
680
|
-
|
|
1244
|
+
enqueueInvalidateCheckpoint(request, opts = {}) {
|
|
681
1245
|
if (!request) {
|
|
682
1246
|
return;
|
|
683
1247
|
}
|
|
684
1248
|
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
685
1249
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(request.gasUsed) * 64 / 63)));
|
|
686
|
-
const { gasUsed,
|
|
1250
|
+
const { gasUsed, checkpointNumber } = request;
|
|
687
1251
|
const logData = {
|
|
688
1252
|
gasUsed,
|
|
689
|
-
|
|
1253
|
+
checkpointNumber,
|
|
690
1254
|
gasLimit,
|
|
691
1255
|
opts
|
|
692
1256
|
};
|
|
693
|
-
this.log.verbose(`Enqueuing invalidate
|
|
1257
|
+
this.log.verbose(`Enqueuing invalidate checkpoint request`, logData);
|
|
694
1258
|
this.addRequest({
|
|
695
1259
|
action: `invalidate-by-${request.reason}`,
|
|
696
1260
|
request: request.request,
|
|
@@ -702,12 +1266,12 @@ export class SequencerPublisher {
|
|
|
702
1266
|
checkSuccess: (_req, result)=>{
|
|
703
1267
|
const success = result && result.receipt && result.receipt.status === 'success' && tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointInvalidated');
|
|
704
1268
|
if (!success) {
|
|
705
|
-
this.log.warn(`Invalidate
|
|
1269
|
+
this.log.warn(`Invalidate checkpoint ${request.checkpointNumber} failed`, {
|
|
706
1270
|
...result,
|
|
707
1271
|
...logData
|
|
708
1272
|
});
|
|
709
1273
|
} else {
|
|
710
|
-
this.log.info(`Invalidate
|
|
1274
|
+
this.log.info(`Invalidate checkpoint ${request.checkpointNumber} succeeded`, {
|
|
711
1275
|
...result,
|
|
712
1276
|
...logData
|
|
713
1277
|
});
|
|
@@ -729,28 +1293,60 @@ export class SequencerPublisher {
|
|
|
729
1293
|
const cachedLastActionSlot = this.lastActions[action];
|
|
730
1294
|
this.lastActions[action] = slotNumber;
|
|
731
1295
|
this.log.debug(`Simulating ${action} for slot ${slotNumber}`, logData);
|
|
1296
|
+
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
732
1297
|
let gasUsed;
|
|
1298
|
+
const simulateAbi = mergeAbis([
|
|
1299
|
+
request.abi ?? [],
|
|
1300
|
+
ErrorsAbi
|
|
1301
|
+
]);
|
|
733
1302
|
try {
|
|
734
1303
|
({ gasUsed } = await this.l1TxUtils.simulate(request, {
|
|
735
1304
|
time: timestamp
|
|
736
|
-
}, [],
|
|
1305
|
+
}, [], simulateAbi)); // TODO(palla/slash): Check the timestamp logic
|
|
737
1306
|
this.log.verbose(`Simulation for ${action} succeeded`, {
|
|
738
1307
|
...logData,
|
|
739
1308
|
request,
|
|
740
1309
|
gasUsed
|
|
741
1310
|
});
|
|
742
1311
|
} catch (err) {
|
|
743
|
-
const viemError = formatViemError(err);
|
|
1312
|
+
const viemError = formatViemError(err, simulateAbi);
|
|
744
1313
|
this.log.error(`Simulation for ${action} at ${slotNumber} failed`, viemError, logData);
|
|
1314
|
+
this.backupFailedTx({
|
|
1315
|
+
id: keccak256(request.data),
|
|
1316
|
+
failureType: 'simulation',
|
|
1317
|
+
request: {
|
|
1318
|
+
to: request.to,
|
|
1319
|
+
data: request.data,
|
|
1320
|
+
value: request.value?.toString()
|
|
1321
|
+
},
|
|
1322
|
+
l1BlockNumber: l1BlockNumber.toString(),
|
|
1323
|
+
error: {
|
|
1324
|
+
message: viemError.message,
|
|
1325
|
+
name: viemError.name
|
|
1326
|
+
},
|
|
1327
|
+
context: {
|
|
1328
|
+
actions: [
|
|
1329
|
+
action
|
|
1330
|
+
],
|
|
1331
|
+
slot: slotNumber,
|
|
1332
|
+
sender: this.getSenderAddress().toString()
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
745
1335
|
return false;
|
|
746
1336
|
}
|
|
747
1337
|
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
748
1338
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(gasUsed) * 64 / 63)));
|
|
749
1339
|
logData.gasLimit = gasLimit;
|
|
1340
|
+
// Store the ABI used for simulation on the request so Multicall3.forward can decode errors
|
|
1341
|
+
// when the tx is sent and a revert is diagnosed via simulation.
|
|
1342
|
+
const requestWithAbi = {
|
|
1343
|
+
...request,
|
|
1344
|
+
abi: simulateAbi
|
|
1345
|
+
};
|
|
750
1346
|
this.log.debug(`Enqueuing ${action}`, logData);
|
|
751
1347
|
this.addRequest({
|
|
752
1348
|
action,
|
|
753
|
-
request,
|
|
1349
|
+
request: requestWithAbi,
|
|
754
1350
|
gasConfig: {
|
|
755
1351
|
gasLimit
|
|
756
1352
|
},
|
|
@@ -814,10 +1410,38 @@ export class SequencerPublisher {
|
|
|
814
1410
|
}, {}, {
|
|
815
1411
|
blobs: encodedData.blobs.map((b)=>b.data),
|
|
816
1412
|
kzg
|
|
817
|
-
}).catch((err)=>{
|
|
818
|
-
const
|
|
819
|
-
this.log.error(`Failed to validate blobs`, message, {
|
|
820
|
-
metaMessages
|
|
1413
|
+
}).catch(async (err)=>{
|
|
1414
|
+
const viemError = formatViemError(err);
|
|
1415
|
+
this.log.error(`Failed to validate blobs`, viemError.message, {
|
|
1416
|
+
metaMessages: viemError.metaMessages
|
|
1417
|
+
});
|
|
1418
|
+
const validateBlobsData = encodeFunctionData({
|
|
1419
|
+
abi: RollupAbi,
|
|
1420
|
+
functionName: 'validateBlobs',
|
|
1421
|
+
args: [
|
|
1422
|
+
blobInput
|
|
1423
|
+
]
|
|
1424
|
+
});
|
|
1425
|
+
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
1426
|
+
this.backupFailedTx({
|
|
1427
|
+
id: keccak256(validateBlobsData),
|
|
1428
|
+
failureType: 'simulation',
|
|
1429
|
+
request: {
|
|
1430
|
+
to: this.rollupContract.address,
|
|
1431
|
+
data: validateBlobsData
|
|
1432
|
+
},
|
|
1433
|
+
blobData: encodedData.blobs.map((b)=>toHex(b.data)),
|
|
1434
|
+
l1BlockNumber: l1BlockNumber.toString(),
|
|
1435
|
+
error: {
|
|
1436
|
+
message: viemError.message,
|
|
1437
|
+
name: viemError.name
|
|
1438
|
+
},
|
|
1439
|
+
context: {
|
|
1440
|
+
actions: [
|
|
1441
|
+
'validate-blobs'
|
|
1442
|
+
],
|
|
1443
|
+
sender: this.getSenderAddress().toString()
|
|
1444
|
+
}
|
|
821
1445
|
});
|
|
822
1446
|
throw new Error('Failed to validate blobs');
|
|
823
1447
|
});
|
|
@@ -828,8 +1452,7 @@ export class SequencerPublisher {
|
|
|
828
1452
|
header: encodedData.header.toViem(),
|
|
829
1453
|
archive: toHex(encodedData.archive),
|
|
830
1454
|
oracleInput: {
|
|
831
|
-
|
|
832
|
-
feeAssetPriceModifier: 0n
|
|
1455
|
+
feeAssetPriceModifier: encodedData.feeAssetPriceModifier
|
|
833
1456
|
}
|
|
834
1457
|
},
|
|
835
1458
|
encodedData.attestationsAndSigners.getPackedAttestations(),
|
|
@@ -857,8 +1480,7 @@ export class SequencerPublisher {
|
|
|
857
1480
|
args
|
|
858
1481
|
});
|
|
859
1482
|
// override the pending checkpoint number if requested
|
|
860
|
-
const
|
|
861
|
-
const forcePendingCheckpointNumberStateDiff = (optsForcePendingCheckpointNumber !== undefined ? await this.rollupContract.makePendingCheckpointNumberOverride(optsForcePendingCheckpointNumber) : []).flatMap((override)=>override.stateDiff ?? []);
|
|
1483
|
+
const forcePendingCheckpointNumberStateDiff = (options.forcePendingCheckpointNumber !== undefined ? await this.rollupContract.makePendingCheckpointNumberOverride(options.forcePendingCheckpointNumber) : []).flatMap((override)=>override.stateDiff ?? []);
|
|
862
1484
|
const stateOverrides = [
|
|
863
1485
|
{
|
|
864
1486
|
address: this.rollupContract.address,
|
|
@@ -879,10 +1501,11 @@ export class SequencerPublisher {
|
|
|
879
1501
|
balance: 10n * WEI_CONST * WEI_CONST
|
|
880
1502
|
});
|
|
881
1503
|
}
|
|
1504
|
+
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
882
1505
|
const simulationResult = await this.l1TxUtils.simulate({
|
|
883
1506
|
to: this.rollupContract.address,
|
|
884
1507
|
data: rollupData,
|
|
885
|
-
gas:
|
|
1508
|
+
gas: MAX_L1_TX_LIMIT,
|
|
886
1509
|
...this.proposerAddressForSimulation && {
|
|
887
1510
|
from: this.proposerAddressForSimulation.toString()
|
|
888
1511
|
}
|
|
@@ -890,10 +1513,10 @@ export class SequencerPublisher {
|
|
|
890
1513
|
// @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
|
|
891
1514
|
time: timestamp + 1n,
|
|
892
1515
|
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
|
|
893
|
-
gasLimit:
|
|
1516
|
+
gasLimit: MAX_L1_TX_LIMIT * 2n
|
|
894
1517
|
}, stateOverrides, RollupAbi, {
|
|
895
1518
|
// @note fallback gas estimate to use if the node doesn't support simulation API
|
|
896
|
-
fallbackGasEstimate:
|
|
1519
|
+
fallbackGasEstimate: MAX_L1_TX_LIMIT
|
|
897
1520
|
}).catch((err)=>{
|
|
898
1521
|
// In fisherman mode, we expect ValidatorSelection__MissingProposerSignature since fisherman doesn't have proposer signature
|
|
899
1522
|
const viemError = formatViemError(err);
|
|
@@ -901,11 +1524,31 @@ export class SequencerPublisher {
|
|
|
901
1524
|
this.log.debug(`Ignoring expected ValidatorSelection__MissingProposerSignature error in fisherman mode`);
|
|
902
1525
|
// Return a minimal simulation result with the fallback gas estimate
|
|
903
1526
|
return {
|
|
904
|
-
gasUsed:
|
|
1527
|
+
gasUsed: MAX_L1_TX_LIMIT,
|
|
905
1528
|
logs: []
|
|
906
1529
|
};
|
|
907
1530
|
}
|
|
908
1531
|
this.log.error(`Failed to simulate propose tx`, viemError);
|
|
1532
|
+
this.backupFailedTx({
|
|
1533
|
+
id: keccak256(rollupData),
|
|
1534
|
+
failureType: 'simulation',
|
|
1535
|
+
request: {
|
|
1536
|
+
to: this.rollupContract.address,
|
|
1537
|
+
data: rollupData
|
|
1538
|
+
},
|
|
1539
|
+
l1BlockNumber: l1BlockNumber.toString(),
|
|
1540
|
+
error: {
|
|
1541
|
+
message: viemError.message,
|
|
1542
|
+
name: viemError.name
|
|
1543
|
+
},
|
|
1544
|
+
context: {
|
|
1545
|
+
actions: [
|
|
1546
|
+
'propose'
|
|
1547
|
+
],
|
|
1548
|
+
slot: Number(args[0].header.slotNumber),
|
|
1549
|
+
sender: this.getSenderAddress().toString()
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
909
1552
|
throw err;
|
|
910
1553
|
});
|
|
911
1554
|
return {
|