@aztec/aztec-node 3.0.0-canary.a9708bd → 3.0.0-devnet.2
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 +2 -2
- package/dest/aztec-node/config.d.ts.map +1 -1
- package/dest/aztec-node/config.js +10 -19
- package/dest/aztec-node/server.d.ts +29 -3
- package/dest/aztec-node/server.d.ts.map +1 -1
- package/dest/aztec-node/server.js +105 -27
- package/dest/sentinel/config.d.ts +1 -0
- package/dest/sentinel/config.d.ts.map +1 -1
- package/dest/sentinel/config.js +16 -0
- package/dest/sentinel/factory.d.ts.map +1 -1
- package/dest/sentinel/factory.js +3 -1
- package/dest/sentinel/sentinel.d.ts +4 -3
- package/dest/sentinel/sentinel.d.ts.map +1 -1
- package/dest/sentinel/sentinel.js +63 -64
- package/dest/sentinel/store.d.ts +2 -0
- package/dest/sentinel/store.d.ts.map +1 -1
- package/dest/sentinel/store.js +5 -2
- package/package.json +26 -26
- package/src/aztec-node/config.ts +19 -35
- package/src/aztec-node/server.ts +126 -40
- package/src/sentinel/config.ts +18 -0
- package/src/sentinel/factory.ts +5 -1
- package/src/sentinel/sentinel.ts +79 -74
- package/src/sentinel/store.ts +7 -3
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { countWhile, filterAsync } from '@aztec/foundation/collection';
|
|
1
|
+
import { countWhile, filterAsync, fromEntries, getEntries, mapValues } from '@aztec/foundation/collection';
|
|
2
2
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
5
5
|
import { L2TipsMemoryStore } from '@aztec/kv-store/stores';
|
|
6
6
|
import { OffenseType, WANT_TO_SLASH_EVENT } from '@aztec/slasher';
|
|
7
|
-
import { L2BlockStream,
|
|
8
|
-
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
7
|
+
import { L2BlockStream, getAttestationInfoFromPublishedL2Block } from '@aztec/stdlib/block';
|
|
8
|
+
import { getEpochAtSlot, getSlotRangeForEpoch, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
9
9
|
import EventEmitter from 'node:events';
|
|
10
10
|
export class Sentinel extends EventEmitter {
|
|
11
11
|
epochCache;
|
|
@@ -55,7 +55,7 @@ export class Sentinel extends EventEmitter {
|
|
|
55
55
|
this.slotNumberToBlock.set(block.block.header.getSlot(), {
|
|
56
56
|
blockNumber: block.block.number,
|
|
57
57
|
archive: block.block.archive.root.toString(),
|
|
58
|
-
attestors:
|
|
58
|
+
attestors: getAttestationInfoFromPublishedL2Block(block).filter((a)=>a.status === 'recovered-from-signature').map((a)=>a.address)
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
// Prune the archive map to only keep at most N entries
|
|
@@ -82,18 +82,17 @@ export class Sentinel extends EventEmitter {
|
|
|
82
82
|
});
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
// TODO(palla/slash): We should only be computing proven performance if this is
|
|
86
|
+
// a full proof epoch and not a partial one, otherwise we'll end up with skewed stats.
|
|
87
|
+
const epoch = getEpochAtSlot(block.header.getSlot(), this.epochCache.getL1Constants());
|
|
86
88
|
this.logger.debug(`Computing proven performance for epoch ${epoch}`);
|
|
87
89
|
const performance = await this.computeProvenPerformance(epoch);
|
|
88
90
|
this.logger.info(`Computed proven performance for epoch ${epoch}`, performance);
|
|
89
|
-
await this.updateProvenPerformance(epoch, performance);
|
|
91
|
+
await this.store.updateProvenPerformance(epoch, performance);
|
|
90
92
|
await this.handleProvenPerformance(epoch, performance);
|
|
91
93
|
}
|
|
92
94
|
async computeProvenPerformance(epoch) {
|
|
93
|
-
const
|
|
94
|
-
const provenSlots = headers.map((h)=>h.getSlot());
|
|
95
|
-
const fromSlot = provenSlots[0];
|
|
96
|
-
const toSlot = provenSlots[provenSlots.length - 1];
|
|
95
|
+
const [fromSlot, toSlot] = getSlotRangeForEpoch(epoch, this.epochCache.getL1Constants());
|
|
97
96
|
const { committee } = await this.epochCache.getCommittee(fromSlot);
|
|
98
97
|
if (!committee) {
|
|
99
98
|
this.logger.trace(`No committee found for slot ${fromSlot}`);
|
|
@@ -101,36 +100,25 @@ export class Sentinel extends EventEmitter {
|
|
|
101
100
|
}
|
|
102
101
|
const stats = await this.computeStats({
|
|
103
102
|
fromSlot,
|
|
104
|
-
toSlot
|
|
103
|
+
toSlot,
|
|
104
|
+
validators: committee
|
|
105
105
|
});
|
|
106
|
-
this.logger.debug(`Stats for epoch ${epoch}`,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
missed++;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
performance[address.toString()] = {
|
|
126
|
-
missed,
|
|
127
|
-
total: provenSlots.length
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
return performance;
|
|
131
|
-
}
|
|
132
|
-
updateProvenPerformance(epoch, performance) {
|
|
133
|
-
return this.store.updateProvenPerformance(epoch, performance);
|
|
106
|
+
this.logger.debug(`Stats for epoch ${epoch}`, {
|
|
107
|
+
...stats,
|
|
108
|
+
fromSlot,
|
|
109
|
+
toSlot,
|
|
110
|
+
epoch
|
|
111
|
+
});
|
|
112
|
+
// Note that we are NOT using the total slots in the epoch as `total` here, since we only
|
|
113
|
+
// compute missed attestations over the blocks that had a proposal in them. So, let's say
|
|
114
|
+
// we have an epoch with 10 slots, but only 5 had a block proposal. A validator that was
|
|
115
|
+
// offline, assuming they were not picked as proposer, will then be reported as having missed
|
|
116
|
+
// 5/5 attestations. If we used the total, they'd be reported as 5/10, which would probably
|
|
117
|
+
// allow them to avoid being slashed.
|
|
118
|
+
return mapValues(stats.stats, (stat)=>({
|
|
119
|
+
missed: stat.missedAttestations.count + stat.missedProposals.count,
|
|
120
|
+
total: stat.missedAttestations.total + stat.missedProposals.total
|
|
121
|
+
}));
|
|
134
122
|
}
|
|
135
123
|
/**
|
|
136
124
|
* Checks if a validator has been inactive for the specified number of consecutive epochs for which we have data on it.
|
|
@@ -152,9 +140,10 @@ export class Sentinel extends EventEmitter {
|
|
|
152
140
|
return allPerformance.sort((a, b)=>Number(b.epoch - a.epoch)).filter((p)=>p.epoch < currentEpoch).slice(0, requiredConsecutiveEpochs).every((p)=>p.missed / p.total >= this.config.slashInactivityTargetPercentage);
|
|
153
141
|
}
|
|
154
142
|
async handleProvenPerformance(epoch, performance) {
|
|
155
|
-
|
|
156
|
-
return
|
|
157
|
-
}
|
|
143
|
+
if (this.config.slashInactivityPenalty === 0n) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const inactiveValidators = getEntries(performance).filter(([_, { missed, total }])=>missed / total >= this.config.slashInactivityTargetPercentage).map(([address])=>address);
|
|
158
147
|
this.logger.debug(`Found ${inactiveValidators.length} inactive validators in epoch ${epoch}`, {
|
|
159
148
|
inactiveValidators,
|
|
160
149
|
epoch,
|
|
@@ -169,7 +158,7 @@ export class Sentinel extends EventEmitter {
|
|
|
169
158
|
epochOrSlot: epoch
|
|
170
159
|
}));
|
|
171
160
|
if (criminals.length > 0) {
|
|
172
|
-
this.logger.
|
|
161
|
+
this.logger.verbose(`Identified ${criminals.length} validators to slash due to inactivity in at least ${epochThreshold} consecutive epochs`, {
|
|
173
162
|
...args,
|
|
174
163
|
epochThreshold
|
|
175
164
|
});
|
|
@@ -267,14 +256,18 @@ export class Sentinel extends EventEmitter {
|
|
|
267
256
|
// (contains the ones synced from mined blocks, which we may have missed from p2p).
|
|
268
257
|
const block = this.slotNumberToBlock.get(slot);
|
|
269
258
|
const p2pAttested = await this.p2p.getAttestationsForSlot(slot, block?.archive);
|
|
259
|
+
// Filter out attestations with invalid signatures
|
|
260
|
+
const p2pAttestors = p2pAttested.map((a)=>a.getSender()).filter((s)=>s !== undefined);
|
|
270
261
|
const attestors = new Set([
|
|
271
|
-
...
|
|
262
|
+
...p2pAttestors.map((a)=>a.toString()),
|
|
272
263
|
...block?.attestors.map((a)=>a.toString()) ?? []
|
|
273
|
-
]);
|
|
274
|
-
// We assume that there was a block proposal if at least one of the validators attested to it.
|
|
264
|
+
].filter((addr)=>proposer.toString() !== addr));
|
|
265
|
+
// We assume that there was a block proposal if at least one of the validators (other than the proposer) attested to it.
|
|
275
266
|
// It could be the case that every single validator failed, and we could differentiate it by having
|
|
276
267
|
// this node re-execute every block proposal it sees and storing it in the attestation pool.
|
|
277
268
|
// But we'll leave that corner case out to reduce pressure on the node.
|
|
269
|
+
// TODO(palla/slash): This breaks if a given node has more than one validator in the current committee,
|
|
270
|
+
// since they will attest to their own proposal it even if it's not re-executable.
|
|
278
271
|
const blockStatus = block ? 'mined' : attestors.size > 0 ? 'proposed' : 'missed';
|
|
279
272
|
this.logger.debug(`Block for slot ${slot} was ${blockStatus}`, {
|
|
280
273
|
...block,
|
|
@@ -315,18 +308,17 @@ export class Sentinel extends EventEmitter {
|
|
|
315
308
|
/** Push the status for each slot for each validator. */ updateValidators(slot, stats) {
|
|
316
309
|
return this.store.updateValidators(slot, stats);
|
|
317
310
|
}
|
|
318
|
-
/** Computes stats to be returned based on stored data. */ async computeStats({ fromSlot
|
|
319
|
-
const histories = await
|
|
311
|
+
/** Computes stats to be returned based on stored data. */ async computeStats({ fromSlot, toSlot, validators } = {}) {
|
|
312
|
+
const histories = validators ? fromEntries(await Promise.all(validators.map(async (v)=>[
|
|
313
|
+
v.toString(),
|
|
314
|
+
await this.store.getHistory(v)
|
|
315
|
+
]))) : await this.store.getHistories();
|
|
320
316
|
const slotNow = this.epochCache.getEpochAndSlotNow().slot;
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const
|
|
324
|
-
for (const [address, history] of Object.entries(histories)){
|
|
325
|
-
const validatorAddress = address;
|
|
326
|
-
result[validatorAddress] = this.computeStatsForValidator(validatorAddress, history, fromSlot, toSlot);
|
|
327
|
-
}
|
|
317
|
+
fromSlot ??= (this.lastProcessedSlot ?? slotNow) - BigInt(this.store.getHistoryLength());
|
|
318
|
+
toSlot ??= this.lastProcessedSlot ?? slotNow;
|
|
319
|
+
const stats = mapValues(histories, (history, address)=>this.computeStatsForValidator(address, history ?? [], fromSlot, toSlot));
|
|
328
320
|
return {
|
|
329
|
-
stats
|
|
321
|
+
stats,
|
|
330
322
|
lastProcessedSlot: this.lastProcessedSlot,
|
|
331
323
|
initialSlot: this.initialSlot,
|
|
332
324
|
slotWindow: this.store.getHistoryLength()
|
|
@@ -357,25 +349,32 @@ export class Sentinel extends EventEmitter {
|
|
|
357
349
|
computeStatsForValidator(address, allHistory, fromSlot, toSlot) {
|
|
358
350
|
let history = fromSlot ? allHistory.filter((h)=>h.slot >= fromSlot) : allHistory;
|
|
359
351
|
history = toSlot ? history.filter((h)=>h.slot <= toSlot) : history;
|
|
352
|
+
const lastProposal = history.filter((h)=>h.status === 'block-proposed' || h.status === 'block-mined').at(-1);
|
|
353
|
+
const lastAttestation = history.filter((h)=>h.status === 'attestation-sent').at(-1);
|
|
360
354
|
return {
|
|
361
355
|
address: EthAddress.fromString(address),
|
|
362
|
-
lastProposal: this.computeFromSlot(
|
|
363
|
-
lastAttestation: this.computeFromSlot(
|
|
356
|
+
lastProposal: this.computeFromSlot(lastProposal?.slot),
|
|
357
|
+
lastAttestation: this.computeFromSlot(lastAttestation?.slot),
|
|
364
358
|
totalSlots: history.length,
|
|
365
|
-
missedProposals: this.computeMissed(history, 'block',
|
|
366
|
-
|
|
359
|
+
missedProposals: this.computeMissed(history, 'block', [
|
|
360
|
+
'block-missed'
|
|
361
|
+
]),
|
|
362
|
+
missedAttestations: this.computeMissed(history, 'attestation', [
|
|
363
|
+
'attestation-missed'
|
|
364
|
+
]),
|
|
367
365
|
history
|
|
368
366
|
};
|
|
369
367
|
}
|
|
370
368
|
computeMissed(history, computeOverPrefix, filter) {
|
|
371
|
-
const relevantHistory = history.filter((h)
|
|
372
|
-
const filteredHistory = relevantHistory.filter((h)=>h.status
|
|
369
|
+
const relevantHistory = history.filter((h)=>!computeOverPrefix || h.status.startsWith(computeOverPrefix));
|
|
370
|
+
const filteredHistory = relevantHistory.filter((h)=>filter.includes(h.status));
|
|
373
371
|
return {
|
|
374
372
|
currentStreak: countWhile([
|
|
375
373
|
...relevantHistory
|
|
376
|
-
].reverse(), (h)=>h.status
|
|
374
|
+
].reverse(), (h)=>filter.includes(h.status)),
|
|
377
375
|
rate: relevantHistory.length === 0 ? undefined : filteredHistory.length / relevantHistory.length,
|
|
378
|
-
count: filteredHistory.length
|
|
376
|
+
count: filteredHistory.length,
|
|
377
|
+
total: relevantHistory.length
|
|
379
378
|
};
|
|
380
379
|
}
|
|
381
380
|
computeFromSlot(slot) {
|
package/dest/sentinel/store.d.ts
CHANGED
|
@@ -9,8 +9,10 @@ export declare class SentinelStore {
|
|
|
9
9
|
private readonly provenMap;
|
|
10
10
|
constructor(store: AztecAsyncKVStore, config: {
|
|
11
11
|
historyLength: number;
|
|
12
|
+
historicProvenPerformanceLength: number;
|
|
12
13
|
});
|
|
13
14
|
getHistoryLength(): number;
|
|
15
|
+
getHistoricProvenPerformanceLength(): number;
|
|
14
16
|
updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance): Promise<void>;
|
|
15
17
|
getProvenPerformance(who: EthAddress): Promise<{
|
|
16
18
|
missed: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sentinel/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAElC,qBAAa,aAAa;IAWtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IAXhB,gBAAuB,cAAc,KAAK;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAIlE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuC;gBAGvD,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sentinel/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAElC,qBAAa,aAAa;IAWtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IAXhB,gBAAuB,cAAc,KAAK;IAG1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAIlE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuC;gBAGvD,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,+BAA+B,EAAE,MAAM,CAAA;KAAE;IAM7E,gBAAgB;IAIhB,kCAAkC;IAI5B,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,0BAA0B;IAQ9E,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;YAKjG,sCAAsC;IA6BvC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,qBAAqB,GAAG,SAAS,CAAC;YAUhG,0BAA0B;IAY3B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC;IAQtE,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAKzF,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,sBAAsB;IAa9B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,gBAAgB;CAgBzB"}
|
package/dest/sentinel/store.js
CHANGED
|
@@ -18,6 +18,9 @@ export class SentinelStore {
|
|
|
18
18
|
getHistoryLength() {
|
|
19
19
|
return this.config.historyLength;
|
|
20
20
|
}
|
|
21
|
+
getHistoricProvenPerformanceLength() {
|
|
22
|
+
return this.config.historicProvenPerformanceLength;
|
|
23
|
+
}
|
|
21
24
|
async updateProvenPerformance(epoch, performance) {
|
|
22
25
|
await this.store.transactionAsync(async ()=>{
|
|
23
26
|
for (const [who, { missed, total }] of Object.entries(performance)){
|
|
@@ -53,8 +56,8 @@ export class SentinelStore {
|
|
|
53
56
|
// This should be sorted by epoch, but just in case.
|
|
54
57
|
// Since we keep the size small, this is not a big deal.
|
|
55
58
|
currentPerformance.sort((a, b)=>Number(a.epoch - b.epoch));
|
|
56
|
-
// keep the most recent `
|
|
57
|
-
const performanceToKeep = currentPerformance.slice(-this.config.
|
|
59
|
+
// keep the most recent `historicProvenPerformanceLength` entries.
|
|
60
|
+
const performanceToKeep = currentPerformance.slice(-this.config.historicProvenPerformanceLength);
|
|
58
61
|
await this.provenMap.set(who.toString(), this.serializePerformance(performanceToKeep));
|
|
59
62
|
}
|
|
60
63
|
async updateValidators(slot, statuses) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/aztec-node",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-devnet.2",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -66,33 +66,33 @@
|
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@aztec/archiver": "3.0.0-
|
|
70
|
-
"@aztec/bb-prover": "3.0.0-
|
|
71
|
-
"@aztec/blob-sink": "3.0.0-
|
|
72
|
-
"@aztec/constants": "3.0.0-
|
|
73
|
-
"@aztec/epoch-cache": "3.0.0-
|
|
74
|
-
"@aztec/ethereum": "3.0.0-
|
|
75
|
-
"@aztec/foundation": "3.0.0-
|
|
76
|
-
"@aztec/kv-store": "3.0.0-
|
|
77
|
-
"@aztec/l1-artifacts": "3.0.0-
|
|
78
|
-
"@aztec/merkle-tree": "3.0.0-
|
|
79
|
-
"@aztec/node-keystore": "3.0.0-
|
|
80
|
-
"@aztec/node-lib": "3.0.0-
|
|
81
|
-
"@aztec/noir-protocol-circuits-types": "3.0.0-
|
|
82
|
-
"@aztec/p2p": "3.0.0-
|
|
83
|
-
"@aztec/protocol-contracts": "3.0.0-
|
|
84
|
-
"@aztec/prover-client": "3.0.0-
|
|
85
|
-
"@aztec/sequencer-client": "3.0.0-
|
|
86
|
-
"@aztec/simulator": "3.0.0-
|
|
87
|
-
"@aztec/slasher": "3.0.0-
|
|
88
|
-
"@aztec/stdlib": "3.0.0-
|
|
89
|
-
"@aztec/telemetry-client": "3.0.0-
|
|
90
|
-
"@aztec/validator-client": "3.0.0-
|
|
91
|
-
"@aztec/world-state": "3.0.0-
|
|
69
|
+
"@aztec/archiver": "3.0.0-devnet.2",
|
|
70
|
+
"@aztec/bb-prover": "3.0.0-devnet.2",
|
|
71
|
+
"@aztec/blob-sink": "3.0.0-devnet.2",
|
|
72
|
+
"@aztec/constants": "3.0.0-devnet.2",
|
|
73
|
+
"@aztec/epoch-cache": "3.0.0-devnet.2",
|
|
74
|
+
"@aztec/ethereum": "3.0.0-devnet.2",
|
|
75
|
+
"@aztec/foundation": "3.0.0-devnet.2",
|
|
76
|
+
"@aztec/kv-store": "3.0.0-devnet.2",
|
|
77
|
+
"@aztec/l1-artifacts": "3.0.0-devnet.2",
|
|
78
|
+
"@aztec/merkle-tree": "3.0.0-devnet.2",
|
|
79
|
+
"@aztec/node-keystore": "3.0.0-devnet.2",
|
|
80
|
+
"@aztec/node-lib": "3.0.0-devnet.2",
|
|
81
|
+
"@aztec/noir-protocol-circuits-types": "3.0.0-devnet.2",
|
|
82
|
+
"@aztec/p2p": "3.0.0-devnet.2",
|
|
83
|
+
"@aztec/protocol-contracts": "3.0.0-devnet.2",
|
|
84
|
+
"@aztec/prover-client": "3.0.0-devnet.2",
|
|
85
|
+
"@aztec/sequencer-client": "3.0.0-devnet.2",
|
|
86
|
+
"@aztec/simulator": "3.0.0-devnet.2",
|
|
87
|
+
"@aztec/slasher": "3.0.0-devnet.2",
|
|
88
|
+
"@aztec/stdlib": "3.0.0-devnet.2",
|
|
89
|
+
"@aztec/telemetry-client": "3.0.0-devnet.2",
|
|
90
|
+
"@aztec/validator-client": "3.0.0-devnet.2",
|
|
91
|
+
"@aztec/world-state": "3.0.0-devnet.2",
|
|
92
92
|
"koa": "^2.16.1",
|
|
93
|
-
"koa-router": "^
|
|
93
|
+
"koa-router": "^13.1.1",
|
|
94
94
|
"tslib": "^2.4.0",
|
|
95
|
-
"viem": "2.
|
|
95
|
+
"viem": "npm:@spalladino/viem@2.38.2-eip7594.0"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@jest/globals": "^30.0.0",
|
package/src/aztec-node/config.ts
CHANGED
|
@@ -6,16 +6,12 @@ import {
|
|
|
6
6
|
l1ContractAddressesMapping,
|
|
7
7
|
} from '@aztec/ethereum';
|
|
8
8
|
import { type ConfigMappingsType, booleanConfigHelper, getConfigFromMappings } from '@aztec/foundation/config';
|
|
9
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
10
|
import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
|
|
10
11
|
import {
|
|
11
|
-
type AztecAddressHex,
|
|
12
|
-
type EthAddressHex,
|
|
13
|
-
type EthPrivateKey,
|
|
14
|
-
type EthRemoteSignerAccount,
|
|
15
|
-
type Hex,
|
|
16
12
|
type KeyStore,
|
|
17
|
-
type KeyStoreConfig,
|
|
18
13
|
type ValidatorKeyStore,
|
|
14
|
+
ethPrivateKeySchema,
|
|
19
15
|
keyStoreConfigMappings,
|
|
20
16
|
} from '@aztec/node-keystore';
|
|
21
17
|
import { type SharedNodeConfig, sharedNodeConfigMappings } from '@aztec/node-lib/config';
|
|
@@ -50,7 +46,6 @@ export type AztecNodeConfig = ArchiverConfig &
|
|
|
50
46
|
Pick<ProverClientUserConfig, 'bbBinaryPath' | 'bbWorkingDirectory' | 'realProofs'> &
|
|
51
47
|
P2PConfig &
|
|
52
48
|
DataStoreConfig &
|
|
53
|
-
KeyStoreConfig &
|
|
54
49
|
SentinelConfig &
|
|
55
50
|
SharedNodeConfig &
|
|
56
51
|
GenesisStateConfig &
|
|
@@ -97,7 +92,7 @@ export function getConfigEnvVars(): AztecNodeConfig {
|
|
|
97
92
|
|
|
98
93
|
type ConfigRequiredToBuildKeyStore = TxSenderConfig & SequencerClientConfig & SharedNodeConfig & ValidatorClientConfig;
|
|
99
94
|
|
|
100
|
-
function createKeyStoreFromWeb3Signer(config: ConfigRequiredToBuildKeyStore) {
|
|
95
|
+
function createKeyStoreFromWeb3Signer(config: ConfigRequiredToBuildKeyStore): KeyStore | undefined {
|
|
101
96
|
const validatorKeyStores: ValidatorKeyStore[] = [];
|
|
102
97
|
|
|
103
98
|
if (
|
|
@@ -108,22 +103,13 @@ function createKeyStoreFromWeb3Signer(config: ConfigRequiredToBuildKeyStore) {
|
|
|
108
103
|
) {
|
|
109
104
|
return undefined;
|
|
110
105
|
}
|
|
111
|
-
const coinbase = config.coinbase ? config.coinbase.toString() : config.validatorAddresses[0].toString();
|
|
112
|
-
const feeRecipient = config.feeRecipient ? config.feeRecipient.toString() : AztecAddress.ZERO.toString();
|
|
113
|
-
|
|
114
|
-
const publisherAddresses =
|
|
115
|
-
config.publisherAddresses && config.publisherAddresses.length > 0
|
|
116
|
-
? config.publisherAddresses.map(k => k.toChecksumString() as EthRemoteSignerAccount)
|
|
117
|
-
: [];
|
|
118
|
-
|
|
119
|
-
const attestors = config.validatorAddresses.map(k => k.toChecksumString() as EthRemoteSignerAccount);
|
|
120
106
|
|
|
121
107
|
validatorKeyStores.push({
|
|
122
|
-
attester:
|
|
123
|
-
feeRecipient: feeRecipient
|
|
124
|
-
coinbase: coinbase
|
|
108
|
+
attester: config.validatorAddresses,
|
|
109
|
+
feeRecipient: config.feeRecipient ?? AztecAddress.ZERO,
|
|
110
|
+
coinbase: config.coinbase ?? config.validatorAddresses[0],
|
|
125
111
|
remoteSigner: config.web3SignerUrl,
|
|
126
|
-
publisher: publisherAddresses,
|
|
112
|
+
publisher: config.publisherAddresses ?? [],
|
|
127
113
|
});
|
|
128
114
|
|
|
129
115
|
const keyStore: KeyStore = {
|
|
@@ -136,30 +122,26 @@ function createKeyStoreFromWeb3Signer(config: ConfigRequiredToBuildKeyStore) {
|
|
|
136
122
|
return keyStore;
|
|
137
123
|
}
|
|
138
124
|
|
|
139
|
-
function createKeyStoreFromPrivateKeys(config: ConfigRequiredToBuildKeyStore) {
|
|
125
|
+
function createKeyStoreFromPrivateKeys(config: ConfigRequiredToBuildKeyStore): KeyStore | undefined {
|
|
140
126
|
const validatorKeyStores: ValidatorKeyStore[] = [];
|
|
141
|
-
const ethPrivateKeys
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const key = validatorKeys[i];
|
|
145
|
-
const ethPrivateKey: EthPrivateKey = key as Hex<32>;
|
|
146
|
-
ethPrivateKeys.push(ethPrivateKey);
|
|
147
|
-
}
|
|
127
|
+
const ethPrivateKeys = config.validatorPrivateKeys
|
|
128
|
+
? config.validatorPrivateKeys.getValue().map(x => ethPrivateKeySchema.parse(x))
|
|
129
|
+
: [];
|
|
148
130
|
|
|
149
131
|
if (!ethPrivateKeys.length) {
|
|
150
132
|
return undefined;
|
|
151
133
|
}
|
|
152
|
-
const coinbase = config.coinbase
|
|
153
|
-
const feeRecipient = config.feeRecipient
|
|
134
|
+
const coinbase = config.coinbase ?? EthAddress.fromString(privateKeyToAddress(ethPrivateKeys[0]));
|
|
135
|
+
const feeRecipient = config.feeRecipient ?? AztecAddress.ZERO;
|
|
154
136
|
|
|
155
137
|
const publisherKeys = config.publisherPrivateKeys
|
|
156
|
-
? config.publisherPrivateKeys.map(k => k.getValue()
|
|
138
|
+
? config.publisherPrivateKeys.map(k => ethPrivateKeySchema.parse(k.getValue()))
|
|
157
139
|
: [];
|
|
158
140
|
|
|
159
141
|
validatorKeyStores.push({
|
|
160
142
|
attester: ethPrivateKeys,
|
|
161
|
-
feeRecipient: feeRecipient
|
|
162
|
-
coinbase: coinbase
|
|
143
|
+
feeRecipient: feeRecipient,
|
|
144
|
+
coinbase: coinbase,
|
|
163
145
|
remoteSigner: undefined,
|
|
164
146
|
publisher: publisherKeys,
|
|
165
147
|
});
|
|
@@ -174,7 +156,9 @@ function createKeyStoreFromPrivateKeys(config: ConfigRequiredToBuildKeyStore) {
|
|
|
174
156
|
return keyStore;
|
|
175
157
|
}
|
|
176
158
|
|
|
177
|
-
export function createKeyStoreForValidator(
|
|
159
|
+
export function createKeyStoreForValidator(
|
|
160
|
+
config: TxSenderConfig & SequencerClientConfig & SharedNodeConfig,
|
|
161
|
+
): KeyStore | undefined {
|
|
178
162
|
if (config.web3SignerUrl !== undefined && config.web3SignerUrl.length > 0) {
|
|
179
163
|
return createKeyStoreFromWeb3Signer(config);
|
|
180
164
|
}
|