@aztec/validator-ha-signer 0.0.1-commit.fffb133c → 0.0.6-commit.a2d1860fe9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dest/config.d.ts +23 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +19 -0
- package/dest/db/postgres.d.ts +17 -3
- package/dest/db/postgres.d.ts.map +1 -1
- package/dest/db/postgres.js +32 -5
- package/dest/db/schema.d.ts +17 -10
- package/dest/db/schema.d.ts.map +1 -1
- package/dest/db/schema.js +39 -22
- package/dest/db/types.d.ts +7 -2
- package/dest/db/types.d.ts.map +1 -1
- package/dest/slashing_protection_service.d.ts +8 -4
- package/dest/slashing_protection_service.d.ts.map +1 -1
- package/dest/slashing_protection_service.js +41 -12
- package/dest/types.d.ts +18 -5
- package/dest/types.d.ts.map +1 -1
- package/dest/validator_ha_signer.d.ts +4 -3
- package/dest/validator_ha_signer.d.ts.map +1 -1
- package/dest/validator_ha_signer.js +8 -3
- package/package.json +3 -2
- package/src/config.ts +24 -0
- package/src/db/postgres.ts +33 -2
- package/src/db/schema.ts +41 -22
- package/src/db/types.ts +6 -1
- package/src/slashing_protection_service.ts +52 -15
- package/src/types.ts +19 -0
- package/src/validator_ha_signer.ts +8 -3
package/src/db/schema.ts
CHANGED
|
@@ -16,12 +16,13 @@ export const SCHEMA_VERSION = 1;
|
|
|
16
16
|
*/
|
|
17
17
|
export const CREATE_VALIDATOR_DUTIES_TABLE = `
|
|
18
18
|
CREATE TABLE IF NOT EXISTS validator_duties (
|
|
19
|
+
rollup_address VARCHAR(42) NOT NULL,
|
|
19
20
|
validator_address VARCHAR(42) NOT NULL,
|
|
20
21
|
slot BIGINT NOT NULL,
|
|
21
22
|
block_number BIGINT NOT NULL,
|
|
22
23
|
block_index_within_checkpoint INTEGER NOT NULL DEFAULT 0,
|
|
23
24
|
duty_type VARCHAR(30) NOT NULL CHECK (duty_type IN ('BLOCK_PROPOSAL', 'CHECKPOINT_PROPOSAL', 'ATTESTATION', 'ATTESTATIONS_AND_SIGNERS', 'GOVERNANCE_VOTE', 'SLASHING_VOTE')),
|
|
24
|
-
status VARCHAR(20) NOT NULL CHECK (status IN ('signing', 'signed'
|
|
25
|
+
status VARCHAR(20) NOT NULL CHECK (status IN ('signing', 'signed')),
|
|
25
26
|
message_hash VARCHAR(66) NOT NULL,
|
|
26
27
|
signature VARCHAR(132),
|
|
27
28
|
node_id VARCHAR(255) NOT NULL,
|
|
@@ -30,7 +31,7 @@ CREATE TABLE IF NOT EXISTS validator_duties (
|
|
|
30
31
|
completed_at TIMESTAMP,
|
|
31
32
|
error_message TEXT,
|
|
32
33
|
|
|
33
|
-
PRIMARY KEY (validator_address, slot, duty_type, block_index_within_checkpoint),
|
|
34
|
+
PRIMARY KEY (rollup_address, validator_address, slot, duty_type, block_index_within_checkpoint),
|
|
34
35
|
CHECK (completed_at IS NULL OR completed_at >= started_at)
|
|
35
36
|
);
|
|
36
37
|
`;
|
|
@@ -101,6 +102,7 @@ SELECT version FROM schema_version ORDER BY version DESC LIMIT 1;
|
|
|
101
102
|
export const INSERT_OR_GET_DUTY = `
|
|
102
103
|
WITH inserted AS (
|
|
103
104
|
INSERT INTO validator_duties (
|
|
105
|
+
rollup_address,
|
|
104
106
|
validator_address,
|
|
105
107
|
slot,
|
|
106
108
|
block_number,
|
|
@@ -111,9 +113,10 @@ WITH inserted AS (
|
|
|
111
113
|
node_id,
|
|
112
114
|
lock_token,
|
|
113
115
|
started_at
|
|
114
|
-
) VALUES ($1, $2, $3, $4, $5, 'signing', $
|
|
115
|
-
ON CONFLICT (validator_address, slot, duty_type, block_index_within_checkpoint) DO NOTHING
|
|
116
|
+
) VALUES ($1, $2, $3, $4, $5, $6, 'signing', $7, $8, $9, CURRENT_TIMESTAMP)
|
|
117
|
+
ON CONFLICT (rollup_address, validator_address, slot, duty_type, block_index_within_checkpoint) DO NOTHING
|
|
116
118
|
RETURNING
|
|
119
|
+
rollup_address,
|
|
117
120
|
validator_address,
|
|
118
121
|
slot,
|
|
119
122
|
block_number,
|
|
@@ -132,6 +135,7 @@ WITH inserted AS (
|
|
|
132
135
|
SELECT * FROM inserted
|
|
133
136
|
UNION ALL
|
|
134
137
|
SELECT
|
|
138
|
+
rollup_address,
|
|
135
139
|
validator_address,
|
|
136
140
|
slot,
|
|
137
141
|
block_number,
|
|
@@ -147,10 +151,11 @@ SELECT
|
|
|
147
151
|
error_message,
|
|
148
152
|
FALSE as is_new
|
|
149
153
|
FROM validator_duties
|
|
150
|
-
WHERE
|
|
151
|
-
AND
|
|
152
|
-
AND
|
|
153
|
-
AND
|
|
154
|
+
WHERE rollup_address = $1
|
|
155
|
+
AND validator_address = $2
|
|
156
|
+
AND slot = $3
|
|
157
|
+
AND duty_type = $6
|
|
158
|
+
AND block_index_within_checkpoint = $5
|
|
154
159
|
AND NOT EXISTS (SELECT 1 FROM inserted);
|
|
155
160
|
`;
|
|
156
161
|
|
|
@@ -162,12 +167,13 @@ UPDATE validator_duties
|
|
|
162
167
|
SET status = 'signed',
|
|
163
168
|
signature = $1,
|
|
164
169
|
completed_at = CURRENT_TIMESTAMP
|
|
165
|
-
WHERE
|
|
166
|
-
AND
|
|
167
|
-
AND
|
|
168
|
-
AND
|
|
170
|
+
WHERE rollup_address = $2
|
|
171
|
+
AND validator_address = $3
|
|
172
|
+
AND slot = $4
|
|
173
|
+
AND duty_type = $5
|
|
174
|
+
AND block_index_within_checkpoint = $6
|
|
169
175
|
AND status = 'signing'
|
|
170
|
-
AND lock_token = $
|
|
176
|
+
AND lock_token = $7;
|
|
171
177
|
`;
|
|
172
178
|
|
|
173
179
|
/**
|
|
@@ -176,12 +182,13 @@ WHERE validator_address = $2
|
|
|
176
182
|
*/
|
|
177
183
|
export const DELETE_DUTY = `
|
|
178
184
|
DELETE FROM validator_duties
|
|
179
|
-
WHERE
|
|
180
|
-
AND
|
|
181
|
-
AND
|
|
182
|
-
AND
|
|
185
|
+
WHERE rollup_address = $1
|
|
186
|
+
AND validator_address = $2
|
|
187
|
+
AND slot = $3
|
|
188
|
+
AND duty_type = $4
|
|
189
|
+
AND block_index_within_checkpoint = $5
|
|
183
190
|
AND status = 'signing'
|
|
184
|
-
AND lock_token = $
|
|
191
|
+
AND lock_token = $6;
|
|
185
192
|
`;
|
|
186
193
|
|
|
187
194
|
/**
|
|
@@ -196,23 +203,34 @@ WHERE status = 'signed'
|
|
|
196
203
|
|
|
197
204
|
/**
|
|
198
205
|
* Query to clean up old duties (for maintenance)
|
|
199
|
-
* Removes duties older than a specified
|
|
206
|
+
* Removes SIGNED duties older than a specified age (in milliseconds)
|
|
200
207
|
*/
|
|
201
208
|
export const CLEANUP_OLD_DUTIES = `
|
|
202
209
|
DELETE FROM validator_duties
|
|
203
|
-
WHERE status
|
|
204
|
-
AND started_at < $1;
|
|
210
|
+
WHERE status = 'signed'
|
|
211
|
+
AND started_at < CURRENT_TIMESTAMP - ($1 || ' milliseconds')::INTERVAL;
|
|
205
212
|
`;
|
|
206
213
|
|
|
207
214
|
/**
|
|
208
215
|
* Query to cleanup own stuck duties
|
|
209
216
|
* Removes duties in 'signing' status for a specific node that are older than maxAgeMs
|
|
217
|
+
* Uses DB's CURRENT_TIMESTAMP to avoid clock skew issues between nodes
|
|
210
218
|
*/
|
|
211
219
|
export const CLEANUP_OWN_STUCK_DUTIES = `
|
|
212
220
|
DELETE FROM validator_duties
|
|
213
221
|
WHERE node_id = $1
|
|
214
222
|
AND status = 'signing'
|
|
215
|
-
AND started_at < $2;
|
|
223
|
+
AND started_at < CURRENT_TIMESTAMP - ($2 || ' milliseconds')::INTERVAL;
|
|
224
|
+
`;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Query to cleanup duties with outdated rollup address
|
|
228
|
+
* Removes all duties where the rollup address doesn't match the current one
|
|
229
|
+
* Used after a rollup upgrade to clean up duties for the old rollup
|
|
230
|
+
*/
|
|
231
|
+
export const CLEANUP_OUTDATED_ROLLUP_DUTIES = `
|
|
232
|
+
DELETE FROM validator_duties
|
|
233
|
+
WHERE rollup_address != $1;
|
|
216
234
|
`;
|
|
217
235
|
|
|
218
236
|
/**
|
|
@@ -231,6 +249,7 @@ export const DROP_SCHEMA_VERSION_TABLE = `DROP TABLE IF EXISTS schema_version;`;
|
|
|
231
249
|
*/
|
|
232
250
|
export const GET_STUCK_DUTIES = `
|
|
233
251
|
SELECT
|
|
252
|
+
rollup_address,
|
|
234
253
|
validator_address,
|
|
235
254
|
slot,
|
|
236
255
|
block_number,
|
package/src/db/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { Signature } from '@aztec/foundation/eth-signature';
|
|
|
6
6
|
* Row type from PostgreSQL query
|
|
7
7
|
*/
|
|
8
8
|
export interface DutyRow {
|
|
9
|
+
rollup_address: string;
|
|
9
10
|
validator_address: string;
|
|
10
11
|
slot: string;
|
|
11
12
|
block_number: string;
|
|
@@ -54,6 +55,8 @@ export enum DutyStatus {
|
|
|
54
55
|
* Record of a validator duty in the database
|
|
55
56
|
*/
|
|
56
57
|
export interface ValidatorDutyRecord {
|
|
58
|
+
/** Ethereum address of the rollup contract */
|
|
59
|
+
rollupAddress: EthAddress;
|
|
57
60
|
/** Ethereum address of the validator */
|
|
58
61
|
validatorAddress: EthAddress;
|
|
59
62
|
/** Slot number for this duty */
|
|
@@ -78,7 +81,7 @@ export interface ValidatorDutyRecord {
|
|
|
78
81
|
startedAt: Date;
|
|
79
82
|
/** When the duty signing was completed (success or failure) */
|
|
80
83
|
completedAt?: Date;
|
|
81
|
-
/** Error message
|
|
84
|
+
/** Error message (currently unused) */
|
|
82
85
|
errorMessage?: string;
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -87,6 +90,7 @@ export interface ValidatorDutyRecord {
|
|
|
87
90
|
* blockIndexWithinCheckpoint is REQUIRED and must be >= 0.
|
|
88
91
|
*/
|
|
89
92
|
export interface BlockProposalDutyIdentifier {
|
|
93
|
+
rollupAddress: EthAddress;
|
|
90
94
|
validatorAddress: EthAddress;
|
|
91
95
|
slot: SlotNumber;
|
|
92
96
|
/** Block index within checkpoint (0, 1, 2...). Required for block proposals. */
|
|
@@ -99,6 +103,7 @@ export interface BlockProposalDutyIdentifier {
|
|
|
99
103
|
* blockIndexWithinCheckpoint is not applicable (internally stored as -1).
|
|
100
104
|
*/
|
|
101
105
|
export interface OtherDutyIdentifier {
|
|
106
|
+
rollupAddress: EthAddress;
|
|
102
107
|
validatorAddress: EthAddress;
|
|
103
108
|
slot: SlotNumber;
|
|
104
109
|
dutyType:
|
|
@@ -40,6 +40,7 @@ export class SlashingProtectionService {
|
|
|
40
40
|
private readonly maxStuckDutiesAgeMs: number;
|
|
41
41
|
|
|
42
42
|
private cleanupRunningPromise: RunningPromise;
|
|
43
|
+
private lastOldDutiesCleanupAtMs?: number;
|
|
43
44
|
|
|
44
45
|
constructor(
|
|
45
46
|
private readonly db: SlashingProtectionDatabase,
|
|
@@ -51,11 +52,7 @@ export class SlashingProtectionService {
|
|
|
51
52
|
// Default to 144s (2x 72s Aztec slot duration) if not explicitly configured
|
|
52
53
|
this.maxStuckDutiesAgeMs = config.maxStuckDutiesAgeMs ?? 144_000;
|
|
53
54
|
|
|
54
|
-
this.cleanupRunningPromise = new RunningPromise(
|
|
55
|
-
this.cleanupStuckDuties.bind(this),
|
|
56
|
-
this.log,
|
|
57
|
-
this.maxStuckDutiesAgeMs,
|
|
58
|
-
);
|
|
55
|
+
this.cleanupRunningPromise = new RunningPromise(this.cleanup.bind(this), this.log, this.maxStuckDutiesAgeMs);
|
|
59
56
|
}
|
|
60
57
|
|
|
61
58
|
/**
|
|
@@ -67,7 +64,6 @@ export class SlashingProtectionService {
|
|
|
67
64
|
* 2. If insert succeeds, we acquired the lock - return the lockToken
|
|
68
65
|
* 3. If a record exists, handle based on status:
|
|
69
66
|
* - SIGNED: Throw appropriate error (already signed or slashing protection)
|
|
70
|
-
* - FAILED: Delete the failed record
|
|
71
67
|
* - SIGNING: Wait and poll until status changes, then handle result
|
|
72
68
|
*
|
|
73
69
|
* @returns The lockToken that must be used for recordSuccess/deleteDuty
|
|
@@ -149,10 +145,11 @@ export class SlashingProtectionService {
|
|
|
149
145
|
* @returns true if the update succeeded, false if token didn't match
|
|
150
146
|
*/
|
|
151
147
|
async recordSuccess(params: RecordSuccessParams): Promise<boolean> {
|
|
152
|
-
const { validatorAddress, slot, dutyType, signature, nodeId, lockToken } = params;
|
|
148
|
+
const { rollupAddress, validatorAddress, slot, dutyType, signature, nodeId, lockToken } = params;
|
|
153
149
|
const blockIndexWithinCheckpoint = getBlockIndexFromDutyIdentifier(params);
|
|
154
150
|
|
|
155
151
|
const success = await this.db.updateDutySigned(
|
|
152
|
+
rollupAddress,
|
|
156
153
|
validatorAddress,
|
|
157
154
|
slot,
|
|
158
155
|
dutyType,
|
|
@@ -184,10 +181,17 @@ export class SlashingProtectionService {
|
|
|
184
181
|
* @returns true if the delete succeeded, false if token didn't match
|
|
185
182
|
*/
|
|
186
183
|
async deleteDuty(params: DeleteDutyParams): Promise<boolean> {
|
|
187
|
-
const { validatorAddress, slot, dutyType, lockToken } = params;
|
|
184
|
+
const { rollupAddress, validatorAddress, slot, dutyType, lockToken } = params;
|
|
188
185
|
const blockIndexWithinCheckpoint = getBlockIndexFromDutyIdentifier(params);
|
|
189
186
|
|
|
190
|
-
const success = await this.db.deleteDuty(
|
|
187
|
+
const success = await this.db.deleteDuty(
|
|
188
|
+
rollupAddress,
|
|
189
|
+
validatorAddress,
|
|
190
|
+
slot,
|
|
191
|
+
dutyType,
|
|
192
|
+
lockToken,
|
|
193
|
+
blockIndexWithinCheckpoint,
|
|
194
|
+
);
|
|
191
195
|
|
|
192
196
|
if (success) {
|
|
193
197
|
this.log.info(`Deleted duty ${dutyType} at slot ${slot} to allow retry`, {
|
|
@@ -213,7 +217,19 @@ export class SlashingProtectionService {
|
|
|
213
217
|
* Start running tasks.
|
|
214
218
|
* Cleanup runs immediately on start to recover from any previous crashes.
|
|
215
219
|
*/
|
|
216
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Start the background cleanup task.
|
|
222
|
+
* Also performs one-time cleanup of duties with outdated rollup addresses.
|
|
223
|
+
*/
|
|
224
|
+
async start() {
|
|
225
|
+
// One-time cleanup at startup: remove duties from previous rollup versions
|
|
226
|
+
const numOutdatedRollupDuties = await this.db.cleanupOutdatedRollupDuties(this.config.l1Contracts.rollupAddress);
|
|
227
|
+
if (numOutdatedRollupDuties > 0) {
|
|
228
|
+
this.log.info(`Cleaned up ${numOutdatedRollupDuties} duties with outdated rollup address at startup`, {
|
|
229
|
+
currentRollupAddress: this.config.l1Contracts.rollupAddress.toString(),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
217
233
|
this.cleanupRunningPromise.start();
|
|
218
234
|
this.log.info('Slashing protection service started', { nodeId: this.config.nodeId });
|
|
219
235
|
}
|
|
@@ -236,15 +252,36 @@ export class SlashingProtectionService {
|
|
|
236
252
|
}
|
|
237
253
|
|
|
238
254
|
/**
|
|
239
|
-
*
|
|
255
|
+
* Periodic cleanup of stuck duties and optionally old signed duties.
|
|
256
|
+
* Runs in the background via RunningPromise.
|
|
240
257
|
*/
|
|
241
|
-
private async
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
258
|
+
private async cleanup() {
|
|
259
|
+
// 1. Clean up stuck duties (our own node's duties that got stuck in 'signing' status)
|
|
260
|
+
const numStuckDuties = await this.db.cleanupOwnStuckDuties(this.config.nodeId, this.maxStuckDutiesAgeMs);
|
|
261
|
+
if (numStuckDuties > 0) {
|
|
262
|
+
this.log.verbose(`Cleaned up ${numStuckDuties} stuck duties`, {
|
|
245
263
|
nodeId: this.config.nodeId,
|
|
246
264
|
maxStuckDutiesAgeMs: this.maxStuckDutiesAgeMs,
|
|
247
265
|
});
|
|
248
266
|
}
|
|
267
|
+
|
|
268
|
+
// 2. Clean up old signed duties if configured
|
|
269
|
+
// we shouldn't run this as often as stuck duty cleanup.
|
|
270
|
+
if (this.config.cleanupOldDutiesAfterHours !== undefined) {
|
|
271
|
+
const maxAgeMs = this.config.cleanupOldDutiesAfterHours * 60 * 60 * 1000;
|
|
272
|
+
const nowMs = Date.now();
|
|
273
|
+
const shouldRun =
|
|
274
|
+
this.lastOldDutiesCleanupAtMs === undefined || nowMs - this.lastOldDutiesCleanupAtMs >= maxAgeMs;
|
|
275
|
+
if (shouldRun) {
|
|
276
|
+
const numOldDuties = await this.db.cleanupOldDuties(maxAgeMs);
|
|
277
|
+
this.lastOldDutiesCleanupAtMs = nowMs;
|
|
278
|
+
if (numOldDuties > 0) {
|
|
279
|
+
this.log.verbose(`Cleaned up ${numOldDuties} old signed duties`, {
|
|
280
|
+
cleanupOldDutiesAfterHours: this.config.cleanupOldDutiesAfterHours,
|
|
281
|
+
maxAgeMs,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
249
286
|
}
|
|
250
287
|
}
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type CheckAndRecordParams,
|
|
15
15
|
type DeleteDutyParams,
|
|
16
16
|
type DutyIdentifier,
|
|
17
|
+
type DutyRow,
|
|
17
18
|
DutyType,
|
|
18
19
|
type OtherDutyIdentifier,
|
|
19
20
|
type RecordSuccessParams,
|
|
@@ -25,6 +26,7 @@ export type {
|
|
|
25
26
|
CheckAndRecordParams,
|
|
26
27
|
DeleteDutyParams,
|
|
27
28
|
DutyIdentifier,
|
|
29
|
+
DutyRow,
|
|
28
30
|
OtherDutyIdentifier,
|
|
29
31
|
RecordSuccessParams,
|
|
30
32
|
ValidatorDutyRecord,
|
|
@@ -170,6 +172,7 @@ export interface SlashingProtectionDatabase {
|
|
|
170
172
|
* @returns true if the update succeeded, false if token didn't match or duty not found
|
|
171
173
|
*/
|
|
172
174
|
updateDutySigned(
|
|
175
|
+
rollupAddress: EthAddress,
|
|
173
176
|
validatorAddress: EthAddress,
|
|
174
177
|
slot: SlotNumber,
|
|
175
178
|
dutyType: DutyType,
|
|
@@ -186,6 +189,7 @@ export interface SlashingProtectionDatabase {
|
|
|
186
189
|
* @returns true if the delete succeeded, false if token didn't match or duty not found
|
|
187
190
|
*/
|
|
188
191
|
deleteDuty(
|
|
192
|
+
rollupAddress: EthAddress,
|
|
189
193
|
validatorAddress: EthAddress,
|
|
190
194
|
slot: SlotNumber,
|
|
191
195
|
dutyType: DutyType,
|
|
@@ -199,6 +203,21 @@ export interface SlashingProtectionDatabase {
|
|
|
199
203
|
*/
|
|
200
204
|
cleanupOwnStuckDuties(nodeId: string, maxAgeMs: number): Promise<number>;
|
|
201
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Cleanup duties with outdated rollup address.
|
|
208
|
+
* Removes all duties where the rollup address doesn't match the current one.
|
|
209
|
+
* Used after a rollup upgrade to clean up duties for the old rollup.
|
|
210
|
+
* @returns the number of duties cleaned up
|
|
211
|
+
*/
|
|
212
|
+
cleanupOutdatedRollupDuties(currentRollupAddress: EthAddress): Promise<number>;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Cleanup old signed duties.
|
|
216
|
+
* Removes only signed duties older than the specified age.
|
|
217
|
+
* @returns the number of duties cleaned up
|
|
218
|
+
*/
|
|
219
|
+
cleanupOldDuties(maxAgeMs: number): Promise<number>;
|
|
220
|
+
|
|
202
221
|
/**
|
|
203
222
|
* Close the database connection.
|
|
204
223
|
* Should be called during graceful shutdown.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* node will sign for a given duty (slot + duty type).
|
|
7
7
|
*/
|
|
8
8
|
import type { Buffer32 } from '@aztec/foundation/buffer';
|
|
9
|
-
import
|
|
9
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
10
10
|
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
11
11
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
12
12
|
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
export class ValidatorHASigner {
|
|
42
42
|
private readonly log: Logger;
|
|
43
43
|
private readonly slashingProtection: SlashingProtectionService;
|
|
44
|
+
private readonly rollupAddress: EthAddress;
|
|
44
45
|
|
|
45
46
|
constructor(
|
|
46
47
|
db: SlashingProtectionDatabase,
|
|
@@ -56,9 +57,11 @@ export class ValidatorHASigner {
|
|
|
56
57
|
if (!config.nodeId || config.nodeId === '') {
|
|
57
58
|
throw new Error('NODE_ID is required for high-availability setups');
|
|
58
59
|
}
|
|
60
|
+
this.rollupAddress = config.l1Contracts.rollupAddress;
|
|
59
61
|
this.slashingProtection = new SlashingProtectionService(db, config);
|
|
60
62
|
this.log.info('Validator HA Signer initialized with slashing protection', {
|
|
61
63
|
nodeId: config.nodeId,
|
|
64
|
+
rollupAddress: this.rollupAddress.toString(),
|
|
62
65
|
});
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -88,6 +91,7 @@ export class ValidatorHASigner {
|
|
|
88
91
|
let dutyIdentifier: DutyIdentifier;
|
|
89
92
|
if (context.dutyType === DutyType.BLOCK_PROPOSAL) {
|
|
90
93
|
dutyIdentifier = {
|
|
94
|
+
rollupAddress: this.rollupAddress,
|
|
91
95
|
validatorAddress,
|
|
92
96
|
slot: context.slot,
|
|
93
97
|
blockIndexWithinCheckpoint: context.blockIndexWithinCheckpoint,
|
|
@@ -95,6 +99,7 @@ export class ValidatorHASigner {
|
|
|
95
99
|
};
|
|
96
100
|
} else {
|
|
97
101
|
dutyIdentifier = {
|
|
102
|
+
rollupAddress: this.rollupAddress,
|
|
98
103
|
validatorAddress,
|
|
99
104
|
slot: context.slot,
|
|
100
105
|
dutyType: context.dutyType,
|
|
@@ -142,8 +147,8 @@ export class ValidatorHASigner {
|
|
|
142
147
|
* Start the HA signer background tasks (cleanup of stuck duties).
|
|
143
148
|
* Should be called after construction and before signing operations.
|
|
144
149
|
*/
|
|
145
|
-
start() {
|
|
146
|
-
this.slashingProtection.start();
|
|
150
|
+
async start() {
|
|
151
|
+
await this.slashingProtection.start();
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
/**
|