@aztec/aztec-node 0.0.1-commit.9593d84 → 0.0.1-commit.96dac018d
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 +1 -1
- package/dest/aztec-node/node_metrics.d.ts.map +1 -1
- package/dest/aztec-node/node_metrics.js +9 -16
- package/dest/aztec-node/server.d.ts +66 -122
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +787 -218
- 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/sentinel.d.ts +6 -5
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +82 -51
- package/dest/sentinel/store.d.ts +2 -2
- package/dest/sentinel/store.d.ts.map +1 -1
- package/dest/sentinel/store.js +11 -7
- package/package.json +30 -28
- package/src/aztec-node/config.ts +34 -14
- package/src/aztec-node/node_metrics.ts +6 -17
- package/src/aztec-node/server.ts +518 -288
- package/src/sentinel/factory.ts +1 -6
- package/src/sentinel/sentinel.ts +94 -52
- package/src/sentinel/store.ts +12 -12
|
@@ -1,18 +1,388 @@
|
|
|
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
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
371
|
+
return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
|
|
6
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
388
|
import { count } from '@aztec/foundation/string';
|
|
@@ -20,30 +390,37 @@ import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
|
20
390
|
import { MembershipWitness } from '@aztec/foundation/trees';
|
|
21
391
|
import { KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
|
|
22
392
|
import { trySnapshotSync, uploadSnapshot } from '@aztec/node-lib/actions';
|
|
23
|
-
import {
|
|
24
|
-
import { createP2PClient, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
393
|
+
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
394
|
+
import { createP2PClient, createTxValidatorForAcceptingTxsOverRPC, getDefaultAllowedSetupFunctions } from '@aztec/p2p';
|
|
25
395
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
26
|
-
import {
|
|
396
|
+
import { createProverNode } from '@aztec/prover-node';
|
|
397
|
+
import { createKeyStoreForProver } from '@aztec/prover-node/config';
|
|
398
|
+
import { GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client';
|
|
27
399
|
import { PublicProcessorFactory } from '@aztec/simulator/server';
|
|
28
400
|
import { AttestationsBlockWatcher, EpochPruneWatcher, createSlasher } from '@aztec/slasher';
|
|
29
|
-
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
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';
|
|
408
|
+
import { InMemoryDebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
35
409
|
import { InboxLeaf } from '@aztec/stdlib/messaging';
|
|
36
410
|
import { P2PClientType } from '@aztec/stdlib/p2p';
|
|
37
411
|
import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
|
|
38
412
|
import { PublicSimulationOutput, TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
39
413
|
import { getPackageVersion } from '@aztec/stdlib/update-checker';
|
|
40
414
|
import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
41
|
-
import { NodeKeystoreAdapter, ValidatorClient, createBlockProposalHandler, createValidatorClient } from '@aztec/validator-client';
|
|
415
|
+
import { FullNodeCheckpointsBuilder as CheckpointsBuilder, FullNodeCheckpointsBuilder, NodeKeystoreAdapter, ValidatorClient, createBlockProposalHandler, createValidatorClient } from '@aztec/validator-client';
|
|
42
416
|
import { createWorldStateSynchronizer } from '@aztec/world-state';
|
|
43
417
|
import { createPublicClient, fallback, http } from 'viem';
|
|
44
418
|
import { createSentinel } from '../sentinel/factory.js';
|
|
45
419
|
import { createKeyStoreForValidator } from './config.js';
|
|
46
420
|
import { NodeMetrics } from './node_metrics.js';
|
|
421
|
+
_dec = trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
422
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
423
|
+
}));
|
|
47
424
|
/**
|
|
48
425
|
* The aztec node.
|
|
49
426
|
*/ export class AztecNodeService {
|
|
@@ -55,6 +432,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
55
432
|
l1ToL2MessageSource;
|
|
56
433
|
worldStateSynchronizer;
|
|
57
434
|
sequencer;
|
|
435
|
+
proverNode;
|
|
58
436
|
slasherClient;
|
|
59
437
|
validatorsSentinel;
|
|
60
438
|
epochPruneWatcher;
|
|
@@ -66,11 +444,25 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
66
444
|
proofVerifier;
|
|
67
445
|
telemetry;
|
|
68
446
|
log;
|
|
447
|
+
blobClient;
|
|
448
|
+
validatorClient;
|
|
449
|
+
keyStoreManager;
|
|
450
|
+
debugLogStore;
|
|
451
|
+
static{
|
|
452
|
+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
|
|
453
|
+
[
|
|
454
|
+
_dec,
|
|
455
|
+
2,
|
|
456
|
+
"simulatePublicCalls"
|
|
457
|
+
]
|
|
458
|
+
], []));
|
|
459
|
+
}
|
|
69
460
|
metrics;
|
|
461
|
+
initialHeaderHashPromise;
|
|
70
462
|
// Prevent two snapshot operations to happen simultaneously
|
|
71
463
|
isUploadingSnapshot;
|
|
72
464
|
tracer;
|
|
73
|
-
constructor(config, p2pClient, blockSource, logsSource, contractDataSource, l1ToL2MessageSource, worldStateSynchronizer, sequencer, slasherClient, validatorsSentinel, epochPruneWatcher, l1ChainId, version, globalVariableBuilder, epochCache, packageVersion, proofVerifier, telemetry = getTelemetryClient(), log = createLogger('node')){
|
|
465
|
+
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, debugLogStore = new NullDebugLogStore()){
|
|
74
466
|
this.config = config;
|
|
75
467
|
this.p2pClient = p2pClient;
|
|
76
468
|
this.blockSource = blockSource;
|
|
@@ -79,6 +471,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
79
471
|
this.l1ToL2MessageSource = l1ToL2MessageSource;
|
|
80
472
|
this.worldStateSynchronizer = worldStateSynchronizer;
|
|
81
473
|
this.sequencer = sequencer;
|
|
474
|
+
this.proverNode = proverNode;
|
|
82
475
|
this.slasherClient = slasherClient;
|
|
83
476
|
this.validatorsSentinel = validatorsSentinel;
|
|
84
477
|
this.epochPruneWatcher = epochPruneWatcher;
|
|
@@ -90,11 +483,22 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
90
483
|
this.proofVerifier = proofVerifier;
|
|
91
484
|
this.telemetry = telemetry;
|
|
92
485
|
this.log = log;
|
|
486
|
+
this.blobClient = blobClient;
|
|
487
|
+
this.validatorClient = validatorClient;
|
|
488
|
+
this.keyStoreManager = keyStoreManager;
|
|
489
|
+
this.debugLogStore = debugLogStore;
|
|
490
|
+
this.initialHeaderHashPromise = (_initProto(this), undefined);
|
|
93
491
|
this.isUploadingSnapshot = false;
|
|
94
492
|
this.metrics = new NodeMetrics(telemetry, 'AztecNodeService');
|
|
95
493
|
this.tracer = telemetry.getTracer('AztecNodeService');
|
|
96
494
|
this.log.info(`Aztec Node version: ${this.packageVersion}`);
|
|
97
495
|
this.log.info(`Aztec Node started on chain 0x${l1ChainId.toString(16)}`, config.l1Contracts);
|
|
496
|
+
// A defensive check that protects us against introducing a bug in the complex `createAndSync` function. We must
|
|
497
|
+
// never have debugLogStore enabled when not in test mode because then we would be accumulating debug logs in
|
|
498
|
+
// memory which could be a DoS vector on the sequencer (since no fees are paid for debug logs).
|
|
499
|
+
if (debugLogStore.isEnabled && config.realProofs) {
|
|
500
|
+
throw new Error('debugLogStore should never be enabled when realProofs are set');
|
|
501
|
+
}
|
|
98
502
|
}
|
|
99
503
|
async getWorldStateSyncStatus() {
|
|
100
504
|
const status = await this.worldStateSynchronizer.status();
|
|
@@ -115,20 +519,28 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
115
519
|
const packageVersion = getPackageVersion() ?? '';
|
|
116
520
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
117
521
|
const dateProvider = deps.dateProvider ?? new DateProvider();
|
|
118
|
-
const blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config, {
|
|
119
|
-
logger: createLogger('node:blob-sink:client')
|
|
120
|
-
});
|
|
121
522
|
const ethereumChain = createEthereumChain(config.l1RpcUrls, config.l1ChainId);
|
|
122
|
-
// Build a key store from file if given or from environment otherwise
|
|
523
|
+
// Build a key store from file if given or from environment otherwise.
|
|
524
|
+
// We keep the raw KeyStore available so we can merge with prover keys if enableProverNode is set.
|
|
123
525
|
let keyStoreManager;
|
|
124
526
|
const keyStoreProvided = config.keyStoreDirectory !== undefined && config.keyStoreDirectory.length > 0;
|
|
125
527
|
if (keyStoreProvided) {
|
|
126
528
|
const keyStores = loadKeystores(config.keyStoreDirectory);
|
|
127
529
|
keyStoreManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
128
530
|
} else {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
531
|
+
const rawKeyStores = [];
|
|
532
|
+
const validatorKeyStore = createKeyStoreForValidator(config);
|
|
533
|
+
if (validatorKeyStore) {
|
|
534
|
+
rawKeyStores.push(validatorKeyStore);
|
|
535
|
+
}
|
|
536
|
+
if (config.enableProverNode) {
|
|
537
|
+
const proverKeyStore = createKeyStoreForProver(config);
|
|
538
|
+
if (proverKeyStore) {
|
|
539
|
+
rawKeyStores.push(proverKeyStore);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (rawKeyStores.length > 0) {
|
|
543
|
+
keyStoreManager = new KeystoreManager(rawKeyStores.length === 1 ? rawKeyStores[0] : mergeKeystores(rawKeyStores));
|
|
132
544
|
}
|
|
133
545
|
}
|
|
134
546
|
await keyStoreManager?.validateSigners();
|
|
@@ -137,8 +549,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
137
549
|
if (keyStoreManager === undefined) {
|
|
138
550
|
throw new Error('Failed to create key store, a requirement for running a validator');
|
|
139
551
|
}
|
|
140
|
-
if (!keyStoreProvided) {
|
|
141
|
-
log.warn(
|
|
552
|
+
if (!keyStoreProvided && process.env.NODE_ENV !== 'test') {
|
|
553
|
+
log.warn("Keystore created from env: it's recommended to use a file-based key store for production");
|
|
142
554
|
}
|
|
143
555
|
ValidatorClient.validateKeyStoreConfiguration(keyStoreManager, log);
|
|
144
556
|
}
|
|
@@ -148,7 +560,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
148
560
|
}
|
|
149
561
|
const publicClient = createPublicClient({
|
|
150
562
|
chain: ethereumChain.chainInfo,
|
|
151
|
-
transport: fallback(config.l1RpcUrls.map((url)=>http(url
|
|
563
|
+
transport: fallback(config.l1RpcUrls.map((url)=>http(url, {
|
|
564
|
+
batch: false
|
|
565
|
+
}))),
|
|
152
566
|
pollingInterval: config.viemPollingIntervalMS
|
|
153
567
|
});
|
|
154
568
|
const l1ContractsAddresses = await RegistryContract.collectAddresses(publicClient, config.l1Contracts.registryAddress, config.rollupVersion ?? 'canonical');
|
|
@@ -167,13 +581,14 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
167
581
|
if (config.rollupVersion !== Number(rollupVersionFromRollup)) {
|
|
168
582
|
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}).`);
|
|
169
583
|
}
|
|
584
|
+
const blobClient = await createBlobClientWithFileStores(config, log.createChild('blob-client'));
|
|
170
585
|
// attempt snapshot sync if possible
|
|
171
586
|
await trySnapshotSync(config, log);
|
|
172
587
|
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config, {
|
|
173
588
|
dateProvider
|
|
174
589
|
});
|
|
175
590
|
const archiver = await createArchiver(config, {
|
|
176
|
-
|
|
591
|
+
blobClient,
|
|
177
592
|
epochCache,
|
|
178
593
|
telemetry,
|
|
179
594
|
dateProvider
|
|
@@ -182,16 +597,22 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
182
597
|
});
|
|
183
598
|
// now create the merkle trees and the world state synchronizer
|
|
184
599
|
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, options.prefilledPublicData, telemetry);
|
|
185
|
-
const circuitVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
600
|
+
const circuitVerifier = config.realProofs || config.debugForceTxProofVerification ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier(config.proverTestVerificationDelayMs);
|
|
601
|
+
let debugLogStore;
|
|
186
602
|
if (!config.realProofs) {
|
|
187
603
|
log.warn(`Aztec node is accepting fake proofs`);
|
|
604
|
+
debugLogStore = new InMemoryDebugLogStore();
|
|
605
|
+
log.info('Aztec node started in test mode (realProofs set to false) hence debug logs from public functions will be collected and served');
|
|
606
|
+
} else {
|
|
607
|
+
debugLogStore = new NullDebugLogStore();
|
|
188
608
|
}
|
|
189
609
|
const proofVerifier = new QueuedIVCVerifier(config, circuitVerifier);
|
|
190
610
|
// create the tx pool and the p2p client, which will need the l2 block source
|
|
191
611
|
const p2pClient = await createP2PClient(P2PClientType.Full, config, archiver, proofVerifier, worldStateSynchronizer, epochCache, packageVersion, dateProvider, telemetry, deps.p2pClientDeps);
|
|
192
612
|
// We should really not be modifying the config object
|
|
193
613
|
config.txPublicSetupAllowList = config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
194
|
-
|
|
614
|
+
// Create FullNodeCheckpointsBuilder for validator and non-validator block proposal handling
|
|
615
|
+
const validatorCheckpointsBuilder = new FullNodeCheckpointsBuilder({
|
|
195
616
|
...config,
|
|
196
617
|
l1GenesisTime,
|
|
197
618
|
slotDuration: Number(slotDuration)
|
|
@@ -199,15 +620,17 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
199
620
|
// We'll accumulate sentinel watchers here
|
|
200
621
|
const watchers = [];
|
|
201
622
|
// Create validator client if required
|
|
202
|
-
const validatorClient = createValidatorClient(config, {
|
|
623
|
+
const validatorClient = await createValidatorClient(config, {
|
|
624
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
625
|
+
worldState: worldStateSynchronizer,
|
|
203
626
|
p2pClient,
|
|
204
627
|
telemetry,
|
|
205
628
|
dateProvider,
|
|
206
629
|
epochCache,
|
|
207
|
-
blockBuilder,
|
|
208
630
|
blockSource: archiver,
|
|
209
631
|
l1ToL2MessageSource: archiver,
|
|
210
|
-
keyStoreManager
|
|
632
|
+
keyStoreManager,
|
|
633
|
+
blobClient
|
|
211
634
|
});
|
|
212
635
|
// If we have a validator client, register it as a source of offenses for the slasher,
|
|
213
636
|
// and have it register callbacks on the p2p client *before* we start it, otherwise messages
|
|
@@ -223,7 +646,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
223
646
|
if (!validatorClient && config.alwaysReexecuteBlockProposals) {
|
|
224
647
|
log.info('Setting up block proposal reexecution for monitoring');
|
|
225
648
|
createBlockProposalHandler(config, {
|
|
226
|
-
|
|
649
|
+
checkpointsBuilder: validatorCheckpointsBuilder,
|
|
650
|
+
worldState: worldStateSynchronizer,
|
|
227
651
|
epochCache,
|
|
228
652
|
blockSource: archiver,
|
|
229
653
|
l1ToL2MessageSource: archiver,
|
|
@@ -242,7 +666,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
242
666
|
}
|
|
243
667
|
let epochPruneWatcher;
|
|
244
668
|
if (config.slashPrunePenalty > 0n || config.slashDataWithholdingPenalty > 0n) {
|
|
245
|
-
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(),
|
|
669
|
+
epochPruneWatcher = new EpochPruneWatcher(archiver, archiver, epochCache, p2pClient.getTxProvider(), validatorCheckpointsBuilder, config);
|
|
246
670
|
watchers.push(epochPruneWatcher);
|
|
247
671
|
}
|
|
248
672
|
// We assume we want to slash for invalid attestations unless all max penalties are set to 0
|
|
@@ -262,21 +686,35 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
262
686
|
// Validator enabled, create/start relevant service
|
|
263
687
|
let sequencer;
|
|
264
688
|
let slasherClient;
|
|
265
|
-
if (!config.disableValidator) {
|
|
689
|
+
if (!config.disableValidator && validatorClient) {
|
|
266
690
|
// We create a slasher only if we have a sequencer, since all slashing actions go through the sequencer publisher
|
|
267
691
|
// as they are executed when the node is selected as proposer.
|
|
268
692
|
const validatorAddresses = keyStoreManager ? NodeKeystoreAdapter.fromKeyStoreManager(keyStoreManager).getAddresses() : [];
|
|
269
693
|
slasherClient = await createSlasher(config, config.l1Contracts, getPublicClient(config), watchers, dateProvider, epochCache, validatorAddresses, undefined);
|
|
270
694
|
await slasherClient.start();
|
|
271
|
-
const l1TxUtils = await
|
|
695
|
+
const l1TxUtils = config.sequencerPublisherForwarderAddress ? await createForwarderL1TxUtilsFromSigners(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), config.sequencerPublisherForwarderAddress, {
|
|
696
|
+
...config,
|
|
697
|
+
scope: 'sequencer'
|
|
698
|
+
}, {
|
|
699
|
+
telemetry,
|
|
700
|
+
logger: log.createChild('l1-tx-utils'),
|
|
701
|
+
dateProvider,
|
|
702
|
+
kzg: Blob.getViemKzgInstance()
|
|
703
|
+
}) : await createL1TxUtilsFromSigners(publicClient, keyStoreManager.createAllValidatorPublisherSigners(), {
|
|
272
704
|
...config,
|
|
273
705
|
scope: 'sequencer'
|
|
274
706
|
}, {
|
|
275
707
|
telemetry,
|
|
276
708
|
logger: log.createChild('l1-tx-utils'),
|
|
277
|
-
dateProvider
|
|
709
|
+
dateProvider,
|
|
710
|
+
kzg: Blob.getViemKzgInstance()
|
|
278
711
|
});
|
|
279
712
|
// Create and start the sequencer client
|
|
713
|
+
const checkpointsBuilder = new CheckpointsBuilder({
|
|
714
|
+
...config,
|
|
715
|
+
l1GenesisTime,
|
|
716
|
+
slotDuration: Number(slotDuration)
|
|
717
|
+
}, worldStateSynchronizer, archiver, dateProvider, telemetry, debugLogStore);
|
|
280
718
|
sequencer = await SequencerClient.new(config, {
|
|
281
719
|
...deps,
|
|
282
720
|
epochCache,
|
|
@@ -285,12 +723,12 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
285
723
|
p2pClient,
|
|
286
724
|
worldStateSynchronizer,
|
|
287
725
|
slasherClient,
|
|
288
|
-
|
|
726
|
+
checkpointsBuilder,
|
|
289
727
|
l2BlockSource: archiver,
|
|
290
728
|
l1ToL2MessageSource: archiver,
|
|
291
729
|
telemetry,
|
|
292
730
|
dateProvider,
|
|
293
|
-
|
|
731
|
+
blobClient,
|
|
294
732
|
nodeKeyStore: keyStoreManager
|
|
295
733
|
});
|
|
296
734
|
}
|
|
@@ -300,7 +738,35 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
300
738
|
} else if (sequencer) {
|
|
301
739
|
log.warn(`Sequencer created but not started`);
|
|
302
740
|
}
|
|
303
|
-
|
|
741
|
+
// Create prover node subsystem if enabled
|
|
742
|
+
let proverNode;
|
|
743
|
+
if (config.enableProverNode) {
|
|
744
|
+
proverNode = await createProverNode(config, {
|
|
745
|
+
...deps.proverNodeDeps,
|
|
746
|
+
telemetry,
|
|
747
|
+
dateProvider,
|
|
748
|
+
archiver,
|
|
749
|
+
worldStateSynchronizer,
|
|
750
|
+
p2pClient,
|
|
751
|
+
epochCache,
|
|
752
|
+
blobClient,
|
|
753
|
+
keyStoreManager
|
|
754
|
+
});
|
|
755
|
+
if (!options.dontStartProverNode) {
|
|
756
|
+
await proverNode.start();
|
|
757
|
+
log.info(`Prover node subsystem started`);
|
|
758
|
+
} else {
|
|
759
|
+
log.info(`Prover node subsystem created but not started`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
const globalVariableBuilder = new GlobalVariableBuilder({
|
|
763
|
+
...config,
|
|
764
|
+
rollupVersion: BigInt(config.rollupVersion),
|
|
765
|
+
l1GenesisTime,
|
|
766
|
+
slotDuration: Number(slotDuration)
|
|
767
|
+
});
|
|
768
|
+
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, debugLogStore);
|
|
769
|
+
return node;
|
|
304
770
|
}
|
|
305
771
|
/**
|
|
306
772
|
* Returns the sequencer client instance.
|
|
@@ -308,6 +774,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
308
774
|
*/ getSequencer() {
|
|
309
775
|
return this.sequencer;
|
|
310
776
|
}
|
|
777
|
+
/** Returns the prover node subsystem, if enabled. */ getProverNode() {
|
|
778
|
+
return this.proverNode;
|
|
779
|
+
}
|
|
311
780
|
getBlockSource() {
|
|
312
781
|
return this.blockSource;
|
|
313
782
|
}
|
|
@@ -350,33 +819,46 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
350
819
|
rollupVersion,
|
|
351
820
|
enr,
|
|
352
821
|
l1ContractAddresses: contractAddresses,
|
|
353
|
-
protocolContractAddresses: protocolContractAddresses
|
|
822
|
+
protocolContractAddresses: protocolContractAddresses,
|
|
823
|
+
realProofs: !!this.config.realProofs
|
|
354
824
|
};
|
|
355
825
|
return nodeInfo;
|
|
356
826
|
}
|
|
357
827
|
/**
|
|
358
|
-
* Get a block specified by its number.
|
|
359
|
-
* @param
|
|
828
|
+
* Get a block specified by its block number, block hash, or 'latest'.
|
|
829
|
+
* @param block - The block parameter (block number, block hash, or 'latest').
|
|
360
830
|
* @returns The requested block.
|
|
361
|
-
*/ async getBlock(
|
|
362
|
-
|
|
363
|
-
|
|
831
|
+
*/ async getBlock(block) {
|
|
832
|
+
if (BlockHash.isBlockHash(block)) {
|
|
833
|
+
return this.getBlockByHash(block);
|
|
834
|
+
}
|
|
835
|
+
const blockNumber = block === 'latest' ? await this.getBlockNumber() : block;
|
|
836
|
+
if (blockNumber === BlockNumber.ZERO) {
|
|
837
|
+
return this.buildInitialBlock();
|
|
838
|
+
}
|
|
839
|
+
return await this.blockSource.getL2Block(blockNumber);
|
|
364
840
|
}
|
|
365
841
|
/**
|
|
366
842
|
* Get a block specified by its hash.
|
|
367
843
|
* @param blockHash - The block hash being requested.
|
|
368
844
|
* @returns The requested block.
|
|
369
845
|
*/ async getBlockByHash(blockHash) {
|
|
370
|
-
const
|
|
371
|
-
|
|
846
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
847
|
+
if (blockHash.equals(initialBlockHash)) {
|
|
848
|
+
return this.buildInitialBlock();
|
|
849
|
+
}
|
|
850
|
+
return await this.blockSource.getL2BlockByHash(blockHash);
|
|
851
|
+
}
|
|
852
|
+
buildInitialBlock() {
|
|
853
|
+
const initialHeader = this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
854
|
+
return L2Block.empty(initialHeader);
|
|
372
855
|
}
|
|
373
856
|
/**
|
|
374
857
|
* Get a block specified by its archive root.
|
|
375
858
|
* @param archive - The archive root being requested.
|
|
376
859
|
* @returns The requested block.
|
|
377
860
|
*/ async getBlockByArchive(archive) {
|
|
378
|
-
|
|
379
|
-
return publishedBlock?.block;
|
|
861
|
+
return await this.blockSource.getL2BlockByArchive(archive);
|
|
380
862
|
}
|
|
381
863
|
/**
|
|
382
864
|
* Method to request blocks. Will attempt to return all requested blocks but will return only those available.
|
|
@@ -384,16 +866,28 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
384
866
|
* @param limit - The maximum number of blocks to obtain.
|
|
385
867
|
* @returns The blocks requested.
|
|
386
868
|
*/ async getBlocks(from, limit) {
|
|
387
|
-
return await this.blockSource.getBlocks(from, limit) ?? [];
|
|
869
|
+
return await this.blockSource.getBlocks(from, BlockNumber(limit)) ?? [];
|
|
388
870
|
}
|
|
389
|
-
async
|
|
390
|
-
return await this.blockSource.
|
|
871
|
+
async getCheckpoints(from, limit) {
|
|
872
|
+
return await this.blockSource.getCheckpoints(from, limit) ?? [];
|
|
873
|
+
}
|
|
874
|
+
async getCheckpointedBlocks(from, limit) {
|
|
875
|
+
return await this.blockSource.getCheckpointedBlocks(from, limit) ?? [];
|
|
391
876
|
}
|
|
392
877
|
/**
|
|
393
|
-
* Method to fetch the current
|
|
394
|
-
* @returns The current
|
|
395
|
-
*/ async
|
|
396
|
-
return await this.globalVariableBuilder.
|
|
878
|
+
* Method to fetch the current min L2 fees.
|
|
879
|
+
* @returns The current min L2 fees.
|
|
880
|
+
*/ async getCurrentMinFees() {
|
|
881
|
+
return await this.globalVariableBuilder.getCurrentMinFees();
|
|
882
|
+
}
|
|
883
|
+
async getMaxPriorityFees() {
|
|
884
|
+
for await (const tx of this.p2pClient.iteratePendingTxs()){
|
|
885
|
+
return tx.getGasSettings().maxPriorityFeesPerGas;
|
|
886
|
+
}
|
|
887
|
+
return GasFees.from({
|
|
888
|
+
feePerDaGas: 0n,
|
|
889
|
+
feePerL2Gas: 0n
|
|
890
|
+
});
|
|
397
891
|
}
|
|
398
892
|
/**
|
|
399
893
|
* Method to fetch the latest block number synchronized by the node.
|
|
@@ -404,6 +898,9 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
404
898
|
async getProvenBlockNumber() {
|
|
405
899
|
return await this.blockSource.getProvenBlockNumber();
|
|
406
900
|
}
|
|
901
|
+
async getCheckpointedBlockNumber() {
|
|
902
|
+
return await this.blockSource.getCheckpointedL2BlockNumber();
|
|
903
|
+
}
|
|
407
904
|
/**
|
|
408
905
|
* Method to fetch the version of the package.
|
|
409
906
|
* @returns The node package version
|
|
@@ -428,22 +925,29 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
428
925
|
getContract(address) {
|
|
429
926
|
return this.contractDataSource.getContract(address);
|
|
430
927
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
928
|
+
async getPrivateLogsByTags(tags, page, referenceBlock) {
|
|
929
|
+
if (referenceBlock) {
|
|
930
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
931
|
+
if (!referenceBlock.equals(initialBlockHash)) {
|
|
932
|
+
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
933
|
+
if (!header) {
|
|
934
|
+
throw new Error(`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return this.logsSource.getPrivateLogsByTags(tags, page);
|
|
939
|
+
}
|
|
940
|
+
async getPublicLogsByTagsFromContract(contractAddress, tags, page, referenceBlock) {
|
|
941
|
+
if (referenceBlock) {
|
|
942
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
943
|
+
if (!referenceBlock.equals(initialBlockHash)) {
|
|
944
|
+
const header = await this.blockSource.getBlockHeaderByHash(referenceBlock);
|
|
945
|
+
if (!header) {
|
|
946
|
+
throw new Error(`Block ${referenceBlock.toString()} not found in the node. This might indicate a reorg has occurred.`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return this.logsSource.getPublicLogsByTagsFromContract(contractAddress, tags, page);
|
|
447
951
|
}
|
|
448
952
|
/**
|
|
449
953
|
* Gets public logs based on the provided filter.
|
|
@@ -484,18 +988,26 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
484
988
|
});
|
|
485
989
|
}
|
|
486
990
|
async getTxReceipt(txHash) {
|
|
487
|
-
|
|
488
|
-
//
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
txReceipt = new TxReceipt(txHash, TxStatus.PENDING, '');
|
|
493
|
-
}
|
|
991
|
+
// Check the tx pool status first. If the tx is known to the pool (pending or mined), we'll use that
|
|
992
|
+
// as a fallback if we don't find a settled receipt in the archiver.
|
|
993
|
+
const txPoolStatus = await this.p2pClient.getTxStatus(txHash);
|
|
994
|
+
const isKnownToPool = txPoolStatus === 'pending' || txPoolStatus === 'mined';
|
|
995
|
+
// Then get the actual tx from the archiver, which tracks every tx in a mined block.
|
|
494
996
|
const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash);
|
|
997
|
+
let receipt;
|
|
495
998
|
if (settledTxReceipt) {
|
|
496
|
-
|
|
999
|
+
receipt = settledTxReceipt;
|
|
1000
|
+
} else if (isKnownToPool) {
|
|
1001
|
+
// If the tx is in the pool but not in the archiver, it's pending.
|
|
1002
|
+
// This handles race conditions between archiver and p2p, where the archiver
|
|
1003
|
+
// has pruned the block in which a tx was mined, but p2p has not caught up yet.
|
|
1004
|
+
receipt = new TxReceipt(txHash, TxStatus.PENDING, undefined, undefined);
|
|
1005
|
+
} else {
|
|
1006
|
+
// Otherwise, if we don't know the tx, we consider it dropped.
|
|
1007
|
+
receipt = new TxReceipt(txHash, TxStatus.DROPPED, undefined, 'Tx dropped by P2P node');
|
|
497
1008
|
}
|
|
498
|
-
|
|
1009
|
+
this.debugLogStore.decorateReceiptWithLogs(txHash.toString(), receipt);
|
|
1010
|
+
return receipt;
|
|
499
1011
|
}
|
|
500
1012
|
getTxEffect(txHash) {
|
|
501
1013
|
return this.blockSource.getTxEffect(txHash);
|
|
@@ -509,13 +1021,21 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
509
1021
|
await tryStop(this.slasherClient);
|
|
510
1022
|
await tryStop(this.proofVerifier);
|
|
511
1023
|
await tryStop(this.sequencer);
|
|
1024
|
+
await tryStop(this.proverNode);
|
|
512
1025
|
await tryStop(this.p2pClient);
|
|
513
1026
|
await tryStop(this.worldStateSynchronizer);
|
|
514
1027
|
await tryStop(this.blockSource);
|
|
1028
|
+
await tryStop(this.blobClient);
|
|
515
1029
|
await tryStop(this.telemetry);
|
|
516
1030
|
this.log.info(`Stopped Aztec Node`);
|
|
517
1031
|
}
|
|
518
1032
|
/**
|
|
1033
|
+
* Returns the blob client used by this node.
|
|
1034
|
+
* @internal - Exposed for testing purposes only.
|
|
1035
|
+
*/ getBlobClient() {
|
|
1036
|
+
return this.blobClient;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
519
1039
|
* Method to retrieve pending txs.
|
|
520
1040
|
* @param limit - The number of items to returns
|
|
521
1041
|
* @param after - The last known pending tx. Used for pagination
|
|
@@ -540,15 +1060,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
540
1060
|
*/ async getTxsByHash(txHashes) {
|
|
541
1061
|
return compactArray(await Promise.all(txHashes.map((txHash)=>this.getTxByHash(txHash))));
|
|
542
1062
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
* the leaves were inserted.
|
|
546
|
-
* @param blockNumber - The block number at which to get the data or 'latest' for latest data.
|
|
547
|
-
* @param treeId - The tree to search in.
|
|
548
|
-
* @param leafValues - The values to search for.
|
|
549
|
-
* @returns The indices of leaves and the block metadata of a block in which the leaves were inserted.
|
|
550
|
-
*/ async findLeavesIndexes(blockNumber, treeId, leafValues) {
|
|
551
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
1063
|
+
async findLeavesIndexes(referenceBlock, treeId, leafValues) {
|
|
1064
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
552
1065
|
const maybeIndices = await committedDb.findLeafIndices(treeId, leafValues.map((x)=>x.toBuffer()));
|
|
553
1066
|
// We filter out undefined values
|
|
554
1067
|
const indices = maybeIndices.filter((x)=>x !== undefined);
|
|
@@ -567,7 +1080,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
567
1080
|
// Now we obtain the block hashes from the archive tree by calling await `committedDb.getLeafValue(treeId, index)`
|
|
568
1081
|
// (note that block number corresponds to the leaf index in the archive tree).
|
|
569
1082
|
const blockHashes = await Promise.all(uniqueBlockNumbers.map((blockNumber)=>{
|
|
570
|
-
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, blockNumber);
|
|
1083
|
+
return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber));
|
|
571
1084
|
}));
|
|
572
1085
|
// If any of the block hashes are undefined, we throw an error.
|
|
573
1086
|
for(let i = 0; i < uniqueBlockNumbers.length; i++){
|
|
@@ -575,7 +1088,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
575
1088
|
throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`);
|
|
576
1089
|
}
|
|
577
1090
|
}
|
|
578
|
-
// Create
|
|
1091
|
+
// Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them.
|
|
579
1092
|
return maybeIndices.map((index, i)=>{
|
|
580
1093
|
if (index === undefined) {
|
|
581
1094
|
return undefined;
|
|
@@ -590,51 +1103,28 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
590
1103
|
return undefined;
|
|
591
1104
|
}
|
|
592
1105
|
return {
|
|
593
|
-
l2BlockNumber: Number(blockNumber),
|
|
594
|
-
l2BlockHash:
|
|
1106
|
+
l2BlockNumber: BlockNumber(Number(blockNumber)),
|
|
1107
|
+
l2BlockHash: new BlockHash(blockHash),
|
|
595
1108
|
data: index
|
|
596
1109
|
};
|
|
597
1110
|
});
|
|
598
1111
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
* @param blockNumber - The block number at which to get the data.
|
|
602
|
-
* @param leafIndex - The index of the leaf for which the sibling path is required.
|
|
603
|
-
* @returns The sibling path for the leaf index.
|
|
604
|
-
*/ async getNullifierSiblingPath(blockNumber, leafIndex) {
|
|
605
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
606
|
-
return committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* Returns a sibling path for the given index in the data tree.
|
|
610
|
-
* @param blockNumber - The block number at which to get the data.
|
|
611
|
-
* @param leafIndex - The index of the leaf for which the sibling path is required.
|
|
612
|
-
* @returns The sibling path for the leaf index.
|
|
613
|
-
*/ async getNoteHashSiblingPath(blockNumber, leafIndex) {
|
|
614
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
615
|
-
return committedDb.getSiblingPath(MerkleTreeId.NOTE_HASH_TREE, leafIndex);
|
|
616
|
-
}
|
|
617
|
-
async getArchiveMembershipWitness(blockNumber, archive) {
|
|
618
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
1112
|
+
async getBlockHashMembershipWitness(referenceBlock, blockHash) {
|
|
1113
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
619
1114
|
const [pathAndIndex] = await committedDb.findSiblingPaths(MerkleTreeId.ARCHIVE, [
|
|
620
|
-
|
|
1115
|
+
blockHash
|
|
621
1116
|
]);
|
|
622
1117
|
return pathAndIndex === undefined ? undefined : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
623
1118
|
}
|
|
624
|
-
async getNoteHashMembershipWitness(
|
|
625
|
-
const committedDb = await this.#getWorldState(
|
|
1119
|
+
async getNoteHashMembershipWitness(referenceBlock, noteHash) {
|
|
1120
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
626
1121
|
const [pathAndIndex] = await committedDb.findSiblingPaths(MerkleTreeId.NOTE_HASH_TREE, [
|
|
627
1122
|
noteHash
|
|
628
1123
|
]);
|
|
629
1124
|
return pathAndIndex === undefined ? undefined : MembershipWitness.fromSiblingPath(pathAndIndex.index, pathAndIndex.path);
|
|
630
1125
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
* @param blockNumber - The block number at which to get the data.
|
|
634
|
-
* @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
|
|
635
|
-
* @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
|
|
636
|
-
*/ async getL1ToL2MessageMembershipWitness(blockNumber, l1ToL2Message) {
|
|
637
|
-
const db = await this.#getWorldState(blockNumber);
|
|
1126
|
+
async getL1ToL2MessageMembershipWitness(referenceBlock, l1ToL2Message) {
|
|
1127
|
+
const db = await this.#getWorldState(referenceBlock);
|
|
638
1128
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, [
|
|
639
1129
|
l1ToL2Message
|
|
640
1130
|
]);
|
|
@@ -649,7 +1139,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
649
1139
|
}
|
|
650
1140
|
async getL1ToL2MessageBlock(l1ToL2Message) {
|
|
651
1141
|
const messageIndex = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message);
|
|
652
|
-
return messageIndex ? InboxLeaf.
|
|
1142
|
+
return messageIndex ? BlockNumber.fromCheckpointNumber(InboxLeaf.checkpointNumberFromIndex(messageIndex)) : undefined;
|
|
653
1143
|
}
|
|
654
1144
|
/**
|
|
655
1145
|
* Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
|
|
@@ -660,38 +1150,29 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
660
1150
|
return messageIndex !== undefined;
|
|
661
1151
|
}
|
|
662
1152
|
/**
|
|
663
|
-
* Returns all the L2 to L1 messages in
|
|
664
|
-
* @param
|
|
665
|
-
* @returns The L2 to L1 messages (
|
|
666
|
-
*/ async getL2ToL1Messages(
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
* @returns The sibling path.
|
|
684
|
-
*/ async getPublicDataSiblingPath(blockNumber, leafIndex) {
|
|
685
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
686
|
-
return committedDb.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, leafIndex);
|
|
1153
|
+
* Returns all the L2 to L1 messages in an epoch.
|
|
1154
|
+
* @param epoch - The epoch at which to get the data.
|
|
1155
|
+
* @returns The L2 to L1 messages (empty array if the epoch is not found).
|
|
1156
|
+
*/ async getL2ToL1Messages(epoch) {
|
|
1157
|
+
// Assumes `getCheckpointedBlocksForEpoch` returns blocks in ascending order of block number.
|
|
1158
|
+
const checkpointedBlocks = await this.blockSource.getCheckpointedBlocksForEpoch(epoch);
|
|
1159
|
+
const blocksInCheckpoints = [];
|
|
1160
|
+
let previousSlotNumber = SlotNumber.ZERO;
|
|
1161
|
+
let checkpointIndex = -1;
|
|
1162
|
+
for (const checkpointedBlock of checkpointedBlocks){
|
|
1163
|
+
const block = checkpointedBlock.block;
|
|
1164
|
+
const slotNumber = block.header.globalVariables.slotNumber;
|
|
1165
|
+
if (slotNumber !== previousSlotNumber) {
|
|
1166
|
+
checkpointIndex++;
|
|
1167
|
+
blocksInCheckpoints.push([]);
|
|
1168
|
+
previousSlotNumber = slotNumber;
|
|
1169
|
+
}
|
|
1170
|
+
blocksInCheckpoints[checkpointIndex].push(block);
|
|
1171
|
+
}
|
|
1172
|
+
return blocksInCheckpoints.map((blocks)=>blocks.map((block)=>block.body.txEffects.map((txEffect)=>txEffect.l2ToL1Msgs)));
|
|
687
1173
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
* @param blockNumber - The block number at which to get the index.
|
|
691
|
-
* @param nullifier - Nullifier we try to find witness for.
|
|
692
|
-
* @returns The nullifier membership witness (if found).
|
|
693
|
-
*/ async getNullifierMembershipWitness(blockNumber, nullifier) {
|
|
694
|
-
const db = await this.#getWorldState(blockNumber);
|
|
1174
|
+
async getNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1175
|
+
const db = await this.#getWorldState(referenceBlock);
|
|
695
1176
|
const [witness] = await db.findSiblingPaths(MerkleTreeId.NULLIFIER_TREE, [
|
|
696
1177
|
nullifier.toBuffer()
|
|
697
1178
|
]);
|
|
@@ -707,7 +1188,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
707
1188
|
}
|
|
708
1189
|
/**
|
|
709
1190
|
* Returns a low nullifier membership witness for a given nullifier at a given block.
|
|
710
|
-
* @param
|
|
1191
|
+
* @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data
|
|
1192
|
+
* (which contains the root of the nullifier tree in which we are searching for the nullifier).
|
|
711
1193
|
* @param nullifier - Nullifier we try to find the low nullifier witness for.
|
|
712
1194
|
* @returns The low nullifier membership witness (if found).
|
|
713
1195
|
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
|
|
@@ -718,8 +1200,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
718
1200
|
* the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the
|
|
719
1201
|
* index of the nullifier itself when it already exists in the tree.
|
|
720
1202
|
* TODO: This is a confusing behavior and we should eventually address that.
|
|
721
|
-
*/ async getLowNullifierMembershipWitness(
|
|
722
|
-
const committedDb = await this.#getWorldState(
|
|
1203
|
+
*/ async getLowNullifierMembershipWitness(referenceBlock, nullifier) {
|
|
1204
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
723
1205
|
const findResult = await committedDb.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
724
1206
|
if (!findResult) {
|
|
725
1207
|
return undefined;
|
|
@@ -732,8 +1214,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
732
1214
|
const siblingPath = await committedDb.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
|
|
733
1215
|
return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
|
|
734
1216
|
}
|
|
735
|
-
async getPublicDataWitness(
|
|
736
|
-
const committedDb = await this.#getWorldState(
|
|
1217
|
+
async getPublicDataWitness(referenceBlock, leafSlot) {
|
|
1218
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
737
1219
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
738
1220
|
if (!lowLeafResult) {
|
|
739
1221
|
return undefined;
|
|
@@ -743,18 +1225,8 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
743
1225
|
return new PublicDataWitness(lowLeafResult.index, preimage, path);
|
|
744
1226
|
}
|
|
745
1227
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
*
|
|
749
|
-
* @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
|
|
750
|
-
* Aztec's version of `eth_getStorageAt`.
|
|
751
|
-
*
|
|
752
|
-
* @param contract - Address of the contract to query.
|
|
753
|
-
* @param slot - Slot to query.
|
|
754
|
-
* @param blockNumber - The block number at which to get the data or 'latest'.
|
|
755
|
-
* @returns Storage value at the given contract slot.
|
|
756
|
-
*/ async getPublicStorageAt(blockNumber, contract, slot) {
|
|
757
|
-
const committedDb = await this.#getWorldState(blockNumber);
|
|
1228
|
+
async getPublicStorageAt(referenceBlock, contract, slot) {
|
|
1229
|
+
const committedDb = await this.#getWorldState(referenceBlock);
|
|
758
1230
|
const leafSlot = await computePublicDataTreeLeafSlot(contract, slot);
|
|
759
1231
|
const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
760
1232
|
if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
|
|
@@ -763,18 +1235,22 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
763
1235
|
const preimage = await committedDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
764
1236
|
return preimage.leaf.value;
|
|
765
1237
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1238
|
+
async getBlockHeader(block = 'latest') {
|
|
1239
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1240
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1241
|
+
if (block.equals(initialBlockHash)) {
|
|
1242
|
+
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1243
|
+
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1244
|
+
}
|
|
1245
|
+
return this.blockSource.getBlockHeaderByHash(block);
|
|
1246
|
+
} else {
|
|
1247
|
+
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1248
|
+
const blockNumber = block === 'latest' ? await this.getBlockNumber() : block;
|
|
1249
|
+
if (blockNumber === BlockNumber.ZERO) {
|
|
1250
|
+
return this.worldStateSynchronizer.getCommitted().getInitialHeader();
|
|
1251
|
+
}
|
|
1252
|
+
return this.blockSource.getBlockHeader(block);
|
|
1253
|
+
}
|
|
778
1254
|
}
|
|
779
1255
|
/**
|
|
780
1256
|
* Get a block header specified by its archive root.
|
|
@@ -783,6 +1259,12 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
783
1259
|
*/ async getBlockHeaderByArchive(archive) {
|
|
784
1260
|
return await this.blockSource.getBlockHeaderByArchive(archive);
|
|
785
1261
|
}
|
|
1262
|
+
getBlockData(number) {
|
|
1263
|
+
return this.blockSource.getBlockData(number);
|
|
1264
|
+
}
|
|
1265
|
+
getBlockDataByArchive(archive) {
|
|
1266
|
+
return this.blockSource.getBlockDataByArchive(archive);
|
|
1267
|
+
}
|
|
786
1268
|
/**
|
|
787
1269
|
* Simulates the public part of a transaction with the current state.
|
|
788
1270
|
* @param tx - The transaction to simulate.
|
|
@@ -795,17 +1277,20 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
795
1277
|
throw new BadRequestError(`Transaction total gas limit ${txGasLimit + teardownGasLimit} (${txGasLimit} + ${teardownGasLimit}) exceeds maximum gas limit ${this.config.rpcSimulatePublicMaxGasLimit} for simulation`);
|
|
796
1278
|
}
|
|
797
1279
|
const txHash = tx.getTxHash();
|
|
798
|
-
const
|
|
1280
|
+
const latestBlockNumber = await this.blockSource.getBlockNumber();
|
|
1281
|
+
const blockNumber = BlockNumber.add(latestBlockNumber, 1);
|
|
799
1282
|
// If sequencer is not initialized, we just set these values to zero for simulation.
|
|
800
1283
|
const coinbase = EthAddress.ZERO;
|
|
801
1284
|
const feeRecipient = AztecAddress.ZERO;
|
|
802
1285
|
const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(blockNumber, coinbase, feeRecipient);
|
|
803
|
-
const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, new DateProvider(), this.telemetry);
|
|
1286
|
+
const publicProcessorFactory = new PublicProcessorFactory(this.contractDataSource, new DateProvider(), this.telemetry, this.log.getBindings());
|
|
804
1287
|
this.log.verbose(`Simulating public calls for tx ${txHash}`, {
|
|
805
1288
|
globalVariables: newGlobalVariables.toInspect(),
|
|
806
1289
|
txHash,
|
|
807
1290
|
blockNumber
|
|
808
1291
|
});
|
|
1292
|
+
// Ensure world-state has caught up with the latest block we loaded from the archiver
|
|
1293
|
+
await this.worldStateSynchronizer.syncImmediate(latestBlockNumber);
|
|
809
1294
|
const merkleTreeFork = await this.worldStateSynchronizer.fork();
|
|
810
1295
|
try {
|
|
811
1296
|
const config = PublicSimulatorConfig.from({
|
|
@@ -813,12 +1298,14 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
813
1298
|
collectDebugLogs: true,
|
|
814
1299
|
collectHints: false,
|
|
815
1300
|
collectCallMetadata: true,
|
|
816
|
-
|
|
817
|
-
|
|
1301
|
+
collectStatistics: false,
|
|
1302
|
+
collectionLimits: CollectionLimitsConfig.from({
|
|
1303
|
+
maxDebugLogMemoryReads: this.config.rpcSimulatePublicMaxDebugLogMemoryReads
|
|
1304
|
+
})
|
|
818
1305
|
});
|
|
819
1306
|
const processor = publicProcessorFactory.create(merkleTreeFork, newGlobalVariables, config);
|
|
820
1307
|
// REFACTOR: Consider merging ProcessReturnValues into ProcessedTx
|
|
821
|
-
const [processedTxs, failedTxs, _usedTxs, returns] = await processor.process([
|
|
1308
|
+
const [processedTxs, failedTxs, _usedTxs, returns, _blobFields, debugLogs] = await processor.process([
|
|
822
1309
|
tx
|
|
823
1310
|
]);
|
|
824
1311
|
// REFACTOR: Consider returning the error rather than throwing
|
|
@@ -829,7 +1316,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
829
1316
|
throw failedTxs[0].error;
|
|
830
1317
|
}
|
|
831
1318
|
const [processedTx] = processedTxs;
|
|
832
|
-
return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed);
|
|
1319
|
+
return new PublicSimulationOutput(processedTx.revertReason, processedTx.globalVariables, processedTx.txEffect, returns, processedTx.gasUsed, debugLogs);
|
|
833
1320
|
} finally{
|
|
834
1321
|
await merkleTreeFork.close();
|
|
835
1322
|
}
|
|
@@ -837,19 +1324,19 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
837
1324
|
async isValidTx(tx, { isSimulation, skipFeeEnforcement } = {}) {
|
|
838
1325
|
const db = this.worldStateSynchronizer.getCommitted();
|
|
839
1326
|
const verifier = isSimulation ? undefined : this.proofVerifier;
|
|
840
|
-
// We accept transactions if they are not expired by the next slot (checked based on the
|
|
1327
|
+
// We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field)
|
|
841
1328
|
const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot();
|
|
842
|
-
const blockNumber = await this.blockSource.getBlockNumber() + 1;
|
|
843
|
-
const validator =
|
|
1329
|
+
const blockNumber = BlockNumber(await this.blockSource.getBlockNumber() + 1);
|
|
1330
|
+
const validator = createTxValidatorForAcceptingTxsOverRPC(db, this.contractDataSource, verifier, {
|
|
844
1331
|
timestamp: nextSlotTimestamp,
|
|
845
1332
|
blockNumber,
|
|
846
1333
|
l1ChainId: this.l1ChainId,
|
|
847
1334
|
rollupVersion: this.version,
|
|
848
1335
|
setupAllowList: this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions(),
|
|
849
|
-
gasFees: await this.
|
|
1336
|
+
gasFees: await this.getCurrentMinFees(),
|
|
850
1337
|
skipFeeEnforcement,
|
|
851
1338
|
txsPermitted: !this.config.disableTransactions
|
|
852
|
-
});
|
|
1339
|
+
}, this.log.getBindings());
|
|
853
1340
|
return await validator.validateTx(tx);
|
|
854
1341
|
}
|
|
855
1342
|
getConfig() {
|
|
@@ -909,7 +1396,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
909
1396
|
throw new Error(`Archiver initial sync not complete. Cannot start snapshot.`);
|
|
910
1397
|
}
|
|
911
1398
|
// And it has an L2 block hash
|
|
912
|
-
const l2BlockHash = await archiver.getL2Tips().then((tips)=>tips.
|
|
1399
|
+
const l2BlockHash = await archiver.getL2Tips().then((tips)=>tips.proposed.hash);
|
|
913
1400
|
if (!l2BlockHash) {
|
|
914
1401
|
this.metrics.recordSnapshotError();
|
|
915
1402
|
throw new Error(`Archiver has no latest L2 block hash downloaded. Cannot start snapshot.`);
|
|
@@ -936,7 +1423,7 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
936
1423
|
if (!('rollbackTo' in archiver)) {
|
|
937
1424
|
throw new Error('Archiver implementation does not support rollbacks.');
|
|
938
1425
|
}
|
|
939
|
-
const finalizedBlock = await archiver.getL2Tips().then((tips)=>tips.finalized.number);
|
|
1426
|
+
const finalizedBlock = await archiver.getL2Tips().then((tips)=>tips.finalized.block.number);
|
|
940
1427
|
if (targetBlock < finalizedBlock) {
|
|
941
1428
|
if (force) {
|
|
942
1429
|
this.log.warn(`Clearing world state database to allow rolling back behind finalized block ${finalizedBlock}`);
|
|
@@ -991,30 +1478,117 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
991
1478
|
return this.slasherClient.gatherOffensesForRound(round === 'current' ? undefined : BigInt(round));
|
|
992
1479
|
}
|
|
993
1480
|
}
|
|
1481
|
+
async reloadKeystore() {
|
|
1482
|
+
if (!this.config.keyStoreDirectory?.length) {
|
|
1483
|
+
throw new BadRequestError('Cannot reload keystore: node is not using a file-based keystore. ' + 'Set KEY_STORE_DIRECTORY to use file-based keystores.');
|
|
1484
|
+
}
|
|
1485
|
+
if (!this.validatorClient) {
|
|
1486
|
+
throw new BadRequestError('Cannot reload keystore: validator is not enabled.');
|
|
1487
|
+
}
|
|
1488
|
+
this.log.info('Reloading keystore from disk');
|
|
1489
|
+
// Re-read and validate keystore files
|
|
1490
|
+
const keyStores = loadKeystores(this.config.keyStoreDirectory);
|
|
1491
|
+
const newManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
1492
|
+
await newManager.validateSigners();
|
|
1493
|
+
ValidatorClient.validateKeyStoreConfiguration(newManager, this.log);
|
|
1494
|
+
// Validate that every validator's publisher keys overlap with the L1 signers
|
|
1495
|
+
// that were initialized at startup. Publishers cannot be hot-reloaded, so a
|
|
1496
|
+
// validator with a publisher key that doesn't match any existing L1 signer
|
|
1497
|
+
// would silently fail on every proposer slot.
|
|
1498
|
+
if (this.keyStoreManager && this.sequencer) {
|
|
1499
|
+
const oldAdapter = NodeKeystoreAdapter.fromKeyStoreManager(this.keyStoreManager);
|
|
1500
|
+
const availablePublishers = new Set(oldAdapter.getAttesterAddresses().flatMap((a)=>oldAdapter.getPublisherAddresses(a).map((p)=>p.toString().toLowerCase())));
|
|
1501
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
1502
|
+
for (const attester of newAdapter.getAttesterAddresses()){
|
|
1503
|
+
const pubs = newAdapter.getPublisherAddresses(attester);
|
|
1504
|
+
if (pubs.length > 0 && !pubs.some((p)=>availablePublishers.has(p.toString().toLowerCase()))) {
|
|
1505
|
+
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 ` + `[${[
|
|
1506
|
+
...availablePublishers
|
|
1507
|
+
].join(', ')}]. Publishers cannot be hot-reloaded — ` + `use an existing publisher key or restart the node.`);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
// Build adapters for old and new keystores to compute diff
|
|
1512
|
+
const newAdapter = NodeKeystoreAdapter.fromKeyStoreManager(newManager);
|
|
1513
|
+
const newAddresses = newAdapter.getAttesterAddresses();
|
|
1514
|
+
const oldAddresses = this.keyStoreManager ? NodeKeystoreAdapter.fromKeyStoreManager(this.keyStoreManager).getAttesterAddresses() : [];
|
|
1515
|
+
const oldSet = new Set(oldAddresses.map((a)=>a.toString()));
|
|
1516
|
+
const newSet = new Set(newAddresses.map((a)=>a.toString()));
|
|
1517
|
+
const added = newAddresses.filter((a)=>!oldSet.has(a.toString()));
|
|
1518
|
+
const removed = oldAddresses.filter((a)=>!newSet.has(a.toString()));
|
|
1519
|
+
if (added.length > 0) {
|
|
1520
|
+
this.log.info(`Keystore reload: adding attester keys: ${added.map((a)=>a.toString()).join(', ')}`);
|
|
1521
|
+
}
|
|
1522
|
+
if (removed.length > 0) {
|
|
1523
|
+
this.log.info(`Keystore reload: removing attester keys: ${removed.map((a)=>a.toString()).join(', ')}`);
|
|
1524
|
+
}
|
|
1525
|
+
if (added.length === 0 && removed.length === 0) {
|
|
1526
|
+
this.log.info('Keystore reload: attester keys unchanged');
|
|
1527
|
+
}
|
|
1528
|
+
// Update the validator client (coinbase, feeRecipient, attester keys)
|
|
1529
|
+
this.validatorClient.reloadKeystore(newManager);
|
|
1530
|
+
// Update the publisher factory's keystore so newly-added validators
|
|
1531
|
+
// can be matched to existing publisher keys when proposing blocks.
|
|
1532
|
+
if (this.sequencer) {
|
|
1533
|
+
this.sequencer.updatePublisherNodeKeyStore(newAdapter);
|
|
1534
|
+
}
|
|
1535
|
+
// Update slasher's "don't-slash-self" list with new validator addresses
|
|
1536
|
+
if (this.slasherClient && !this.config.slashSelfAllowed) {
|
|
1537
|
+
const slashValidatorsNever = unique([
|
|
1538
|
+
...this.config.slashValidatorsNever ?? [],
|
|
1539
|
+
...newAddresses
|
|
1540
|
+
].map((a)=>a.toString())).map(EthAddress.fromString);
|
|
1541
|
+
this.slasherClient.updateConfig({
|
|
1542
|
+
slashValidatorsNever
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
this.keyStoreManager = newManager;
|
|
1546
|
+
this.log.info('Keystore reloaded: coinbase, feeRecipient, and attester keys updated');
|
|
1547
|
+
}
|
|
1548
|
+
#getInitialHeaderHash() {
|
|
1549
|
+
if (!this.initialHeaderHashPromise) {
|
|
1550
|
+
this.initialHeaderHashPromise = this.worldStateSynchronizer.getCommitted().getInitialHeader().hash();
|
|
1551
|
+
}
|
|
1552
|
+
return this.initialHeaderHashPromise;
|
|
1553
|
+
}
|
|
994
1554
|
/**
|
|
995
1555
|
* Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched
|
|
996
|
-
* @param
|
|
1556
|
+
* @param block - The block parameter (block number, block hash, or 'latest') at which to get the data.
|
|
997
1557
|
* @returns An instance of a committed MerkleTreeOperations
|
|
998
|
-
*/ async #getWorldState(
|
|
999
|
-
|
|
1000
|
-
throw new Error('Invalid block number to get world state for: ' + blockNumber);
|
|
1001
|
-
}
|
|
1002
|
-
let blockSyncedTo = 0;
|
|
1558
|
+
*/ async #getWorldState(block) {
|
|
1559
|
+
let blockSyncedTo = BlockNumber.ZERO;
|
|
1003
1560
|
try {
|
|
1004
1561
|
// Attempt to sync the world state if necessary
|
|
1005
1562
|
blockSyncedTo = await this.#syncWorldState();
|
|
1006
1563
|
} catch (err) {
|
|
1007
1564
|
this.log.error(`Error getting world state: ${err}`);
|
|
1008
1565
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
this.log.debug(`Using committed db for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1566
|
+
if (block === 'latest') {
|
|
1567
|
+
this.log.debug(`Using committed db for block 'latest', world state synced upto ${blockSyncedTo}`);
|
|
1012
1568
|
return this.worldStateSynchronizer.getCommitted();
|
|
1013
|
-
}
|
|
1569
|
+
}
|
|
1570
|
+
if (BlockHash.isBlockHash(block)) {
|
|
1571
|
+
const initialBlockHash = await this.#getInitialHeaderHash();
|
|
1572
|
+
if (block.equals(initialBlockHash)) {
|
|
1573
|
+
// Block source doesn't handle initial header so we need to handle the case separately.
|
|
1574
|
+
return this.worldStateSynchronizer.getSnapshot(BlockNumber.ZERO);
|
|
1575
|
+
}
|
|
1576
|
+
const header = await this.blockSource.getBlockHeaderByHash(block);
|
|
1577
|
+
if (!header) {
|
|
1578
|
+
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.`);
|
|
1579
|
+
}
|
|
1580
|
+
const blockNumber = header.getBlockNumber();
|
|
1581
|
+
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1582
|
+
return this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1583
|
+
}
|
|
1584
|
+
// Block number provided
|
|
1585
|
+
{
|
|
1586
|
+
const blockNumber = block;
|
|
1587
|
+
if (blockNumber > blockSyncedTo) {
|
|
1588
|
+
throw new Error(`Queried block ${block} not yet synced by the node (node is synced upto ${blockSyncedTo}).`);
|
|
1589
|
+
}
|
|
1014
1590
|
this.log.debug(`Using snapshot for block ${blockNumber}, world state synced upto ${blockSyncedTo}`);
|
|
1015
1591
|
return this.worldStateSynchronizer.getSnapshot(blockNumber);
|
|
1016
|
-
} else {
|
|
1017
|
-
throw new Error(`Block ${blockNumber} not yet synced`);
|
|
1018
1592
|
}
|
|
1019
1593
|
}
|
|
1020
1594
|
/**
|
|
@@ -1022,11 +1596,6 @@ import { NodeMetrics } from './node_metrics.js';
|
|
|
1022
1596
|
* @returns A promise that fulfils once the world state is synced
|
|
1023
1597
|
*/ async #syncWorldState() {
|
|
1024
1598
|
const blockSourceHeight = await this.blockSource.getBlockNumber();
|
|
1025
|
-
return this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
|
|
1599
|
+
return await this.worldStateSynchronizer.syncImmediate(blockSourceHeight);
|
|
1026
1600
|
}
|
|
1027
1601
|
}
|
|
1028
|
-
_ts_decorate([
|
|
1029
|
-
trackSpan('AztecNodeService.simulatePublicCalls', (tx)=>({
|
|
1030
|
-
[Attributes.TX_HASH]: tx.getTxHash().toString()
|
|
1031
|
-
}))
|
|
1032
|
-
], AztecNodeService.prototype, "simulatePublicCalls", null);
|