@aztec/aztec-node 0.0.1-fake-ceab37513c → 0.0.6-commit.a2d1860fe9
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/aztec-node/config.d.ts +11 -5
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +17 -3
- package/dest/aztec-node/node_metrics.d.ts +5 -1
- package/dest/aztec-node/node_metrics.d.ts.map +1 -1
- package/dest/aztec-node/node_metrics.js +20 -6
- package/dest/aztec-node/server.d.ts +68 -124
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +789 -225
- package/dest/bin/index.d.ts +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/sentinel/config.d.ts +1 -1
- package/dest/sentinel/factory.d.ts +1 -1
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/factory.js +1 -1
- package/dest/sentinel/index.d.ts +1 -1
- package/dest/sentinel/sentinel.d.ts +22 -20
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +101 -63
- package/dest/sentinel/store.d.ts +6 -5
- package/dest/sentinel/store.d.ts.map +1 -1
- package/dest/sentinel/store.js +14 -9
- package/dest/test/index.d.ts +1 -1
- package/package.json +31 -28
- package/src/aztec-node/config.ts +34 -14
- package/src/aztec-node/node_metrics.ts +23 -6
- package/src/aztec-node/server.ts +512 -304
- package/src/sentinel/factory.ts +1 -6
- package/src/sentinel/sentinel.ts +136 -82
- package/src/sentinel/store.ts +22 -21
|
@@ -1,34 +1,407 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
+
};
|
|
6
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, _initProto;
|
|
7
374
|
import { createArchiver } from '@aztec/archiver';
|
|
8
375
|
import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
376
|
+
import { createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
377
|
+
import { Blob } from '@aztec/blob-lib';
|
|
11
378
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
379
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
380
|
+
import { getPublicClient } from '@aztec/ethereum/client';
|
|
381
|
+
import { RegistryContract, RollupContract } from '@aztec/ethereum/contracts';
|
|
382
|
+
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
383
|
+
import { compactArray, pick, unique } from '@aztec/foundation/collection';
|
|
384
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
14
385
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
15
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
16
386
|
import { BadRequestError } from '@aztec/foundation/json-rpc';
|
|
17
387
|
import { createLogger } from '@aztec/foundation/log';
|
|
18
|
-
import { SerialQueue } from '@aztec/foundation/queue';
|
|
19
388
|
import { count } from '@aztec/foundation/string';
|
|
20
389
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
21
390
|
import { MembershipWitness } from '@aztec/foundation/trees';
|
|
22
391
|
import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
23
392
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
24
|
-
import {
|
|
393
|
+
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
25
394
|
import { createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
26
395
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
27
|
-
import {
|
|
396
|
+
import { createProverNode } from '@aztec/prover-node';
|
|
397
|
+
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
398
|
+
import { GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client';
|
|
28
399
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
29
400
|
import { AttestationsBlockWatcher, EpochPruneWatcher, createSlasher } from '@aztec/slasher';
|
|
401
|
+
import { CollectionLimitsConfig, PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
30
402
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
31
|
-
import {
|
|
403
|
+
import { BlockHash, L2Block } from '@aztec/stdlib/block';
|
|
404
|
+
import { GasFees } from '@aztec/stdlib/gas';
|
|
32
405
|
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
33
406
|
import { AztecNodeAdminConfigSchema } from '@aztec/stdlib/interfaces/client';
|
|
34
407
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
@@ -38,12 +411,15 @@ import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@az
|
|
|
38
411
|
import { PublicSimulationOutput, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
39
412
|
import { getPackageVersion } from '@aztec/stdlib/update-checker';
|
|
40
413
|
import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
41
|
-
import { NodeKeystoreAdapter, ValidatorClient, createBlockProposalHandler, createValidatorClient } from '@aztec/validator-client';
|
|
414
|
+
import { FullNodeCheckpointsBuilder as CheckpointsBuilder, FullNodeCheckpointsBuilder, NodeKeystoreAdapter, ValidatorClient, createBlockProposalHandler, createValidatorClient, createValidatorForAcceptingTxs } from '@aztec/validator-client';
|
|
42
415
|
import { createWorldStateSynchronizer } from '@aztec/world-state';
|
|
43
416
|
import { createPublicClient, fallback, http } from 'viem';
|
|
44
417
|
import { createSentinel } from '../sentinel/factory.js';
|
|
45
418
|
import { createKeyStoreForValidator } from './config.js';
|
|
46
419
|
import { NodeMetrics } from './node_metrics.js';
|
|
420
|
+
_dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
421
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
422
|
+
}));
|
|
47
423
|
/**
|
|
48
424
|
* The aztec node.
|
|
49
425
|
*/ export class AztecNodeService {
|
|
@@ -55,6 +431,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
55
431
|
l1ToL2MessageSource;
|
|
56
432
|
worldStateSynchronizer;
|
|
57
433
|
sequencer;
|
|
434
|
+
proverNode;
|
|
58
435
|
slasherClient;
|
|
59
436
|
validatorsSentinel;
|
|
60
437
|
epochPruneWatcher;
|
|
@@ -66,13 +443,24 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
66
443
|
proofVerifier;
|
|
67
444
|
telemetry;
|
|
68
445
|
log;
|
|
446
|
+
blobClient;
|
|
447
|
+
validatorClient;
|
|
448
|
+
keyStoreManager;
|
|
449
|
+
static{
|
|
450
|
+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
451
|
+
[
|
|
452
|
+
_dec,
|
|
453
|
+
2,
|
|
454
|
+
"simulatePublicCalls"
|
|
455
|
+
]
|
|
456
|
+
], []));
|
|
457
|
+
}
|
|
69
458
|
metrics;
|
|
459
|
+
initialHeaderHashPromise;
|
|
70
460
|
// Prevent two snapshot operations to happen simultaneously
|
|
71
461
|
isUploadingSnapshot;
|
|
72
|
-
// Serial queue to ensure that we only send one tx at a time
|
|
73
|
-
txQueue;
|
|
74
462
|
tracer;
|
|
75
|
-
constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, epochCache, packageVersion, proofVerifier, telemetry = getTelemetryClient(), log = createLogger('node')){
|
|
463
|
+
constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, epochCache, packageVersion, proofVerifier, telemetry = getTelemetryClient(), log = createLogger('node'), blobClient, validatorClient, keyStoreManager){
|
|
76
464
|
this.config = config;
|
|
77
465
|
this.p2pClient = p2pClient;
|
|
78
466
|
this.blockSource = blockSource;
|
|
@@ -81,6 +469,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
81
469
|
this.l1ToL2MessageSource = l1ToL2MessageSource;
|
|
82
470
|
this.worldStateSynchronizer = worldStateSynchronizer;
|
|
83
471
|
this.sequencer = sequencer;
|
|
472
|
+
this.proverNode = proverNode;
|
|
84
473
|
this.slasherClient = slasherClient;
|
|
85
474
|
this.validatorsSentinel = validatorsSentinel;
|
|
86
475
|
this.epochPruneWatcher = epochPruneWatcher;
|
|
@@ -92,11 +481,13 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
92
481
|
this.proofVerifier = proofVerifier;
|
|
93
482
|
this.telemetry = telemetry;
|
|
94
483
|
this.log = log;
|
|
484
|
+
this.blobClient = blobClient;
|
|
485
|
+
this.validatorClient = validatorClient;
|
|
486
|
+
this.keyStoreManager = keyStoreManager;
|
|
487
|
+
this.initialHeaderHashPromise = (_initProto(this), undefined);
|
|
95
488
|
this.isUploadingSnapshot = false;
|
|
96
|
-
this.txQueue = new SerialQueue();
|
|
97
489
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
98
490
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
99
|
-
this.txQueue.start();
|
|
100
491
|
this.log.info(`Aztec Node version: ${this.packageVersion}`);
|
|
101
492
|
this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
|
|
102
493
|
}
|
|
@@ -119,20 +510,28 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
119
510
|
const packageVersion = getPackageVersion() ?? '';
|
|
120
511
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
121
512
|
const dateProvider = deps.dateProvider ?? new DateProvider();
|
|
122
|
-
const blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config, {
|
|
123
|
-
logger: createLogger('node:blob-sink:client')
|
|
124
|
-
});
|
|
125
513
|
const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
126
|
-
// Build a key store from file if given or from environment otherwise
|
|
514
|
+
// Build a key store from file if given or from environment otherwise.
|
|
515
|
+
// We keep the raw KeyStore available so we can merge with prover keys if enableProverNode is set.
|
|
127
516
|
let keyStoreManager;
|
|
128
517
|
const keyStoreProvided = config.keyStoreDirectory !== undefined && config.keyStoreDirectory.length > 0;
|
|
129
518
|
if (keyStoreProvided) {
|
|
130
519
|
const keyStores = loadKeystores(config.keyStoreDirectory);
|
|
131
520
|
keyStoreManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
132
521
|
} else {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
522
|
+
const rawKeyStores = [];
|
|
523
|
+
const validatorKeyStore = createKeyStoreForValidator(config);
|
|
524
|
+
if (validatorKeyStore) {
|
|
525
|
+
rawKeyStores.push(validatorKeyStore);
|
|
526
|
+
}
|
|
527
|
+
if (config.enableProverNode) {
|
|
528
|
+
const proverKeyStore = createKeyStoreForProver(config);
|
|
529
|
+
if (proverKeyStore) {
|
|
530
|
+
rawKeyStores.push(proverKeyStore);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (rawKeyStores.length > 0) {
|
|
534
|
+
keyStoreManager = new KeystoreManager(rawKeyStores.length === 1 ? rawKeyStores[0] : mergeKeystores(rawKeyStores));
|
|
136
535
|
}
|
|
137
536
|
}
|
|
138
537
|
await keyStoreManager?.validateSigners();
|
|
@@ -141,10 +540,10 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
141
540
|
if (keyStoreManager === undefined) {
|
|
142
541
|
throw new Error('Failed to create key store, a requirement for running a validator');
|
|
143
542
|
}
|
|
144
|
-
if (!keyStoreProvided) {
|
|
145
|
-
log.warn(
|
|
543
|
+
if (!keyStoreProvided && process.env.NODE_ENV !== 'test') {
|
|
544
|
+
log.warn("Keystore created from env: it's recommended to use a file-based key store for production");
|
|
146
545
|
}
|
|
147
|
-
ValidatorClient.validateKeyStoreConfiguration(keyStoreManager);
|
|
546
|
+
ValidatorClient.validateKeyStoreConfiguration(keyStoreManager, log);
|
|
148
547
|
}
|
|
149
548
|
// validate that the actual chain id matches that specified in configuration
|
|
150
549
|
if (config.l1ChainId !== ethereumChain.chainInfo.id) {
|
|
@@ -152,7 +551,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
152
551
|
}
|
|
153
552
|
const publicClient = createPublicClient({
|
|
154
553
|
chain: ethereumChain.chainInfo,
|
|
155
|
-
transport: fallback(config.l1RpcUrls.map((url)=>http(url
|
|
554
|
+
transport: fallback(config.l1RpcUrls.map((url)=>http(url, {
|
|
555
|
+
batch: false
|
|
556
|
+
}))),
|
|
156
557
|
pollingInterval: config.viemPollingIntervalMS
|
|
157
558
|
});
|
|
158
559
|
const l1ContractsAddresses = await RegistryContract.collectAddresses(publicClient, config.l1Contracts.registryAddress, config.rollupVersion ?? 'canonical');
|
|
@@ -171,13 +572,14 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
171
572
|
if (config.rollupVersion !== Number(rollupVersionFromRollup)) {
|
|
172
573
|
log.warn(`Registry looked up and returned a rollup with version (${config.rollupVersion}), but this does not match with version detected from the rollup directly: (${rollupVersionFromRollup}).`);
|
|
173
574
|
}
|
|
575
|
+
const blobClient = await createBlobClientWithFileStores(config, log.createChild('blob-client'));
|
|
174
576
|
// attempt snapshot sync if possible
|
|
175
577
|
await trySnapshotSync(config, log);
|
|
176
578
|
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, {
|
|
177
579
|
dateProvider
|
|
178
580
|
});
|
|
179
581
|
const archiver = await createArchiver(config, {
|
|
180
|
-
|
|
582
|
+
blobClient,
|
|
181
583
|
epochCache,
|
|
182
584
|
telemetry,
|
|
183
585
|
dateProvider
|
|
@@ -186,17 +588,17 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
186
588
|
});
|
|
187
589
|
// now create the merkle trees and the world state synchronizer
|
|
188
590
|
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.prefilledPublicData, telemetry);
|
|
189
|
-
const circuitVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();
|
|
591
|
+
const circuitVerifier = config.realProofs || config.debugForceTxProofVerification ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
190
592
|
if (!config.realProofs) {
|
|
191
593
|
log.warn(`Aztec node is accepting fake proofs`);
|
|
192
594
|
}
|
|
193
595
|
const proofVerifier = new QueuedIVCVerifier(config, circuitVerifier);
|
|
194
596
|
// create the tx pool and the p2p client, which will need the l2 block source
|
|
195
597
|
const p2pClient = await createP2PClient(P2PClientType.Full, config, archiver, proofVerifier, worldStateSynchronizer, epochCache, packageVersion, dateProvider, telemetry, deps.p2pClientDeps);
|
|
196
|
-
//
|
|
197
|
-
await worldStateSynchronizer.start();
|
|
598
|
+
// We should really not be modifying the config object
|
|
198
599
|
config.txPublicSetupAllowList = config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
199
|
-
|
|
600
|
+
// Create FullNodeCheckpointsBuilder for validator and non-validator block proposal handling
|
|
601
|
+
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder({
|
|
200
602
|
...config,
|
|
201
603
|
l1GenesisTime,
|
|
202
604
|
slotDuration: Number(slotDuration)
|
|
@@ -204,15 +606,17 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
204
606
|
// We'll accumulate sentinel watchers here
|
|
205
607
|
const watchers = [];
|
|
206
608
|
// Create validator client if required
|
|
207
|
-
const validatorClient = createValidatorClient(config, {
|
|
609
|
+
const validatorClient = await createValidatorClient(config, {
|
|
610
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
611
|
+
worldState: worldStateSynchronizer,
|
|
208
612
|
p2pClient,
|
|
209
613
|
telemetry,
|
|
210
614
|
dateProvider,
|
|
211
615
|
epochCache,
|
|
212
|
-
blockBuilder,
|
|
213
616
|
blockSource: archiver,
|
|
214
617
|
l1ToL2MessageSource: archiver,
|
|
215
|
-
keyStoreManager
|
|
618
|
+
keyStoreManager,
|
|
619
|
+
blobClient
|
|
216
620
|
});
|
|
217
621
|
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
218
622
|
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
@@ -228,7 +632,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
228
632
|
if (!validatorClient && config.alwaysReexecuteBlockProposals) {
|
|
229
633
|
log.info('Setting up block proposal reexecution for monitoring');
|
|
230
634
|
createBlockProposalHandler(config, {
|
|
231
|
-
|
|
635
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
636
|
+
worldState: worldStateSynchronizer,
|
|
232
637
|
epochCache,
|
|
233
638
|
blockSource: archiver,
|
|
234
639
|
l1ToL2MessageSource: archiver,
|
|
@@ -247,7 +652,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
247
652
|
}
|
|
248
653
|
let epochPruneWatcher;
|
|
249
654
|
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
250
|
-
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(),
|
|
655
|
+
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(), validatorCheckpointsBuilder, config);
|
|
251
656
|
watchers.push(epochPruneWatcher);
|
|
252
657
|
}
|
|
253
658
|
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
@@ -264,25 +669,38 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
264
669
|
await attestationsBlockWatcher?.start();
|
|
265
670
|
log.info(`All p2p services started`);
|
|
266
671
|
}).catch((err)=>log.error('Failed to start p2p services after archiver sync', err));
|
|
267
|
-
log.verbose(`All Aztec Node subsystems synced`);
|
|
268
672
|
// Validator enabled, create/start relevant service
|
|
269
673
|
let sequencer;
|
|
270
674
|
let slasherClient;
|
|
271
|
-
if (!config.disableValidator) {
|
|
675
|
+
if (!config.disableValidator && validatorClient) {
|
|
272
676
|
// We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
|
|
273
677
|
// as they are executed when the node is selected as proposer.
|
|
274
678
|
const validatorAddresses = keyStoreManager ? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses() : [];
|
|
275
679
|
slasherClient = await createSlasher(config, config.l1Contracts, getPublicClient(config), watchers, dateProvider, epochCache, validatorAddresses, undefined);
|
|
276
680
|
await slasherClient.start();
|
|
277
|
-
const l1TxUtils = await
|
|
681
|
+
const l1TxUtils = config.sequencerPublisherForwarderAddress ? await createForwarderL1TxUtilsFromSigners(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), config.sequencerPublisherForwarderAddress, {
|
|
682
|
+
...config,
|
|
683
|
+
scope: 'sequencer'
|
|
684
|
+
}, {
|
|
685
|
+
telemetry,
|
|
686
|
+
logger: log.createChild('l1-tx-utils'),
|
|
687
|
+
dateProvider,
|
|
688
|
+
kzg: Blob.getViemKzgInstance()
|
|
689
|
+
}) : await createL1TxUtilsFromSigners(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), {
|
|
278
690
|
...config,
|
|
279
691
|
scope: 'sequencer'
|
|
280
692
|
}, {
|
|
281
693
|
telemetry,
|
|
282
694
|
logger: log.createChild('l1-tx-utils'),
|
|
283
|
-
dateProvider
|
|
695
|
+
dateProvider,
|
|
696
|
+
kzg: Blob.getViemKzgInstance()
|
|
284
697
|
});
|
|
285
698
|
// Create and start the sequencer client
|
|
699
|
+
const checkpointsBuilder = new CheckpointsBuilder({
|
|
700
|
+
...config,
|
|
701
|
+
l1GenesisTime,
|
|
702
|
+
slotDuration: Number(slotDuration)
|
|
703
|
+
}, worldStateSynchronizer, archiver, dateProvider, telemetry);
|
|
286
704
|
sequencer = await SequencerClient.new(config, {
|
|
287
705
|
...deps,
|
|
288
706
|
epochCache,
|
|
@@ -291,12 +709,12 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
291
709
|
p2pClient,
|
|
292
710
|
worldStateSynchronizer,
|
|
293
711
|
slasherClient,
|
|
294
|
-
|
|
712
|
+
checkpointsBuilder,
|
|
295
713
|
l2BlockSource: archiver,
|
|
296
714
|
l1ToL2MessageSource: archiver,
|
|
297
715
|
telemetry,
|
|
298
716
|
dateProvider,
|
|
299
|
-
|
|
717
|
+
blobClient,
|
|
300
718
|
nodeKeyStore: keyStoreManager
|
|
301
719
|
});
|
|
302
720
|
}
|
|
@@ -306,7 +724,35 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
306
724
|
} else if (sequencer) {
|
|
307
725
|
log.warn(`Sequencer created but not started`);
|
|
308
726
|
}
|
|
309
|
-
|
|
727
|
+
// Create prover node subsystem if enabled
|
|
728
|
+
let proverNode;
|
|
729
|
+
if (config.enableProverNode) {
|
|
730
|
+
proverNode = await createProverNode(config, {
|
|
731
|
+
...deps.proverNodeDeps,
|
|
732
|
+
telemetry,
|
|
733
|
+
dateProvider,
|
|
734
|
+
archiver,
|
|
735
|
+
worldStateSynchronizer,
|
|
736
|
+
p2pClient,
|
|
737
|
+
epochCache,
|
|
738
|
+
blobClient,
|
|
739
|
+
keyStoreManager
|
|
740
|
+
});
|
|
741
|
+
if (!options.dontStartProverNode) {
|
|
742
|
+
await proverNode.start();
|
|
743
|
+
log.info(`Prover node subsystem started`);
|
|
744
|
+
} else {
|
|
745
|
+
log.info(`Prover node subsystem created but not started`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const globalVariableBuilder = new GlobalVariableBuilder({
|
|
749
|
+
...config,
|
|
750
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
751
|
+
l1GenesisTime,
|
|
752
|
+
slotDuration: Number(slotDuration)
|
|
753
|
+
});
|
|
754
|
+
const node = new AztecNodeService(config, p2pClient, archiver, archiver, archiver, archiver, worldStateSynchronizer, sequencer, proverNode, slasherClient, validatorsSentinel, epochPruneWatcher, ethereumChain.chainInfo.id, config.rollupVersion, globalVariableBuilder, epochCache, packageVersion, proofVerifier, telemetry, log, blobClient, validatorClient, keyStoreManager);
|
|
755
|
+
return node;
|
|
310
756
|
}
|
|
311
757
|
/**
|
|
312
758
|
* Returns the sequencer client instance.
|
|
@@ -314,6 +760,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
314
760
|
*/ getSequencer() {
|
|
315
761
|
return this.sequencer;
|
|
316
762
|
}
|
|
763
|
+
/** Returns the prover node subsystem, if enabled. */ getProverNode() {
|
|
764
|
+
return this.proverNode;
|
|
765
|
+
}
|
|
317
766
|
getBlockSource() {
|
|
318
767
|
return this.blockSource;
|
|
319
768
|
}
|
|
@@ -332,6 +781,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
332
781
|
getEncodedEnr() {
|
|
333
782
|
return Promise.resolve(this.p2pClient.getEnr()?.encodeTxt());
|
|
334
783
|
}
|
|
784
|
+
async getAllowedPublicSetup() {
|
|
785
|
+
return this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
786
|
+
}
|
|
335
787
|
/**
|
|
336
788
|
* Method to determine if the node is ready to accept transactions.
|
|
337
789
|
* @returns - Flag indicating the readiness for tx submission.
|
|
@@ -353,33 +805,46 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
353
805
|
rollupVersion,
|
|
354
806
|
enr,
|
|
355
807
|
l1ContractAddresses: contractAddresses,
|
|
356
|
-
protocolContractAddresses: protocolContractAddresses
|
|
808
|
+
protocolContractAddresses: protocolContractAddresses,
|
|
809
|
+
realProofs: !!this.config.realProofs
|
|
357
810
|
};
|
|
358
811
|
return nodeInfo;
|
|
359
812
|
}
|
|
360
813
|
/**
|
|
361
|
-
* Get a block specified by its number.
|
|
362
|
-
* @param
|
|
814
|
+
* Get a block specified by its block number, block hash, or 'latest'.
|
|
815
|
+
* @param block - The block parameter (block number, block hash, or 'latest').
|
|
363
816
|
* @returns The requested block.
|
|
364
|
-
*/ async getBlock(
|
|
365
|
-
|
|
366
|
-
|
|
817
|
+
*/ async getBlock(block) {
|
|
818
|
+
if (BlockHash.isBlockHash(block)) {
|
|
819
|
+
return this.getBlockByHash(block);
|
|
820
|
+
}
|
|
821
|
+
const blockNumber = block === 'latest' ? await this.getBlockNumber() : block;
|
|
822
|
+
if (blockNumber === BlockNumber.ZERO) {
|
|
823
|
+
return this.buildInitialBlock();
|
|
824
|
+
}
|
|
825
|
+
return await this.blockSource.getL2Block(blockNumber);
|
|
367
826
|
}
|
|
368
827
|
/**
|
|
369
828
|
* Get a block specified by its hash.
|
|
370
829
|
* @param blockHash - The block hash being requested.
|
|
371
830
|
* @returns The requested block.
|
|
372
831
|
*/ async getBlockByHash(blockHash) {
|
|
373
|
-
const
|
|
374
|
-
|
|
832
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
833
|
+
if (blockHash.equals(initialBlockHash)) {
|
|
834
|
+
return this.buildInitialBlock();
|
|
835
|
+
}
|
|
836
|
+
return await this.blockSource.getL2BlockByHash(blockHash);
|
|
837
|
+
}
|
|
838
|
+
buildInitialBlock() {
|
|
839
|
+
const initialHeader = this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
840
|
+
return L2Block.empty(initialHeader);
|
|
375
841
|
}
|
|
376
842
|
/**
|
|
377
843
|
* Get a block specified by its archive root.
|
|
378
844
|
* @param archive - The archive root being requested.
|
|
379
845
|
* @returns The requested block.
|
|
380
846
|
*/ async getBlockByArchive(archive) {
|
|
381
|
-
|
|
382
|
-
return publishedBlock?.block;
|
|
847
|
+
return await this.blockSource.getL2BlockByArchive(archive);
|
|
383
848
|
}
|
|
384
849
|
/**
|
|
385
850
|
* Method to request blocks. Will attempt to return all requested blocks but will return only those available.
|
|
@@ -387,16 +852,28 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
387
852
|
* @param limit - The maximum number of blocks to obtain.
|
|
388
853
|
* @returns The blocks requested.
|
|
389
854
|
*/ async getBlocks(from, limit) {
|
|
390
|
-
return await this.blockSource.getBlocks(from, limit) ?? [];
|
|
855
|
+
return await this.blockSource.getBlocks(from, BlockNumber(limit)) ?? [];
|
|
856
|
+
}
|
|
857
|
+
async getCheckpoints(from, limit) {
|
|
858
|
+
return await this.blockSource.getCheckpoints(from, limit) ?? [];
|
|
391
859
|
}
|
|
392
|
-
async
|
|
393
|
-
return await this.blockSource.
|
|
860
|
+
async getCheckpointedBlocks(from, limit) {
|
|
861
|
+
return await this.blockSource.getCheckpointedBlocks(from, limit) ?? [];
|
|
394
862
|
}
|
|
395
863
|
/**
|
|
396
|
-
* Method to fetch the current
|
|
397
|
-
* @returns The current
|
|
398
|
-
*/ async
|
|
399
|
-
return await this.globalVariableBuilder.
|
|
864
|
+
* Method to fetch the current min L2 fees.
|
|
865
|
+
* @returns The current min L2 fees.
|
|
866
|
+
*/ async getCurrentMinFees() {
|
|
867
|
+
return await this.globalVariableBuilder.getCurrentMinFees();
|
|
868
|
+
}
|
|
869
|
+
async getMaxPriorityFees() {
|
|
870
|
+
for await (const tx of this.p2pClient.iteratePendingTxs()){
|
|
871
|
+
return tx.getGasSettings().maxPriorityFeesPerGas;
|
|
872
|
+
}
|
|
873
|
+
return GasFees.from({
|
|
874
|
+
feePerDaGas: 0n,
|
|
875
|
+
feePerL2Gas: 0n
|
|
876
|
+
});
|
|
400
877
|
}
|
|
401
878
|
/**
|
|
402
879
|
* Method to fetch the latest block number synchronized by the node.
|
|
@@ -407,6 +884,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
407
884
|
async getProvenBlockNumber() {
|
|
408
885
|
return await this.blockSource.getProvenBlockNumber();
|
|
409
886
|
}
|
|
887
|
+
async getCheckpointedBlockNumber() {
|
|
888
|
+
return await this.blockSource.getCheckpointedL2BlockNumber();
|
|
889
|
+
}
|
|
410
890
|
/**
|
|
411
891
|
* Method to fetch the version of the package.
|
|
412
892
|
* @returns The node package version
|
|
@@ -431,22 +911,29 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
431
911
|
getContract(address) {
|
|
432
912
|
return this.contractDataSource.getContract(address);
|
|
433
913
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
914
|
+
async getPrivateLogsByTags(tags, page, referenceBlock) {
|
|
915
|
+
if (referenceBlock) {
|
|
916
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
917
|
+
if (!referenceBlock.equals(initialBlockHash)) {
|
|
918
|
+
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
919
|
+
if (!header) {
|
|
920
|
+
throw new Error(`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return this.logsSource.getPrivateLogsByTags(tags, page);
|
|
925
|
+
}
|
|
926
|
+
async getPublicLogsByTagsFromContract(contractAddress, tags, page, referenceBlock) {
|
|
927
|
+
if (referenceBlock) {
|
|
928
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
929
|
+
if (!referenceBlock.equals(initialBlockHash)) {
|
|
930
|
+
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
931
|
+
if (!header) {
|
|
932
|
+
throw new Error(`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
450
937
|
}
|
|
451
938
|
/**
|
|
452
939
|
* Gets public logs based on the provided filter.
|
|
@@ -466,7 +953,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
466
953
|
* Method to submit a transaction to the p2p pool.
|
|
467
954
|
* @param tx - The transaction to be submitted.
|
|
468
955
|
*/ async sendTx(tx) {
|
|
469
|
-
await this
|
|
956
|
+
await this.#sendTx(tx);
|
|
470
957
|
}
|
|
471
958
|
async #sendTx(tx) {
|
|
472
959
|
const timer = new Timer();
|
|
@@ -487,18 +974,24 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
487
974
|
});
|
|
488
975
|
}
|
|
489
976
|
async getTxReceipt(txHash) {
|
|
490
|
-
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
txReceipt = new TxReceipt(txHash, TxStatus.PENDING, '');
|
|
496
|
-
}
|
|
977
|
+
// Check the tx pool status first. If the tx is known to the pool (pending or mined), we'll use that
|
|
978
|
+
// as a fallback if we don't find a settled receipt in the archiver.
|
|
979
|
+
const txPoolStatus = await this.p2pClient.getTxStatus(txHash);
|
|
980
|
+
const isKnownToPool = txPoolStatus === 'pending' || txPoolStatus === 'mined';
|
|
981
|
+
// Then get the actual tx from the archiver, which tracks every tx in a mined block.
|
|
497
982
|
const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
|
|
498
983
|
if (settledTxReceipt) {
|
|
499
|
-
|
|
984
|
+
// If the archiver has the receipt then return it.
|
|
985
|
+
return settledTxReceipt;
|
|
986
|
+
} else if (isKnownToPool) {
|
|
987
|
+
// If the tx is in the pool but not in the archiver, it's pending.
|
|
988
|
+
// This handles race conditions between archiver and p2p, where the archiver
|
|
989
|
+
// has pruned the block in which a tx was mined, but p2p has not caught up yet.
|
|
990
|
+
return new TxReceipt(txHash, TxStatus.PENDING, undefined, undefined);
|
|
991
|
+
} else {
|
|
992
|
+
// Otherwise, if we don't know the tx, we consider it dropped.
|
|
993
|
+
return new TxReceipt(txHash, TxStatus.DROPPED, undefined, 'Tx dropped by P2P node');
|
|
500
994
|
}
|
|
501
|
-
return txReceipt;
|
|
502
995
|
}
|
|
503
996
|
getTxEffect(txHash) {
|
|
504
997
|
return this.blockSource.getTxEffect(txHash);
|
|
@@ -507,19 +1000,26 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
507
1000
|
* Method to stop the aztec node.
|
|
508
1001
|
*/ async stop() {
|
|
509
1002
|
this.log.info(`Stopping Aztec Node`);
|
|
510
|
-
await this.txQueue.end();
|
|
511
1003
|
await tryStop(this.validatorsSentinel);
|
|
512
1004
|
await tryStop(this.epochPruneWatcher);
|
|
513
1005
|
await tryStop(this.slasherClient);
|
|
514
1006
|
await tryStop(this.proofVerifier);
|
|
515
1007
|
await tryStop(this.sequencer);
|
|
1008
|
+
await tryStop(this.proverNode);
|
|
516
1009
|
await tryStop(this.p2pClient);
|
|
517
1010
|
await tryStop(this.worldStateSynchronizer);
|
|
518
1011
|
await tryStop(this.blockSource);
|
|
1012
|
+
await tryStop(this.blobClient);
|
|
519
1013
|
await tryStop(this.telemetry);
|
|
520
1014
|
this.log.info(`Stopped Aztec Node`);
|
|
521
1015
|
}
|
|
522
1016
|
/**
|
|
1017
|
+
* Returns the blob client used by this node.
|
|
1018
|
+
* @internal - Exposed for testing purposes only.
|
|
1019
|
+
*/ getBlobClient() {
|
|
1020
|
+
return this.blobClient;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
523
1023
|
* Method to retrieve pending txs.
|
|
524
1024
|
* @param limit - The number of items to returns
|
|
525
1025
|
* @param after - The last known pending tx. Used for pagination
|
|
@@ -544,15 +1044,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
544
1044
|
*/ async getTxsByHash(txHashes) {
|
|
545
1045
|
return compactArray(await Promise.all(txHashes.map((txHash)=>this.getTxByHash(txHash))));
|
|
546
1046
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
* the leaves were inserted.
|
|
550
|
-
* @param blockNumber - The block number at which to get the data or 'latest' for latest data.
|
|
551
|
-
* @param treeId - The tree to search in.
|
|
552
|
-
* @param leafValues - The values to search for.
|
|
553
|
-
* @returns The indices of leaves and the block metadata of a block in which the leaves were inserted.
|
|
554
|
-
*/ async findLeavesIndexes(blockNumber, treeId, leafValues) {
|
|
555
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
1047
|
+
async findLeavesIndexes(referenceBlock, treeId, leafValues) {
|
|
1048
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
556
1049
|
const maybeIndices = await committedDb.findLeafIndices(treeId, leafValues.map((x)=>x.toBuffer()));
|
|
557
1050
|
// We filter out undefined values
|
|
558
1051
|
const indices = maybeIndices.filter((x)=>x !== undefined);
|
|
@@ -571,7 +1064,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
571
1064
|
// Now we obtain the block hashes from the archive tree by calling await `committedDb.getLeafValue(treeId, index)`
|
|
572
1065
|
// (note that block number corresponds to the leaf index in the archive tree).
|
|
573
1066
|
const blockHashes = await Promise.all(uniqueBlockNumbers.map((blockNumber)=>{
|
|
574
|
-
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, blockNumber);
|
|
1067
|
+
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
575
1068
|
}));
|
|
576
1069
|
// If any of the block hashes are undefined, we throw an error.
|
|
577
1070
|
for(let i = 0; i < uniqueBlockNumbers.length; i++){
|
|
@@ -579,7 +1072,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
579
1072
|
throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
|
|
580
1073
|
}
|
|
581
1074
|
}
|
|
582
|
-
// Create
|
|
1075
|
+
// Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
|
|
583
1076
|
return maybeIndices.map((index, i)=>{
|
|
584
1077
|
if (index === undefined) {
|
|
585
1078
|
return undefined;
|
|
@@ -594,51 +1087,28 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
594
1087
|
return undefined;
|
|
595
1088
|
}
|
|
596
1089
|
return {
|
|
597
|
-
l2BlockNumber: Number(blockNumber),
|
|
598
|
-
l2BlockHash:
|
|
1090
|
+
l2BlockNumber: BlockNumber(Number(blockNumber)),
|
|
1091
|
+
l2BlockHash: new BlockHash(blockHash),
|
|
599
1092
|
data: index
|
|
600
1093
|
};
|
|
601
1094
|
});
|
|
602
1095
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
* @param blockNumber - The block number at which to get the data.
|
|
606
|
-
* @param leafIndex - The index of the leaf for which the sibling path is required.
|
|
607
|
-
* @returns The sibling path for the leaf index.
|
|
608
|
-
*/ async getNullifierSiblingPath(blockNumber, leafIndex) {
|
|
609
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
610
|
-
return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Returns a sibling path for the given index in the data tree.
|
|
614
|
-
* @param blockNumber - The block number at which to get the data.
|
|
615
|
-
* @param leafIndex - The index of the leaf for which the sibling path is required.
|
|
616
|
-
* @returns The sibling path for the leaf index.
|
|
617
|
-
*/ async getNoteHashSiblingPath(blockNumber, leafIndex) {
|
|
618
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
619
|
-
return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
|
|
620
|
-
}
|
|
621
|
-
async getArchiveMembershipWitness(blockNumber, archive) {
|
|
622
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
1096
|
+
async getBlockHashMembershipWitness(referenceBlock, blockHash) {
|
|
1097
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
623
1098
|
const [pathAndIndex] = await committedDb.findSiblingPaths(MerkleTreeId.ARCHIVE, [
|
|
624
|
-
|
|
1099
|
+
blockHash
|
|
625
1100
|
]);
|
|
626
1101
|
return pathAndIndex === undefined ? undefined : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
627
1102
|
}
|
|
628
|
-
async getNoteHashMembershipWitness(
|
|
629
|
-
const committedDb = await this.#getWorldState(
|
|
1103
|
+
async getNoteHashMembershipWitness(referenceBlock, noteHash) {
|
|
1104
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
630
1105
|
const [pathAndIndex] = await committedDb.findSiblingPaths(MerkleTreeId.NOTE_HASH_TREE, [
|
|
631
1106
|
noteHash
|
|
632
1107
|
]);
|
|
633
1108
|
return pathAndIndex === undefined ? undefined : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
634
1109
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
* @param blockNumber - The block number at which to get the data.
|
|
638
|
-
* @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
|
|
639
|
-
* @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
|
|
640
|
-
*/ async getL1ToL2MessageMembershipWitness(blockNumber, l1ToL2Message) {
|
|
641
|
-
const db = await this.#getWorldState(blockNumber);
|
|
1110
|
+
async getL1ToL2MessageMembershipWitness(referenceBlock, l1ToL2Message) {
|
|
1111
|
+
const db = await this.#getWorldState(referenceBlock);
|
|
642
1112
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [
|
|
643
1113
|
l1ToL2Message
|
|
644
1114
|
]);
|
|
@@ -653,7 +1123,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
653
1123
|
}
|
|
654
1124
|
async getL1ToL2MessageBlock(l1ToL2Message) {
|
|
655
1125
|
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
656
|
-
return messageIndex ? InboxLeaf.
|
|
1126
|
+
return messageIndex ? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex)) : undefined;
|
|
657
1127
|
}
|
|
658
1128
|
/**
|
|
659
1129
|
* Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
|
|
@@ -664,38 +1134,29 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
664
1134
|
return messageIndex !== undefined;
|
|
665
1135
|
}
|
|
666
1136
|
/**
|
|
667
|
-
* Returns all the L2 to L1 messages in
|
|
668
|
-
* @param
|
|
669
|
-
* @returns The L2 to L1 messages (
|
|
670
|
-
*/ async getL2ToL1Messages(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
* @returns The sibling path.
|
|
688
|
-
*/ async getPublicDataSiblingPath(blockNumber, leafIndex) {
|
|
689
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
690
|
-
return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
|
|
1137
|
+
* Returns all the L2 to L1 messages in an epoch.
|
|
1138
|
+
* @param epoch - The epoch at which to get the data.
|
|
1139
|
+
* @returns The L2 to L1 messages (empty array if the epoch is not found).
|
|
1140
|
+
*/ async getL2ToL1Messages(epoch) {
|
|
1141
|
+
// Assumes `getCheckpointedBlocksForEpoch` returns blocks in ascending order of block number.
|
|
1142
|
+
const checkpointedBlocks = await this.blockSource.getCheckpointedBlocksForEpoch(epoch);
|
|
1143
|
+
const blocksInCheckpoints = [];
|
|
1144
|
+
let previousSlotNumber = SlotNumber.ZERO;
|
|
1145
|
+
let checkpointIndex = -1;
|
|
1146
|
+
for (const checkpointedBlock of checkpointedBlocks){
|
|
1147
|
+
const block = checkpointedBlock.block;
|
|
1148
|
+
const slotNumber = block.header.globalVariables.slotNumber;
|
|
1149
|
+
if (slotNumber !== previousSlotNumber) {
|
|
1150
|
+
checkpointIndex++;
|
|
1151
|
+
blocksInCheckpoints.push([]);
|
|
1152
|
+
previousSlotNumber = slotNumber;
|
|
1153
|
+
}
|
|
1154
|
+
blocksInCheckpoints[checkpointIndex].push(block);
|
|
1155
|
+
}
|
|
1156
|
+
return blocksInCheckpoints.map((blocks)=>blocks.map((block)=>block.body.txEffects.map((txEffect)=>txEffect.l2ToL1Msgs)));
|
|
691
1157
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
* @param blockNumber - The block number at which to get the index.
|
|
695
|
-
* @param nullifier - Nullifier we try to find witness for.
|
|
696
|
-
* @returns The nullifier membership witness (if found).
|
|
697
|
-
*/ async getNullifierMembershipWitness(blockNumber, nullifier) {
|
|
698
|
-
const db = await this.#getWorldState(blockNumber);
|
|
1158
|
+
async getNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1159
|
+
const db = await this.#getWorldState(referenceBlock);
|
|
699
1160
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [
|
|
700
1161
|
nullifier.toBuffer()
|
|
701
1162
|
]);
|
|
@@ -711,7 +1172,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
711
1172
|
}
|
|
712
1173
|
/**
|
|
713
1174
|
* Returns a low nullifier membership witness for a given nullifier at a given block.
|
|
714
|
-
* @param
|
|
1175
|
+
* @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data
|
|
1176
|
+
* (which contains the root of the nullifier tree in which we are searching for the nullifier).
|
|
715
1177
|
* @param nullifier - Nullifier we try to find the low nullifier witness for.
|
|
716
1178
|
* @returns The low nullifier membership witness (if found).
|
|
717
1179
|
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
|
|
@@ -722,8 +1184,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
722
1184
|
* the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the
|
|
723
1185
|
* index of the nullifier itself when it already exists in the tree.
|
|
724
1186
|
* TODO: This is a confusing behavior and we should eventually address that.
|
|
725
|
-
*/ async getLowNullifierMembershipWitness(
|
|
726
|
-
const committedDb = await this.#getWorldState(
|
|
1187
|
+
*/ async getLowNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1188
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
727
1189
|
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
728
1190
|
if (!findResult) {
|
|
729
1191
|
return undefined;
|
|
@@ -736,8 +1198,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
736
1198
|
const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
|
|
737
1199
|
return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
|
|
738
1200
|
}
|
|
739
|
-
async getPublicDataWitness(
|
|
740
|
-
const committedDb = await this.#getWorldState(
|
|
1201
|
+
async getPublicDataWitness(referenceBlock, leafSlot) {
|
|
1202
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
741
1203
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
742
1204
|
if (!lowLeafResult) {
|
|
743
1205
|
return undefined;
|
|
@@ -747,18 +1209,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
747
1209
|
return new PublicDataWitness(lowLeafResult.index, preimage, path);
|
|
748
1210
|
}
|
|
749
1211
|
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
*
|
|
753
|
-
* @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
|
|
754
|
-
* Aztec's version of `eth_getStorageAt`.
|
|
755
|
-
*
|
|
756
|
-
* @param contract - Address of the contract to query.
|
|
757
|
-
* @param slot - Slot to query.
|
|
758
|
-
* @param blockNumber - The block number at which to get the data or 'latest'.
|
|
759
|
-
* @returns Storage value at the given contract slot.
|
|
760
|
-
*/ async getPublicStorageAt(blockNumber, contract, slot) {
|
|
761
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
1212
|
+
async getPublicStorageAt(referenceBlock, contract, slot) {
|
|
1213
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
762
1214
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
763
1215
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
764
1216
|
if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
|
|
@@ -767,18 +1219,22 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
767
1219
|
const preimage = await committedDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
768
1220
|
return preimage.leaf.value;
|
|
769
1221
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1222
|
+
async getBlockHeader(block = 'latest') {
|
|
1223
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1224
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1225
|
+
if (block.equals(initialBlockHash)) {
|
|
1226
|
+
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1227
|
+
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1228
|
+
}
|
|
1229
|
+
return this.blockSource.getBlockHeaderByHash(block);
|
|
1230
|
+
} else {
|
|
1231
|
+
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1232
|
+
const blockNumber = block === 'latest' ? await this.getBlockNumber() : block;
|
|
1233
|
+
if (blockNumber === BlockNumber.ZERO) {
|
|
1234
|
+
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1235
|
+
}
|
|
1236
|
+
return this.blockSource.getBlockHeader(block);
|
|
1237
|
+
}
|
|
782
1238
|
}
|
|
783
1239
|
/**
|
|
784
1240
|
* Get a block header specified by its archive root.
|
|
@@ -787,6 +1243,12 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
787
1243
|
*/ async getBlockHeaderByArchive(archive) {
|
|
788
1244
|
return await this.blockSource.getBlockHeaderByArchive(archive);
|
|
789
1245
|
}
|
|
1246
|
+
getBlockData(number) {
|
|
1247
|
+
return this.blockSource.getBlockData(number);
|
|
1248
|
+
}
|
|
1249
|
+
getBlockDataByArchive(archive) {
|
|
1250
|
+
return this.blockSource.getBlockDataByArchive(archive);
|
|
1251
|
+
}
|
|
790
1252
|
/**
|
|
791
1253
|
* Simulates the public part of a transaction with the current state.
|
|
792
1254
|
* @param tx - The transaction to simulate.
|
|
@@ -799,22 +1261,35 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
799
1261
|
throw new BadRequestError(`Transaction total gas limit ${txGasLimit + teardownGasLimit} (${txGasLimit} + ${teardownGasLimit}) exceeds maximum gas limit ${this.config.rpcSimulatePublicMaxGasLimit} for simulation`);
|
|
800
1262
|
}
|
|
801
1263
|
const txHash = tx.getTxHash();
|
|
802
|
-
const
|
|
1264
|
+
const latestBlockNumber = await this.blockSource.getBlockNumber();
|
|
1265
|
+
const blockNumber = BlockNumber.add(latestBlockNumber, 1);
|
|
803
1266
|
// If sequencer is not initialized, we just set these values to zero for simulation.
|
|
804
1267
|
const coinbase = EthAddress.ZERO;
|
|
805
1268
|
const feeRecipient = AztecAddress.ZERO;
|
|
806
1269
|
const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(blockNumber, coinbase, feeRecipient);
|
|
807
|
-
const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, new DateProvider(), this.telemetry);
|
|
1270
|
+
const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, new DateProvider(), this.telemetry, this.log.getBindings());
|
|
808
1271
|
this.log.verbose(`Simulating public calls for tx ${txHash}`, {
|
|
809
1272
|
globalVariables: newGlobalVariables.toInspect(),
|
|
810
1273
|
txHash,
|
|
811
1274
|
blockNumber
|
|
812
1275
|
});
|
|
1276
|
+
// Ensure world-state has caught up with the latest block we loaded from the archiver
|
|
1277
|
+
await this.worldStateSynchronizer.syncImmediate(latestBlockNumber);
|
|
813
1278
|
const merkleTreeFork = await this.worldStateSynchronizer.fork();
|
|
814
1279
|
try {
|
|
815
|
-
const
|
|
1280
|
+
const config = PublicSimulatorConfig.from({
|
|
1281
|
+
skipFeeEnforcement,
|
|
1282
|
+
collectDebugLogs: true,
|
|
1283
|
+
collectHints: false,
|
|
1284
|
+
collectCallMetadata: true,
|
|
1285
|
+
collectStatistics: false,
|
|
1286
|
+
collectionLimits: CollectionLimitsConfig.from({
|
|
1287
|
+
maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads
|
|
1288
|
+
})
|
|
1289
|
+
});
|
|
1290
|
+
const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
|
|
816
1291
|
// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
|
|
817
|
-
const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([
|
|
1292
|
+
const [processedTxs, failedTxs, _usedTxs, returns, _blobFields, debugLogs] = await processor.process([
|
|
818
1293
|
tx
|
|
819
1294
|
]);
|
|
820
1295
|
// REFACTOR: Consider returning the error rather than throwing
|
|
@@ -825,7 +1300,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
825
1300
|
throw failedTxs[0].error;
|
|
826
1301
|
}
|
|
827
1302
|
const [processedTx] = processedTxs;
|
|
828
|
-
return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed);
|
|
1303
|
+
return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed, debugLogs);
|
|
829
1304
|
} finally{
|
|
830
1305
|
await merkleTreeFork.close();
|
|
831
1306
|
}
|
|
@@ -833,19 +1308,19 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
833
1308
|
async isValidTx(tx, { isSimulation, skipFeeEnforcement } = {}) {
|
|
834
1309
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
835
1310
|
const verifier = isSimulation ? undefined : this.proofVerifier;
|
|
836
|
-
// We accept transactions if they are not expired by the next slot (checked based on the
|
|
1311
|
+
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
837
1312
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
838
|
-
const blockNumber = await this.blockSource.getBlockNumber() + 1;
|
|
1313
|
+
const blockNumber = BlockNumber(await this.blockSource.getBlockNumber() + 1);
|
|
839
1314
|
const validator = createValidatorForAcceptingTxs(db, this.contractDataSource, verifier, {
|
|
840
1315
|
timestamp: nextSlotTimestamp,
|
|
841
1316
|
blockNumber,
|
|
842
1317
|
l1ChainId: this.l1ChainId,
|
|
843
1318
|
rollupVersion: this.version,
|
|
844
1319
|
setupAllowList: this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions(),
|
|
845
|
-
gasFees: await this.
|
|
1320
|
+
gasFees: await this.getCurrentMinFees(),
|
|
846
1321
|
skipFeeEnforcement,
|
|
847
1322
|
txsPermitted: !this.config.disableTransactions
|
|
848
|
-
});
|
|
1323
|
+
}, this.log.getBindings());
|
|
849
1324
|
return await validator.validateTx(tx);
|
|
850
1325
|
}
|
|
851
1326
|
getConfig() {
|
|
@@ -896,26 +1371,33 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
896
1371
|
// We break support for archiver running remotely to the node
|
|
897
1372
|
const archiver = this.blockSource;
|
|
898
1373
|
if (!('backupTo' in archiver)) {
|
|
1374
|
+
this.metrics.recordSnapshotError();
|
|
899
1375
|
throw new Error('Archiver implementation does not support backups. Cannot generate snapshot.');
|
|
900
1376
|
}
|
|
901
1377
|
// Test that the archiver has done an initial sync.
|
|
902
1378
|
if (!archiver.isInitialSyncComplete()) {
|
|
1379
|
+
this.metrics.recordSnapshotError();
|
|
903
1380
|
throw new Error(`Archiver initial sync not complete. Cannot start snapshot.`);
|
|
904
1381
|
}
|
|
905
1382
|
// And it has an L2 block hash
|
|
906
|
-
const l2BlockHash = await archiver.getL2Tips().then((tips)=>tips.
|
|
1383
|
+
const l2BlockHash = await archiver.getL2Tips().then((tips)=>tips.proposed.hash);
|
|
907
1384
|
if (!l2BlockHash) {
|
|
1385
|
+
this.metrics.recordSnapshotError();
|
|
908
1386
|
throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
|
|
909
1387
|
}
|
|
910
1388
|
if (this.isUploadingSnapshot) {
|
|
1389
|
+
this.metrics.recordSnapshotError();
|
|
911
1390
|
throw new Error(`Snapshot upload already in progress. Cannot start another one until complete.`);
|
|
912
1391
|
}
|
|
913
1392
|
// Do not wait for the upload to be complete to return to the caller, but flag that an operation is in progress
|
|
914
1393
|
this.isUploadingSnapshot = true;
|
|
1394
|
+
const timer = new Timer();
|
|
915
1395
|
void uploadSnapshot(location, this.blockSource, this.worldStateSynchronizer, this.config, this.log).then(()=>{
|
|
916
1396
|
this.isUploadingSnapshot = false;
|
|
1397
|
+
this.metrics.recordSnapshot(timer.ms());
|
|
917
1398
|
}).catch((err)=>{
|
|
918
1399
|
this.isUploadingSnapshot = false;
|
|
1400
|
+
this.metrics.recordSnapshotError();
|
|
919
1401
|
this.log.error(`Error uploading snapshot: ${err}`);
|
|
920
1402
|
});
|
|
921
1403
|
return Promise.resolve();
|
|
@@ -925,7 +1407,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
925
1407
|
if (!('rollbackTo' in archiver)) {
|
|
926
1408
|
throw new Error('Archiver implementation does not support rollbacks.');
|
|
927
1409
|
}
|
|
928
|
-
const finalizedBlock = await archiver.getL2Tips().then((tips)=>tips.finalized.number);
|
|
1410
|
+
const finalizedBlock = await archiver.getL2Tips().then((tips)=>tips.finalized.block.number);
|
|
929
1411
|
if (targetBlock < finalizedBlock) {
|
|
930
1412
|
if (force) {
|
|
931
1413
|
this.log.warn(`Clearing world state database to allow rolling back behind finalized block ${finalizedBlock}`);
|
|
@@ -980,30 +1462,117 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
980
1462
|
return this.slasherClient.gatherOffensesForRound(round === 'current' ? undefined : BigInt(round));
|
|
981
1463
|
}
|
|
982
1464
|
}
|
|
1465
|
+
async reloadKeystore() {
|
|
1466
|
+
if (!this.config.keyStoreDirectory?.length) {
|
|
1467
|
+
throw new BadRequestError('Cannot reload keystore: node is not using a file-based keystore. ' + 'Set KEY_STORE_DIRECTORY to use file-based keystores.');
|
|
1468
|
+
}
|
|
1469
|
+
if (!this.validatorClient) {
|
|
1470
|
+
throw new BadRequestError('Cannot reload keystore: validator is not enabled.');
|
|
1471
|
+
}
|
|
1472
|
+
this.log.info('Reloading keystore from disk');
|
|
1473
|
+
// Re-read and validate keystore files
|
|
1474
|
+
const keyStores = loadKeystores(this.config.keyStoreDirectory);
|
|
1475
|
+
const newManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
1476
|
+
await newManager.validateSigners();
|
|
1477
|
+
ValidatorClient.validateKeyStoreConfiguration(newManager, this.log);
|
|
1478
|
+
// Validate that every validator's publisher keys overlap with the L1 signers
|
|
1479
|
+
// that were initialized at startup. Publishers cannot be hot-reloaded, so a
|
|
1480
|
+
// validator with a publisher key that doesn't match any existing L1 signer
|
|
1481
|
+
// would silently fail on every proposer slot.
|
|
1482
|
+
if (this.keyStoreManager && this.sequencer) {
|
|
1483
|
+
const oldAdapter = NodeKeystoreAdapter.fromKeyStoreManager(this.keyStoreManager);
|
|
1484
|
+
const availablePublishers = new Set(oldAdapter.getAttesterAddresses().flatMap((a)=>oldAdapter.getPublisherAddresses(a).map((p)=>p.toString().toLowerCase())));
|
|
1485
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
1486
|
+
for (const attester of newAdapter.getAttesterAddresses()){
|
|
1487
|
+
const pubs = newAdapter.getPublisherAddresses(attester);
|
|
1488
|
+
if (pubs.length > 0 && !pubs.some((p)=>availablePublishers.has(p.toString().toLowerCase()))) {
|
|
1489
|
+
throw new BadRequestError(`Cannot reload keystore: validator ${attester} has publisher keys ` + `[${pubs.map((p)=>p.toString()).join(', ')}] but none match the L1 signers initialized at startup ` + `[${[
|
|
1490
|
+
...availablePublishers
|
|
1491
|
+
].join(', ')}]. Publishers cannot be hot-reloaded — ` + `use an existing publisher key or restart the node.`);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
// Build adapters for old and new keystores to compute diff
|
|
1496
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
1497
|
+
const newAddresses = newAdapter.getAttesterAddresses();
|
|
1498
|
+
const oldAddresses = this.keyStoreManager ? NodeKeystoreAdapter.fromKeyStoreManager(this.keyStoreManager).getAttesterAddresses() : [];
|
|
1499
|
+
const oldSet = new Set(oldAddresses.map((a)=>a.toString()));
|
|
1500
|
+
const newSet = new Set(newAddresses.map((a)=>a.toString()));
|
|
1501
|
+
const added = newAddresses.filter((a)=>!oldSet.has(a.toString()));
|
|
1502
|
+
const removed = oldAddresses.filter((a)=>!newSet.has(a.toString()));
|
|
1503
|
+
if (added.length > 0) {
|
|
1504
|
+
this.log.info(`Keystore reload: adding attester keys: ${added.map((a)=>a.toString()).join(', ')}`);
|
|
1505
|
+
}
|
|
1506
|
+
if (removed.length > 0) {
|
|
1507
|
+
this.log.info(`Keystore reload: removing attester keys: ${removed.map((a)=>a.toString()).join(', ')}`);
|
|
1508
|
+
}
|
|
1509
|
+
if (added.length === 0 && removed.length === 0) {
|
|
1510
|
+
this.log.info('Keystore reload: attester keys unchanged');
|
|
1511
|
+
}
|
|
1512
|
+
// Update the validator client (coinbase, feeRecipient, attester keys)
|
|
1513
|
+
this.validatorClient.reloadKeystore(newManager);
|
|
1514
|
+
// Update the publisher factory's keystore so newly-added validators
|
|
1515
|
+
// can be matched to existing publisher keys when proposing blocks.
|
|
1516
|
+
if (this.sequencer) {
|
|
1517
|
+
this.sequencer.updatePublisherNodeKeyStore(newAdapter);
|
|
1518
|
+
}
|
|
1519
|
+
// Update slasher's "don't-slash-self" list with new validator addresses
|
|
1520
|
+
if (this.slasherClient && !this.config.slashSelfAllowed) {
|
|
1521
|
+
const slashValidatorsNever = unique([
|
|
1522
|
+
...this.config.slashValidatorsNever ?? [],
|
|
1523
|
+
...newAddresses
|
|
1524
|
+
].map((a)=>a.toString())).map(EthAddress.fromString);
|
|
1525
|
+
this.slasherClient.updateConfig({
|
|
1526
|
+
slashValidatorsNever
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
this.keyStoreManager = newManager;
|
|
1530
|
+
this.log.info('Keystore reloaded: coinbase, feeRecipient, and attester keys updated');
|
|
1531
|
+
}
|
|
1532
|
+
#getInitialHeaderHash() {
|
|
1533
|
+
if (!this.initialHeaderHashPromise) {
|
|
1534
|
+
this.initialHeaderHashPromise = this.worldStateSynchronizer.getCommitted().getInitialHeader().hash();
|
|
1535
|
+
}
|
|
1536
|
+
return this.initialHeaderHashPromise;
|
|
1537
|
+
}
|
|
983
1538
|
/**
|
|
984
1539
|
* Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
|
|
985
|
-
* @param
|
|
1540
|
+
* @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
|
|
986
1541
|
* @returns An instance of a committed MerkleTreeOperations
|
|
987
|
-
*/ async #getWorldState(
|
|
988
|
-
|
|
989
|
-
throw new Error('Invalid block number to get world state for: ' + blockNumber);
|
|
990
|
-
}
|
|
991
|
-
let blockSyncedTo = 0;
|
|
1542
|
+
*/ async #getWorldState(block) {
|
|
1543
|
+
let blockSyncedTo = BlockNumber.ZERO;
|
|
992
1544
|
try {
|
|
993
1545
|
// Attempt to sync the world state if necessary
|
|
994
1546
|
blockSyncedTo = await this.#syncWorldState();
|
|
995
1547
|
} catch (err) {
|
|
996
1548
|
this.log.error(`Error getting world state: ${err}`);
|
|
997
1549
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
this.log.debug(`Using committed db for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1550
|
+
if (block === 'latest') {
|
|
1551
|
+
this.log.debug(`Using committed db for block 'latest', world state synced upto ${blockSyncedTo}`);
|
|
1001
1552
|
return this.worldStateSynchronizer.getCommitted();
|
|
1002
|
-
}
|
|
1553
|
+
}
|
|
1554
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1555
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1556
|
+
if (block.equals(initialBlockHash)) {
|
|
1557
|
+
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1558
|
+
return this.worldStateSynchronizer.getSnapshot(BlockNumber.ZERO);
|
|
1559
|
+
}
|
|
1560
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1561
|
+
if (!header) {
|
|
1562
|
+
throw new Error(`Block hash ${block.toString()} not found when querying world state. If the node API has been queried with anchor block hash possibly a reorg has occurred.`);
|
|
1563
|
+
}
|
|
1564
|
+
const blockNumber = header.getBlockNumber();
|
|
1565
|
+
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1566
|
+
return this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1567
|
+
}
|
|
1568
|
+
// Block number provided
|
|
1569
|
+
{
|
|
1570
|
+
const blockNumber = block;
|
|
1571
|
+
if (blockNumber > blockSyncedTo) {
|
|
1572
|
+
throw new Error(`Queried block ${block} not yet synced by the node (node is synced upto ${blockSyncedTo}).`);
|
|
1573
|
+
}
|
|
1003
1574
|
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1004
1575
|
return this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1005
|
-
} else {
|
|
1006
|
-
throw new Error(`Block ${blockNumber} not yet synced`);
|
|
1007
1576
|
}
|
|
1008
1577
|
}
|
|
1009
1578
|
/**
|
|
@@ -1011,11 +1580,6 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
1011
1580
|
* @returns A promise that fulfils once the world state is synced
|
|
1012
1581
|
*/ async #syncWorldState() {
|
|
1013
1582
|
const blockSourceHeight = await this.blockSource.getBlockNumber();
|
|
1014
|
-
return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
|
|
1583
|
+
return await this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
|
|
1015
1584
|
}
|
|
1016
1585
|
}
|
|
1017
|
-
_ts_decorate([
|
|
1018
|
-
trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
1019
|
-
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
1020
|
-
}))
|
|
1021
|
-
], AztecNodeService.prototype, "simulatePublicCalls", null);
|