@aztec/validator-client 1.0.0 → 1.1.0
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/config.d.ts.map +1 -1
- package/dest/config.js +4 -1
- package/dest/validator.d.ts +2 -0
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +38 -12
- package/package.json +10 -10
- package/src/config.ts +1 -0
- package/src/validator.ts +52 -13
package/dest/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAKjB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,oBAAoB,EAAE,WAAW,CAAC,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;IAEnD,+BAA+B;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAE1B,+DAA+D;IAC/D,4BAA4B,EAAE,MAAM,CAAC;IAErC,+CAA+C;IAC/C,kBAAkB,EAAE,OAAO,CAAC;IAE5B,wEAAwE;IACxE,4BAA4B,EAAE,MAAM,CAAC;CACtC;AAED,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAKjB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6EAA6E;IAC7E,oBAAoB,EAAE,WAAW,CAAC,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;IAEnD,+BAA+B;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAE1B,+DAA+D;IAC/D,4BAA4B,EAAE,MAAM,CAAC;IAErC,+CAA+C;IAC/C,kBAAkB,EAAE,OAAO,CAAC;IAE5B,wEAAwE;IACxE,4BAA4B,EAAE,MAAM,CAAC;CACtC;AAED,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,CA6BnF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,qBAAqB,CAExD"}
|
package/dest/config.js
CHANGED
|
@@ -3,7 +3,10 @@ export const validatorClientConfigMappings = {
|
|
|
3
3
|
validatorPrivateKeys: {
|
|
4
4
|
env: 'VALIDATOR_PRIVATE_KEYS',
|
|
5
5
|
description: 'List of private keys of the validators participating in attestation duties',
|
|
6
|
-
...secretValueConfigHelper((val)=>val ? val.split(',').map((key)=>`0x${key.replace('0x', '')}`) : [])
|
|
6
|
+
...secretValueConfigHelper((val)=>val ? val.split(',').map((key)=>`0x${key.replace('0x', '')}`) : []),
|
|
7
|
+
fallback: [
|
|
8
|
+
'VALIDATOR_PRIVATE_KEY'
|
|
9
|
+
]
|
|
7
10
|
},
|
|
8
11
|
disableValidator: {
|
|
9
12
|
env: 'VALIDATOR_DISABLED',
|
package/dest/validator.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
+
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
2
3
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
4
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
5
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
@@ -48,6 +49,7 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
48
49
|
private handleEpochCommitteeUpdate;
|
|
49
50
|
static new(config: ValidatorClientConfig & Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>, blockBuilder: IFullNodeBlockBuilder, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, dateProvider?: DateProvider, telemetry?: TelemetryClient): ValidatorClient;
|
|
50
51
|
getValidatorAddresses(): EthAddress[];
|
|
52
|
+
signWithAddress(addr: EthAddress, msg: Buffer32): Promise<import("@aztec/stdlib/block").Signature>;
|
|
51
53
|
configureSlashing(config: Partial<Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>>): void;
|
|
52
54
|
start(): Promise<void>;
|
|
53
55
|
stop(): Promise<void>;
|
package/dest/validator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dest/validator.js
CHANGED
|
@@ -2,6 +2,7 @@ import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
|
2
2
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
5
6
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
6
7
|
import { sleep } from '@aztec/foundation/sleep';
|
|
7
8
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
@@ -90,6 +91,9 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
90
91
|
getValidatorAddresses() {
|
|
91
92
|
return this.keyStore.getAddresses();
|
|
92
93
|
}
|
|
94
|
+
signWithAddress(addr, msg) {
|
|
95
|
+
return this.keyStore.signWithAddress(addr, msg);
|
|
96
|
+
}
|
|
93
97
|
configureSlashing(config) {
|
|
94
98
|
this.config.slashInvalidBlockEnabled = config.slashInvalidBlockEnabled ?? this.config.slashInvalidBlockEnabled;
|
|
95
99
|
this.config.slashInvalidBlockPenalty = config.slashInvalidBlockPenalty ?? this.config.slashInvalidBlockPenalty;
|
|
@@ -121,6 +125,9 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
121
125
|
const slotNumber = proposal.slotNumber.toNumber();
|
|
122
126
|
const blockNumber = proposal.blockNumber;
|
|
123
127
|
const proposer = proposal.getSender();
|
|
128
|
+
// Check that I have any address in current committee before attesting
|
|
129
|
+
const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
|
|
130
|
+
const partOfCommittee = inCommittee.length > 0;
|
|
124
131
|
const proposalInfo = {
|
|
125
132
|
slotNumber,
|
|
126
133
|
blockNumber,
|
|
@@ -135,7 +142,9 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
135
142
|
const invalidProposal = await this.blockProposalValidator.validate(proposal);
|
|
136
143
|
if (invalidProposal) {
|
|
137
144
|
this.log.warn(`Proposal is not valid, skipping attestation`);
|
|
138
|
-
|
|
145
|
+
if (partOfCommittee) {
|
|
146
|
+
this.metrics.incFailedAttestations(1, 'invalid_proposal');
|
|
147
|
+
}
|
|
139
148
|
return undefined;
|
|
140
149
|
}
|
|
141
150
|
// Check that the parent proposal is a block we know, otherwise reexecution would fail.
|
|
@@ -144,10 +153,23 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
144
153
|
// would not be rebroadcasted. But it also means that nodes that have not fully synced would
|
|
145
154
|
// not rebroadcast the proposal.
|
|
146
155
|
if (blockNumber > INITIAL_L2_BLOCK_NUM) {
|
|
147
|
-
const
|
|
156
|
+
const config = this.blockBuilder.getConfig();
|
|
157
|
+
const deadline = this.getReexecutionDeadline(proposal, config);
|
|
158
|
+
const currentTime = this.dateProvider.now();
|
|
159
|
+
const timeoutDurationMs = deadline.getTime() - currentTime;
|
|
160
|
+
const parentBlock = timeoutDurationMs <= 0 ? undefined : await retryUntil(async ()=>{
|
|
161
|
+
const block = await this.blockSource.getBlock(blockNumber - 1);
|
|
162
|
+
if (block) {
|
|
163
|
+
return block;
|
|
164
|
+
}
|
|
165
|
+
await this.blockSource.syncImmediate();
|
|
166
|
+
return await this.blockSource.getBlock(blockNumber - 1);
|
|
167
|
+
}, 'Force Archiver Sync', timeoutDurationMs / 1000, 0.5);
|
|
148
168
|
if (parentBlock === undefined) {
|
|
149
169
|
this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`);
|
|
150
|
-
|
|
170
|
+
if (partOfCommittee) {
|
|
171
|
+
this.metrics.incFailedAttestations(1, 'parent_block_not_found');
|
|
172
|
+
}
|
|
151
173
|
return undefined;
|
|
152
174
|
}
|
|
153
175
|
if (!proposal.payload.header.lastArchiveRoot.equals(parentBlock.archive.root)) {
|
|
@@ -156,25 +178,23 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
156
178
|
parentBlockArchiveRoot: parentBlock.archive.root.toString(),
|
|
157
179
|
...proposalInfo
|
|
158
180
|
});
|
|
159
|
-
|
|
181
|
+
if (partOfCommittee) {
|
|
182
|
+
this.metrics.incFailedAttestations(1, 'parent_block_does_not_match');
|
|
183
|
+
}
|
|
160
184
|
return undefined;
|
|
161
185
|
}
|
|
162
186
|
}
|
|
163
187
|
// Collect txs from the proposal
|
|
164
188
|
const { missing, txs } = await this.txCollector.collectForBlockProposal(proposal, proposalSender);
|
|
165
|
-
// Check that I have any address in current committee before attesting
|
|
166
|
-
const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
|
|
167
|
-
if (inCommittee.length === 0) {
|
|
168
|
-
this.log.verbose(`No validator in the committee, skipping attestation`);
|
|
169
|
-
return undefined;
|
|
170
|
-
}
|
|
171
189
|
// Check that all of the transactions in the proposal are available in the tx pool before attesting
|
|
172
190
|
if (missing && missing.length > 0) {
|
|
173
191
|
this.log.warn(`Missing ${missing.length}/${proposal.payload.txHashes.length} txs to attest to proposal`, {
|
|
174
192
|
...proposalInfo,
|
|
175
193
|
missing
|
|
176
194
|
});
|
|
177
|
-
|
|
195
|
+
if (partOfCommittee) {
|
|
196
|
+
this.metrics.incFailedAttestations(1, 'tx_not_available');
|
|
197
|
+
}
|
|
178
198
|
return undefined;
|
|
179
199
|
}
|
|
180
200
|
// Check that I have the same set of l1ToL2Messages as the proposal
|
|
@@ -187,7 +207,13 @@ const MAX_PROPOSERS_OF_INVALID_BLOCKS = 1000;
|
|
|
187
207
|
computedInHash: computedInHash.toString(),
|
|
188
208
|
...proposalInfo
|
|
189
209
|
});
|
|
190
|
-
|
|
210
|
+
if (partOfCommittee) {
|
|
211
|
+
this.metrics.incFailedAttestations(1, 'in_hash_mismatch');
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
if (!partOfCommittee) {
|
|
216
|
+
this.log.verbose(`No validator in the committee, skipping attestation`);
|
|
191
217
|
return undefined;
|
|
192
218
|
}
|
|
193
219
|
// Try re-executing the transactions in the proposal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,15 +64,15 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/constants": "1.
|
|
68
|
-
"@aztec/epoch-cache": "1.
|
|
69
|
-
"@aztec/ethereum": "1.
|
|
70
|
-
"@aztec/foundation": "1.
|
|
71
|
-
"@aztec/p2p": "1.
|
|
72
|
-
"@aztec/prover-client": "1.
|
|
73
|
-
"@aztec/slasher": "1.
|
|
74
|
-
"@aztec/stdlib": "1.
|
|
75
|
-
"@aztec/telemetry-client": "1.
|
|
67
|
+
"@aztec/constants": "1.1.0",
|
|
68
|
+
"@aztec/epoch-cache": "1.1.0",
|
|
69
|
+
"@aztec/ethereum": "1.1.0",
|
|
70
|
+
"@aztec/foundation": "1.1.0",
|
|
71
|
+
"@aztec/p2p": "1.1.0",
|
|
72
|
+
"@aztec/prover-client": "1.1.0",
|
|
73
|
+
"@aztec/slasher": "1.1.0",
|
|
74
|
+
"@aztec/stdlib": "1.1.0",
|
|
75
|
+
"@aztec/telemetry-client": "1.1.0",
|
|
76
76
|
"koa": "^2.16.1",
|
|
77
77
|
"koa-router": "^12.0.0",
|
|
78
78
|
"tslib": "^2.4.0",
|
package/src/config.ts
CHANGED
|
@@ -34,6 +34,7 @@ export const validatorClientConfigMappings: ConfigMappingsType<ValidatorClientCo
|
|
|
34
34
|
...secretValueConfigHelper<`0x${string}`[]>(val =>
|
|
35
35
|
val ? val.split(',').map<`0x${string}`>(key => `0x${key.replace('0x', '')}`) : [],
|
|
36
36
|
),
|
|
37
|
+
fallback: ['VALIDATOR_PRIVATE_KEY'],
|
|
37
38
|
},
|
|
38
39
|
disableValidator: {
|
|
39
40
|
env: 'VALIDATOR_DISABLED',
|
package/src/validator.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Buffer32 } from '@aztec/foundation/buffer';
|
|
|
4
4
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
6
6
|
import { createLogger } from '@aztec/foundation/log';
|
|
7
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
7
8
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
8
9
|
import { sleep } from '@aztec/foundation/sleep';
|
|
9
10
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
@@ -181,6 +182,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
181
182
|
return this.keyStore.getAddresses();
|
|
182
183
|
}
|
|
183
184
|
|
|
185
|
+
public signWithAddress(addr: EthAddress, msg: Buffer32) {
|
|
186
|
+
return this.keyStore.signWithAddress(addr, msg);
|
|
187
|
+
}
|
|
188
|
+
|
|
184
189
|
public configureSlashing(
|
|
185
190
|
config: Partial<
|
|
186
191
|
Pick<SlasherConfig, 'slashInvalidBlockEnabled' | 'slashInvalidBlockPenalty' | 'slashInvalidBlockMaxPenalty'>
|
|
@@ -226,6 +231,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
226
231
|
const blockNumber = proposal.blockNumber;
|
|
227
232
|
const proposer = proposal.getSender();
|
|
228
233
|
|
|
234
|
+
// Check that I have any address in current committee before attesting
|
|
235
|
+
const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
|
|
236
|
+
const partOfCommittee = inCommittee.length > 0;
|
|
237
|
+
|
|
229
238
|
const proposalInfo = {
|
|
230
239
|
slotNumber,
|
|
231
240
|
blockNumber,
|
|
@@ -241,7 +250,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
241
250
|
const invalidProposal = await this.blockProposalValidator.validate(proposal);
|
|
242
251
|
if (invalidProposal) {
|
|
243
252
|
this.log.warn(`Proposal is not valid, skipping attestation`);
|
|
244
|
-
|
|
253
|
+
if (partOfCommittee) {
|
|
254
|
+
this.metrics.incFailedAttestations(1, 'invalid_proposal');
|
|
255
|
+
}
|
|
245
256
|
return undefined;
|
|
246
257
|
}
|
|
247
258
|
|
|
@@ -251,10 +262,34 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
251
262
|
// would not be rebroadcasted. But it also means that nodes that have not fully synced would
|
|
252
263
|
// not rebroadcast the proposal.
|
|
253
264
|
if (blockNumber > INITIAL_L2_BLOCK_NUM) {
|
|
254
|
-
const
|
|
265
|
+
const config = this.blockBuilder.getConfig();
|
|
266
|
+
const deadline = this.getReexecutionDeadline(proposal, config);
|
|
267
|
+
const currentTime = this.dateProvider.now();
|
|
268
|
+
const timeoutDurationMs = deadline.getTime() - currentTime;
|
|
269
|
+
const parentBlock =
|
|
270
|
+
timeoutDurationMs <= 0
|
|
271
|
+
? undefined
|
|
272
|
+
: await retryUntil(
|
|
273
|
+
async () => {
|
|
274
|
+
const block = await this.blockSource.getBlock(blockNumber - 1);
|
|
275
|
+
if (block) {
|
|
276
|
+
return block;
|
|
277
|
+
}
|
|
278
|
+
await this.blockSource.syncImmediate();
|
|
279
|
+
return await this.blockSource.getBlock(blockNumber - 1);
|
|
280
|
+
},
|
|
281
|
+
'Force Archiver Sync',
|
|
282
|
+
timeoutDurationMs / 1000, // Continue retrying until the deadline
|
|
283
|
+
0.5, // Retry every 500ms
|
|
284
|
+
);
|
|
285
|
+
|
|
255
286
|
if (parentBlock === undefined) {
|
|
256
287
|
this.log.warn(`Parent block for ${blockNumber} not found, skipping attestation`);
|
|
257
|
-
|
|
288
|
+
|
|
289
|
+
if (partOfCommittee) {
|
|
290
|
+
this.metrics.incFailedAttestations(1, 'parent_block_not_found');
|
|
291
|
+
}
|
|
292
|
+
|
|
258
293
|
return undefined;
|
|
259
294
|
}
|
|
260
295
|
if (!proposal.payload.header.lastArchiveRoot.equals(parentBlock.archive.root)) {
|
|
@@ -263,7 +298,9 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
263
298
|
parentBlockArchiveRoot: parentBlock.archive.root.toString(),
|
|
264
299
|
...proposalInfo,
|
|
265
300
|
});
|
|
266
|
-
|
|
301
|
+
if (partOfCommittee) {
|
|
302
|
+
this.metrics.incFailedAttestations(1, 'parent_block_does_not_match');
|
|
303
|
+
}
|
|
267
304
|
return undefined;
|
|
268
305
|
}
|
|
269
306
|
}
|
|
@@ -271,20 +308,15 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
271
308
|
// Collect txs from the proposal
|
|
272
309
|
const { missing, txs } = await this.txCollector.collectForBlockProposal(proposal, proposalSender);
|
|
273
310
|
|
|
274
|
-
// Check that I have any address in current committee before attesting
|
|
275
|
-
const inCommittee = await this.epochCache.filterInCommittee(this.keyStore.getAddresses());
|
|
276
|
-
if (inCommittee.length === 0) {
|
|
277
|
-
this.log.verbose(`No validator in the committee, skipping attestation`);
|
|
278
|
-
return undefined;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
311
|
// Check that all of the transactions in the proposal are available in the tx pool before attesting
|
|
282
312
|
if (missing && missing.length > 0) {
|
|
283
313
|
this.log.warn(`Missing ${missing.length}/${proposal.payload.txHashes.length} txs to attest to proposal`, {
|
|
284
314
|
...proposalInfo,
|
|
285
315
|
missing,
|
|
286
316
|
});
|
|
287
|
-
|
|
317
|
+
if (partOfCommittee) {
|
|
318
|
+
this.metrics.incFailedAttestations(1, 'tx_not_available');
|
|
319
|
+
}
|
|
288
320
|
return undefined;
|
|
289
321
|
}
|
|
290
322
|
|
|
@@ -298,7 +330,14 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
298
330
|
computedInHash: computedInHash.toString(),
|
|
299
331
|
...proposalInfo,
|
|
300
332
|
});
|
|
301
|
-
|
|
333
|
+
if (partOfCommittee) {
|
|
334
|
+
this.metrics.incFailedAttestations(1, 'in_hash_mismatch');
|
|
335
|
+
}
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (!partOfCommittee) {
|
|
340
|
+
this.log.verbose(`No validator in the committee, skipping attestation`);
|
|
302
341
|
return undefined;
|
|
303
342
|
}
|
|
304
343
|
|