@aztec/validator-ha-signer 0.0.1-commit.f504929 → 0.0.1-commit.f5a9928
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 +2 -4
- package/dest/db/index.d.ts +2 -1
- package/dest/db/index.d.ts.map +1 -1
- package/dest/db/index.js +1 -0
- package/dest/db/lmdb.d.ts +70 -0
- package/dest/db/lmdb.d.ts.map +1 -0
- package/dest/db/lmdb.js +223 -0
- package/dest/db/migrations/1_initial-schema.d.ts +4 -2
- package/dest/db/migrations/1_initial-schema.d.ts.map +1 -1
- package/dest/db/migrations/1_initial-schema.js +34 -4
- package/dest/db/migrations/2_add-checkpoint-number.d.ts +7 -0
- package/dest/db/migrations/2_add-checkpoint-number.d.ts.map +1 -0
- package/dest/db/migrations/2_add-checkpoint-number.js +17 -0
- package/dest/db/postgres.d.ts +4 -2
- package/dest/db/postgres.d.ts.map +1 -1
- package/dest/db/postgres.js +15 -13
- package/dest/db/schema.d.ts +6 -6
- package/dest/db/schema.d.ts.map +1 -1
- package/dest/db/schema.js +9 -4
- package/dest/db/types.d.ts +44 -7
- package/dest/db/types.d.ts.map +1 -1
- package/dest/db/types.js +26 -0
- package/dest/errors.d.ts +14 -1
- package/dest/errors.d.ts.map +1 -1
- package/dest/errors.js +15 -0
- package/dest/factory.d.ts +38 -5
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +95 -9
- package/dest/slashing_protection_service.d.ts +6 -4
- package/dest/slashing_protection_service.d.ts.map +1 -1
- package/dest/slashing_protection_service.js +14 -11
- package/dest/types.d.ts +8 -3
- package/dest/types.d.ts.map +1 -1
- package/dest/types.js +2 -1
- package/dest/validator_ha_signer.d.ts +5 -4
- package/dest/validator_ha_signer.d.ts.map +1 -1
- package/dest/validator_ha_signer.js +33 -12
- package/package.json +9 -7
- package/src/db/index.ts +1 -0
- package/src/db/lmdb.ts +308 -0
- package/src/db/migrations/1_initial-schema.ts +35 -4
- package/src/db/migrations/2_add-checkpoint-number.ts +19 -0
- package/src/db/postgres.ts +15 -11
- package/src/db/schema.ts +9 -4
- package/src/db/types.ts +63 -6
- package/src/errors.ts +21 -0
- package/src/factory.ts +130 -7
- package/src/slashing_protection_service.ts +18 -13
- package/src/types.ts +11 -0
- package/src/validator_ha_signer.ts +48 -13
package/dest/db/schema.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* slot, and duty type combination.
|
|
7
7
|
*/ /**
|
|
8
8
|
* Current schema version
|
|
9
|
-
*/ export const SCHEMA_VERSION =
|
|
9
|
+
*/ export const SCHEMA_VERSION = 2;
|
|
10
10
|
/**
|
|
11
11
|
* SQL to create the validator_duties table
|
|
12
12
|
*/ export const CREATE_VALIDATOR_DUTIES_TABLE = `
|
|
@@ -15,6 +15,7 @@ CREATE TABLE IF NOT EXISTS validator_duties (
|
|
|
15
15
|
validator_address VARCHAR(42) NOT NULL,
|
|
16
16
|
slot BIGINT NOT NULL,
|
|
17
17
|
block_number BIGINT NOT NULL,
|
|
18
|
+
checkpoint_number BIGINT NOT NULL DEFAULT 0,
|
|
18
19
|
block_index_within_checkpoint INTEGER NOT NULL DEFAULT 0,
|
|
19
20
|
duty_type VARCHAR(30) NOT NULL CHECK (duty_type IN ('BLOCK_PROPOSAL', 'CHECKPOINT_PROPOSAL', 'ATTESTATION', 'ATTESTATIONS_AND_SIGNERS', 'GOVERNANCE_VOTE', 'SLASHING_VOTE')),
|
|
20
21
|
status VARCHAR(20) NOT NULL CHECK (status IN ('signing', 'signed')),
|
|
@@ -87,6 +88,7 @@ WITH inserted AS (
|
|
|
87
88
|
validator_address,
|
|
88
89
|
slot,
|
|
89
90
|
block_number,
|
|
91
|
+
checkpoint_number,
|
|
90
92
|
block_index_within_checkpoint,
|
|
91
93
|
duty_type,
|
|
92
94
|
status,
|
|
@@ -94,13 +96,14 @@ WITH inserted AS (
|
|
|
94
96
|
node_id,
|
|
95
97
|
lock_token,
|
|
96
98
|
started_at
|
|
97
|
-
) VALUES ($1, $2, $3, $4, $5, $6, 'signing', $
|
|
99
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, 'signing', $8, $9, $10, CURRENT_TIMESTAMP)
|
|
98
100
|
ON CONFLICT (rollup_address, validator_address, slot, duty_type, block_index_within_checkpoint) DO NOTHING
|
|
99
101
|
RETURNING
|
|
100
102
|
rollup_address,
|
|
101
103
|
validator_address,
|
|
102
104
|
slot,
|
|
103
105
|
block_number,
|
|
106
|
+
checkpoint_number,
|
|
104
107
|
block_index_within_checkpoint,
|
|
105
108
|
duty_type,
|
|
106
109
|
status,
|
|
@@ -120,6 +123,7 @@ SELECT
|
|
|
120
123
|
validator_address,
|
|
121
124
|
slot,
|
|
122
125
|
block_number,
|
|
126
|
+
checkpoint_number,
|
|
123
127
|
block_index_within_checkpoint,
|
|
124
128
|
duty_type,
|
|
125
129
|
status,
|
|
@@ -135,8 +139,8 @@ FROM validator_duties
|
|
|
135
139
|
WHERE rollup_address = $1
|
|
136
140
|
AND validator_address = $2
|
|
137
141
|
AND slot = $3
|
|
138
|
-
AND duty_type = $
|
|
139
|
-
AND block_index_within_checkpoint = $
|
|
142
|
+
AND duty_type = $7
|
|
143
|
+
AND block_index_within_checkpoint = $6
|
|
140
144
|
AND NOT EXISTS (SELECT 1 FROM inserted);
|
|
141
145
|
`;
|
|
142
146
|
/**
|
|
@@ -216,6 +220,7 @@ SELECT
|
|
|
216
220
|
validator_address,
|
|
217
221
|
slot,
|
|
218
222
|
block_number,
|
|
223
|
+
checkpoint_number,
|
|
219
224
|
block_index_within_checkpoint,
|
|
220
225
|
duty_type,
|
|
221
226
|
status,
|
package/dest/db/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { BlockNumber, CheckpointNumber, type IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
4
4
|
import { DutyType } from '@aztec/stdlib/ha-signing';
|
|
5
5
|
/**
|
|
@@ -10,6 +10,7 @@ export interface DutyRow {
|
|
|
10
10
|
validator_address: string;
|
|
11
11
|
slot: string;
|
|
12
12
|
block_number: string;
|
|
13
|
+
checkpoint_number: string;
|
|
13
14
|
block_index_within_checkpoint: number;
|
|
14
15
|
duty_type: DutyType;
|
|
15
16
|
status: DutyStatus;
|
|
@@ -21,6 +22,30 @@ export interface DutyRow {
|
|
|
21
22
|
completed_at: Date | null;
|
|
22
23
|
error_message: string | null;
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Plain-primitive representation of a duty record suitable for serialization
|
|
27
|
+
* (e.g. msgpackr for LMDB). All domain types are stored as their string/number
|
|
28
|
+
* equivalents. Timestamps are Unix milliseconds.
|
|
29
|
+
*/
|
|
30
|
+
export interface StoredDutyRecord {
|
|
31
|
+
rollupAddress: string;
|
|
32
|
+
validatorAddress: string;
|
|
33
|
+
slot: string;
|
|
34
|
+
blockNumber: string;
|
|
35
|
+
checkpointNumber: string;
|
|
36
|
+
blockIndexWithinCheckpoint: number;
|
|
37
|
+
dutyType: DutyType;
|
|
38
|
+
status: DutyStatus;
|
|
39
|
+
messageHash: string;
|
|
40
|
+
signature?: string;
|
|
41
|
+
nodeId: string;
|
|
42
|
+
lockToken: string;
|
|
43
|
+
/** Unix timestamp in milliseconds when signing started */
|
|
44
|
+
startedAtMs: number;
|
|
45
|
+
/** Unix timestamp in milliseconds when signing completed */
|
|
46
|
+
completedAtMs?: number;
|
|
47
|
+
errorMessage?: string;
|
|
48
|
+
}
|
|
24
49
|
/**
|
|
25
50
|
* Row type from INSERT_OR_GET_DUTY query (includes is_new flag)
|
|
26
51
|
*/
|
|
@@ -36,7 +61,8 @@ export declare enum DutyStatus {
|
|
|
36
61
|
}
|
|
37
62
|
export { DutyType };
|
|
38
63
|
/**
|
|
39
|
-
*
|
|
64
|
+
* Rich representation of a validator duty, with branded types and Date objects.
|
|
65
|
+
* This is the common output type returned by all SlashingProtectionDatabase implementations.
|
|
40
66
|
*/
|
|
41
67
|
export interface ValidatorDutyRecord {
|
|
42
68
|
/** Ethereum address of the rollup contract */
|
|
@@ -45,8 +71,10 @@ export interface ValidatorDutyRecord {
|
|
|
45
71
|
validatorAddress: EthAddress;
|
|
46
72
|
/** Slot number for this duty */
|
|
47
73
|
slot: SlotNumber;
|
|
48
|
-
/** Block number for this duty */
|
|
74
|
+
/** Block number for this duty (0 for non-block-proposal duties) */
|
|
49
75
|
blockNumber: BlockNumber;
|
|
76
|
+
/** Checkpoint number for this duty (0 for attestation and vote duties) */
|
|
77
|
+
checkpointNumber: CheckpointNumber;
|
|
50
78
|
/** Block index within checkpoint (0, 1, 2... for block proposals, -1 for other duty types) */
|
|
51
79
|
blockIndexWithinCheckpoint: number;
|
|
52
80
|
/** Type of duty being performed */
|
|
@@ -68,6 +96,13 @@ export interface ValidatorDutyRecord {
|
|
|
68
96
|
/** Error message (currently unused) */
|
|
69
97
|
errorMessage?: string;
|
|
70
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Convert a {@link StoredDutyRecord} (plain-primitive wire format) to a
|
|
101
|
+
* {@link ValidatorDutyRecord} (rich domain type).
|
|
102
|
+
*
|
|
103
|
+
* Shared by LMDB and any future non-Postgres backend implementations.
|
|
104
|
+
*/
|
|
105
|
+
export declare function recordFromFields(stored: StoredDutyRecord): ValidatorDutyRecord;
|
|
71
106
|
/**
|
|
72
107
|
* Duty identifier for block proposals.
|
|
73
108
|
* blockIndexWithinCheckpoint is REQUIRED and must be >= 0.
|
|
@@ -115,8 +150,10 @@ export declare function getBlockIndexFromDutyIdentifier(duty: DutyIdentifier): n
|
|
|
115
150
|
* Additional parameters for checking and recording a new duty
|
|
116
151
|
*/
|
|
117
152
|
interface CheckAndRecordExtra {
|
|
118
|
-
/** Block number for this duty */
|
|
119
|
-
blockNumber: BlockNumber
|
|
153
|
+
/** Block number for this duty (0 for non-block-proposal duties) */
|
|
154
|
+
blockNumber: BlockNumber;
|
|
155
|
+
/** Checkpoint number for this duty (0 for attestation and vote duties) */
|
|
156
|
+
checkpointNumber: CheckpointNumber;
|
|
120
157
|
/** The signing root (hash) for this duty */
|
|
121
158
|
messageHash: string;
|
|
122
159
|
/** Identifier for the node that acquired the lock */
|
|
@@ -151,4 +188,4 @@ interface DeleteDutyExtra {
|
|
|
151
188
|
* Uses intersection with DutyIdentifier to preserve the discriminated union.
|
|
152
189
|
*/
|
|
153
190
|
export type DeleteDutyParams = DutyIdentifier & DeleteDutyExtra;
|
|
154
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
191
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYi90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLEtBQUsscUJBQXFCLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDeEgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzNELE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUVwRDs7R0FFRztBQUNILE1BQU0sV0FBVyxPQUFPO0lBQ3RCLGNBQWMsRUFBRSxNQUFNLENBQUM7SUFDdkIsaUJBQWlCLEVBQUUsTUFBTSxDQUFDO0lBQzFCLElBQUksRUFBRSxNQUFNLENBQUM7SUFDYixZQUFZLEVBQUUsTUFBTSxDQUFDO0lBQ3JCLGlCQUFpQixFQUFFLE1BQU0sQ0FBQztJQUMxQiw2QkFBNkIsRUFBRSxNQUFNLENBQUM7SUFDdEMsU0FBUyxFQUFFLFFBQVEsQ0FBQztJQUNwQixNQUFNLEVBQUUsVUFBVSxDQUFDO0lBQ25CLFlBQVksRUFBRSxNQUFNLENBQUM7SUFDckIsU0FBUyxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUM7SUFDekIsT0FBTyxFQUFFLE1BQU0sQ0FBQztJQUNoQixVQUFVLEVBQUUsTUFBTSxDQUFDO0lBQ25CLFVBQVUsRUFBRSxJQUFJLENBQUM7SUFDakIsWUFBWSxFQUFFLElBQUksR0FBRyxJQUFJLENBQUM7SUFDMUIsYUFBYSxFQUFFLE1BQU0sR0FBRyxJQUFJLENBQUM7Q0FDOUI7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxXQUFXLGdCQUFnQjtJQUMvQixhQUFhLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztJQUN6QixJQUFJLEVBQUUsTUFBTSxDQUFD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
|
package/dest/db/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":"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"}
|
package/dest/db/types.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
1
3
|
import { DutyType } from '@aztec/stdlib/ha-signing';
|
|
2
4
|
/**
|
|
3
5
|
* Status of a duty in the database
|
|
@@ -8,6 +10,30 @@ import { DutyType } from '@aztec/stdlib/ha-signing';
|
|
|
8
10
|
}({});
|
|
9
11
|
// Re-export DutyType from stdlib
|
|
10
12
|
export { DutyType };
|
|
13
|
+
/**
|
|
14
|
+
* Convert a {@link StoredDutyRecord} (plain-primitive wire format) to a
|
|
15
|
+
* {@link ValidatorDutyRecord} (rich domain type).
|
|
16
|
+
*
|
|
17
|
+
* Shared by LMDB and any future non-Postgres backend implementations.
|
|
18
|
+
*/ export function recordFromFields(stored) {
|
|
19
|
+
return {
|
|
20
|
+
rollupAddress: EthAddress.fromString(stored.rollupAddress),
|
|
21
|
+
validatorAddress: EthAddress.fromString(stored.validatorAddress),
|
|
22
|
+
slot: SlotNumber.fromString(stored.slot),
|
|
23
|
+
blockNumber: BlockNumber.fromString(stored.blockNumber),
|
|
24
|
+
checkpointNumber: CheckpointNumber.fromString(stored.checkpointNumber),
|
|
25
|
+
blockIndexWithinCheckpoint: stored.blockIndexWithinCheckpoint,
|
|
26
|
+
dutyType: stored.dutyType,
|
|
27
|
+
status: stored.status,
|
|
28
|
+
messageHash: stored.messageHash,
|
|
29
|
+
signature: stored.signature,
|
|
30
|
+
nodeId: stored.nodeId,
|
|
31
|
+
lockToken: stored.lockToken,
|
|
32
|
+
startedAt: new Date(stored.startedAtMs),
|
|
33
|
+
completedAt: stored.completedAtMs !== undefined ? new Date(stored.completedAtMs) : undefined,
|
|
34
|
+
errorMessage: stored.errorMessage
|
|
35
|
+
};
|
|
36
|
+
}
|
|
11
37
|
/**
|
|
12
38
|
* Validates and normalizes the block index for a duty.
|
|
13
39
|
* - BLOCK_PROPOSAL: validates blockIndexWithinCheckpoint is provided and >= 0
|
package/dest/errors.d.ts
CHANGED
|
@@ -15,6 +15,19 @@ export declare class DutyAlreadySignedError extends Error {
|
|
|
15
15
|
readonly signedByNode: string;
|
|
16
16
|
constructor(slot: SlotNumber, dutyType: DutyType, blockIndexWithinCheckpoint: number, signedByNode: string);
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Thrown when the slashing-protection record for an in-flight signing operation can no longer be
|
|
20
|
+
* updated because it is no longer owned by this node - for example, the stuck-duty cleanup loop
|
|
21
|
+
* deleted the SIGNING row while the remote signer was slow. The produced signature must be
|
|
22
|
+
* discarded rather than broadcast: with no protection record in place, a later attempt for the
|
|
23
|
+
* same duty with different data would sign freely, which is slashable equivocation.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SigningLockLostError extends Error {
|
|
26
|
+
readonly slot: SlotNumber;
|
|
27
|
+
readonly dutyType: DutyType;
|
|
28
|
+
readonly nodeId: string;
|
|
29
|
+
constructor(slot: SlotNumber, dutyType: DutyType, nodeId: string);
|
|
30
|
+
}
|
|
18
31
|
/**
|
|
19
32
|
* Thrown when attempting to sign data that conflicts with an already-signed duty.
|
|
20
33
|
* This means the same validator tried to sign DIFFERENT data for the same slot.
|
|
@@ -31,4 +44,4 @@ export declare class SlashingProtectionError extends Error {
|
|
|
31
44
|
readonly signedByNode: string;
|
|
32
45
|
constructor(slot: SlotNumber, dutyType: DutyType, blockIndexWithinCheckpoint: number, existingMessageHash: string, attemptedMessageHash: string, signedByNode: string);
|
|
33
46
|
}
|
|
34
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZXJyb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFbEUsT0FBTyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTlDOzs7O0dBSUc7QUFDSCxxQkFBYSxzQkFBdUIsU0FBUSxLQUFLO2FBRTdCLElBQUksRUFBRSxVQUFVO2FBQ2hCLFFBQVEsRUFBRSxRQUFRO2FBQ2xCLDBCQUEwQixFQUFFLE1BQU07YUFDbEMsWUFBWSxFQUFFLE1BQU07SUFKdEMsWUFDa0IsSUFBSSxFQUFFLFVBQVUsRUFDaEIsUUFBUSxFQUFFLFFBQVEsRUFDbEIsMEJBQTBCLEVBQUUsTUFBTSxFQUNsQyxZQUFZLEVBQUUsTUFBTSxFQUlyQztDQUNGO0FBRUQ7Ozs7OztHQU1HO0FBQ0gscUJBQWEsb0JBQXFCLFNBQVEsS0FBSzthQUUzQixJQUFJLEVBQUUsVUFBVTthQUNoQixRQUFRLEVBQUUsUUFBUTthQUNsQixNQUFNLEVBQUUsTUFBTTtJQUhoQyxZQUNrQixJQUFJLEVBQUUsVUFBVSxFQUNoQixRQUFRLEVBQUUsUUFBUSxFQUNsQixNQUFNLEVBQUUsTUFBTSxFQU8vQjtDQUNGO0FBRUQ7Ozs7OztHQU1HO0FBQ0gscUJBQWEsdUJBQXdCLFNBQVEsS0FBSzthQUU5QixJQUFJLEVBQUUsVUFBVTthQUNoQixRQUFRLEVBQUUsUUFBUTthQUNsQiwwQkFBMEIsRUFBRSxNQUFNO2FBQ2xDLG1CQUFtQixFQUFFLE1BQU07YUFDM0Isb0JBQW9CLEVBQUUsTUFBTTthQUM1QixZQUFZLEVBQUUsTUFBTTtJQU50QyxZQUNrQixJQUFJLEVBQUUsVUFBVSxFQUNoQixRQUFRLEVBQUUsUUFBUSxFQUNsQiwwQkFBMEIsRUFBRSxNQUFNLEVBQ2xDLG1CQUFtQixFQUFFLE1BQU0sRUFDM0Isb0JBQW9CLEVBQUUsTUFBTSxFQUM1QixZQUFZLEVBQUUsTUFBTSxFQU9yQztDQUNGIn0=
|
package/dest/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,IAAI,EAAE,UAAU;aAChB,QAAQ,EAAE,QAAQ;aAClB,0BAA0B,EAAE,MAAM;aAClC,YAAY,EAAE,MAAM;IAJtC,YACkB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,0BAA0B,EAAE,MAAM,EAClC,YAAY,EAAE,MAAM,EAIrC;CACF;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aAE9B,IAAI,EAAE,UAAU;aAChB,QAAQ,EAAE,QAAQ;aAClB,0BAA0B,EAAE,MAAM;aAClC,mBAAmB,EAAE,MAAM;aAC3B,oBAAoB,EAAE,MAAM;aAC5B,YAAY,EAAE,MAAM;IANtC,YACkB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,0BAA0B,EAAE,MAAM,EAClC,mBAAmB,EAAE,MAAM,EAC3B,oBAAoB,EAAE,MAAM,EAC5B,YAAY,EAAE,MAAM,EAOrC;CACF"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,IAAI,EAAE,UAAU;aAChB,QAAQ,EAAE,QAAQ;aAClB,0BAA0B,EAAE,MAAM;aAClC,YAAY,EAAE,MAAM;IAJtC,YACkB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,0BAA0B,EAAE,MAAM,EAClC,YAAY,EAAE,MAAM,EAIrC;CACF;AAED;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,IAAI,EAAE,UAAU;aAChB,QAAQ,EAAE,QAAQ;aAClB,MAAM,EAAE,MAAM;IAHhC,YACkB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EAO/B;CACF;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aAE9B,IAAI,EAAE,UAAU;aAChB,QAAQ,EAAE,QAAQ;aAClB,0BAA0B,EAAE,MAAM;aAClC,mBAAmB,EAAE,MAAM;aAC3B,oBAAoB,EAAE,MAAM;aAC5B,YAAY,EAAE,MAAM;IANtC,YACkB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,0BAA0B,EAAE,MAAM,EAClC,mBAAmB,EAAE,MAAM,EAC3B,oBAAoB,EAAE,MAAM,EAC5B,YAAY,EAAE,MAAM,EAOrC;CACF"}
|
package/dest/errors.js
CHANGED
|
@@ -14,6 +14,21 @@
|
|
|
14
14
|
this.name = 'DutyAlreadySignedError';
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Thrown when the slashing-protection record for an in-flight signing operation can no longer be
|
|
19
|
+
* updated because it is no longer owned by this node - for example, the stuck-duty cleanup loop
|
|
20
|
+
* deleted the SIGNING row while the remote signer was slow. The produced signature must be
|
|
21
|
+
* discarded rather than broadcast: with no protection record in place, a later attempt for the
|
|
22
|
+
* same duty with different data would sign freely, which is slashable equivocation.
|
|
23
|
+
*/ export class SigningLockLostError extends Error {
|
|
24
|
+
slot;
|
|
25
|
+
dutyType;
|
|
26
|
+
nodeId;
|
|
27
|
+
constructor(slot, dutyType, nodeId){
|
|
28
|
+
super(`Slashing protection record for ${dutyType} at slot ${slot} was lost before signing completed ` + `(node ${nodeId}); discarding signature`), this.slot = slot, this.dutyType = dutyType, this.nodeId = nodeId;
|
|
29
|
+
this.name = 'SigningLockLostError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
17
32
|
/**
|
|
18
33
|
* Thrown when attempting to sign data that conflicts with an already-signed duty.
|
|
19
34
|
* This means the same validator tried to sign DIFFERENT data for the same slot.
|
package/dest/factory.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
1
|
+
import { DateProvider } from '@aztec/foundation/timer';
|
|
2
|
+
import type { LocalSignerConfig, ValidatorHASignerConfig } from '@aztec/stdlib/ha-signing';
|
|
3
|
+
import type { CreateHASignerDeps, CreateLocalSignerWithProtectionDeps, SlashingProtectionDatabase } from './types.js';
|
|
3
4
|
import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
4
5
|
/**
|
|
5
6
|
* Create a validator HA signer with PostgreSQL backend
|
|
@@ -16,10 +17,9 @@ import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
|
16
17
|
* ```typescript
|
|
17
18
|
* const { signer, db } = await createHASigner({
|
|
18
19
|
* databaseUrl: process.env.DATABASE_URL,
|
|
19
|
-
* haSigningEnabled: true,
|
|
20
20
|
* nodeId: 'validator-node-1',
|
|
21
21
|
* pollingIntervalMs: 100,
|
|
22
|
-
*
|
|
22
|
+
* peerSigningTimeoutMs: 3000,
|
|
23
23
|
* });
|
|
24
24
|
* signer.start(); // Start background cleanup
|
|
25
25
|
*
|
|
@@ -39,4 +39,37 @@ export declare function createHASigner(config: ValidatorHASignerConfig, deps?: C
|
|
|
39
39
|
signer: ValidatorHASigner;
|
|
40
40
|
db: SlashingProtectionDatabase;
|
|
41
41
|
}>;
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Create a local (single-node) signing protection signer backed by LMDB.
|
|
44
|
+
*
|
|
45
|
+
* This provides double-signing protection for nodes that are NOT running in a
|
|
46
|
+
* high-availability (multi-node) setup. It prevents a proposer from sending two
|
|
47
|
+
* proposals for the same slot if the node crashes and restarts mid-proposal.
|
|
48
|
+
*
|
|
49
|
+
* `config.dataDirectory` is required so the protection database is persisted to disk and survives
|
|
50
|
+
* crashes/restarts. Booting without it throws, since an ephemeral store silently drops all
|
|
51
|
+
* double-signing protection across restarts. Set `config.allowEphemeralSigningProtection` to opt
|
|
52
|
+
* into the ephemeral store anyway (dev/test networks only) — a loud warning is logged in that case.
|
|
53
|
+
*
|
|
54
|
+
* @param config - Local signer config
|
|
55
|
+
* @param deps - Optional dependencies (telemetry, date provider).
|
|
56
|
+
* @returns An object containing the signer and database instances.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createLocalSignerWithProtection(config: LocalSignerConfig, deps?: CreateLocalSignerWithProtectionDeps): Promise<{
|
|
59
|
+
signer: ValidatorHASigner;
|
|
60
|
+
db: SlashingProtectionDatabase;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Create an in-memory LMDB-backed SlashingProtectionDatabase that can be shared across
|
|
64
|
+
* multiple validator nodes in the same process. Used for testing HA setups.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createSharedSlashingProtectionDb(dateProvider?: DateProvider): Promise<SlashingProtectionDatabase>;
|
|
67
|
+
/**
|
|
68
|
+
* Create a ValidatorHASigner backed by a pre-existing SlashingProtectionDatabase.
|
|
69
|
+
* Used for testing HA setups where multiple nodes share the same protection database.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createSignerFromSharedDb(db: SlashingProtectionDatabase, config: Pick<ValidatorHASignerConfig, 'nodeId' | 'pollingIntervalMs' | 'peerSigningTimeoutMs' | 'maxStuckDutiesAgeMs' | 'rollupAddress'>, deps?: CreateLocalSignerWithProtectionDeps): {
|
|
72
|
+
signer: ValidatorHASigner;
|
|
73
|
+
db: SlashingProtectionDatabase;
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXZELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFRM0YsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsbUNBQW1DLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDdEgsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFN0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBZ0NHO0FBQ0gsd0JBQXNCLGNBQWMsQ0FDbEMsTUFBTSxFQUFFLHVCQUF1QixFQUMvQixJQUFJLENBQUMsRUFBRSxrQkFBa0IsR0FDeEIsT0FBTyxDQUFDO0lBQ1QsTUFBTSxFQUFFLGlCQUFpQixDQUFDO0lBQzFCLEVBQUUsRUFBRSwwQkFBMEIsQ0FBQztDQUNoQyxDQUFDLENBaUREO0FBRUQ7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsd0JBQXNCLCtCQUErQixDQUNuRCxNQUFNLEVBQUUsaUJBQWlCLEVBQ3pCLElBQUksQ0FBQyxFQUFFLG1DQUFtQyxHQUN6QyxPQUFPLENBQUM7SUFDVCxNQUFNLEVBQUUsaUJBQWlCLENBQUM7SUFDMUIsRUFBRSxFQUFFLDBCQUEwQixDQUFDO0NBQ2hDLENBQUMsQ0FzREQ7QUFFRDs7O0dBR0c7QUFDSCx3QkFBc0IsZ0NBQWdDLENBQ3BELFlBQVksR0FBRSxZQUFpQyxHQUM5QyxPQUFPLENBQUMsMEJBQTBCLENBQUMsQ0FLckM7QUFFRDs7O0dBR0c7QUFDSCx3QkFBZ0Isd0JBQXdCLENBQ3RDLEVBQUUsRUFBRSwwQkFBMEIsRUFDOUIsTUFBTSxFQUFFLElBQUksQ0FDVix1QkFBdUIsRUFDdkIsUUFBUSxHQUFHLG1CQUFtQixHQUFHLHNCQUFzQixHQUFHLHFCQUFxQixHQUFHLGVBQWUsQ0FDbEcsRUFDRCxJQUFJLENBQUMsRUFBRSxtQ0FBbUMsR0FDekM7SUFBRSxNQUFNLEVBQUUsaUJBQWlCLENBQUM7SUFBQyxFQUFFLEVBQUUsMEJBQTBCLENBQUE7Q0FBRSxDQU0vRCJ9
|
package/dest/factory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAQ3F,OAAO,KAAK,EAAE,kBAAkB,EAAE,mCAAmC,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,uBAAuB,EAC/B,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC;IACT,MAAM,EAAE,iBAAiB,CAAC;IAC1B,EAAE,EAAE,0BAA0B,CAAC;CAChC,CAAC,CAiDD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,iBAAiB,EACzB,IAAI,CAAC,EAAE,mCAAmC,GACzC,OAAO,CAAC;IACT,MAAM,EAAE,iBAAiB,CAAC;IAC1B,EAAE,EAAE,0BAA0B,CAAC;CAChC,CAAC,CAsDD;AAED;;;GAGG;AACH,wBAAsB,gCAAgC,CACpD,YAAY,GAAE,YAAiC,GAC9C,OAAO,CAAC,0BAA0B,CAAC,CAKrC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,0BAA0B,EAC9B,MAAM,EAAE,IAAI,CACV,uBAAuB,EACvB,QAAQ,GAAG,mBAAmB,GAAG,sBAAsB,GAAG,qBAAqB,GAAG,eAAe,CAClG,EACD,IAAI,CAAC,EAAE,mCAAmC,GACzC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,EAAE,EAAE,0BAA0B,CAAA;CAAE,CAM/D"}
|
package/dest/factory.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Factory functions for creating validator HA signers
|
|
3
|
-
*/ import {
|
|
3
|
+
*/ import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { DateProvider } from '@aztec/foundation/timer';
|
|
5
|
+
import { createStore } from '@aztec/kv-store/lmdb-v2';
|
|
4
6
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
5
7
|
import { Pool } from 'pg';
|
|
8
|
+
import { LmdbSlashingProtectionDatabase, migrateLmdbSlashingProtectionDatabase } from './db/lmdb.js';
|
|
6
9
|
import { PostgresSlashingProtectionDatabase } from './db/postgres.js';
|
|
7
10
|
import { HASignerMetrics } from './metrics.js';
|
|
8
11
|
import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
@@ -21,10 +24,9 @@ import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
|
21
24
|
* ```typescript
|
|
22
25
|
* const { signer, db } = await createHASigner({
|
|
23
26
|
* databaseUrl: process.env.DATABASE_URL,
|
|
24
|
-
* haSigningEnabled: true,
|
|
25
27
|
* nodeId: 'validator-node-1',
|
|
26
28
|
* pollingIntervalMs: 100,
|
|
27
|
-
*
|
|
29
|
+
* peerSigningTimeoutMs: 3000,
|
|
28
30
|
* });
|
|
29
31
|
* signer.start(); // Start background cleanup
|
|
30
32
|
*
|
|
@@ -41,7 +43,8 @@ import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
|
41
43
|
* @returns An object containing the signer and database instances
|
|
42
44
|
*/ export async function createHASigner(config, deps) {
|
|
43
45
|
const { databaseUrl, poolMaxCount, poolMinCount, poolIdleTimeoutMs, poolConnectionTimeoutMs, ...signerConfig } = config;
|
|
44
|
-
|
|
46
|
+
const databaseUrlValue = databaseUrl?.getValue();
|
|
47
|
+
if (!databaseUrlValue) {
|
|
45
48
|
throw new Error('databaseUrl is required for createHASigner');
|
|
46
49
|
}
|
|
47
50
|
const telemetryClient = deps?.telemetryClient ?? getTelemetryClient();
|
|
@@ -50,7 +53,7 @@ import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
|
50
53
|
let pool;
|
|
51
54
|
if (!deps?.pool) {
|
|
52
55
|
pool = new Pool({
|
|
53
|
-
connectionString:
|
|
56
|
+
connectionString: databaseUrlValue,
|
|
54
57
|
max: poolMaxCount ?? 10,
|
|
55
58
|
min: poolMinCount ?? 0,
|
|
56
59
|
idleTimeoutMillis: poolIdleTimeoutMs ?? 10_000,
|
|
@@ -59,6 +62,18 @@ import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
|
59
62
|
} else {
|
|
60
63
|
pool = deps.pool;
|
|
61
64
|
}
|
|
65
|
+
// pg re-emits idle-client errors (e.g. a Postgres restart severing an idle connection) on the
|
|
66
|
+
// pool. Without an 'error' listener, Node escalates these to an uncaughtException and crashes the
|
|
67
|
+
// process - taking down every HA replica sharing the DB at once. pg destroys and replaces the
|
|
68
|
+
// errored client itself, so logging is the only action needed. Log just message/code, never the
|
|
69
|
+
// raw error object (it can carry connection metadata).
|
|
70
|
+
const log = createLogger('validator-ha-signer:factory');
|
|
71
|
+
pool.on('error', (err)=>{
|
|
72
|
+
log.warn('Postgres pool error on idle client', {
|
|
73
|
+
message: err.message,
|
|
74
|
+
code: err.code
|
|
75
|
+
});
|
|
76
|
+
});
|
|
62
77
|
// Create database instance
|
|
63
78
|
const db = new PostgresSlashingProtectionDatabase(pool);
|
|
64
79
|
// Verify database schema is initialized and version matches
|
|
@@ -66,10 +81,81 @@ import { ValidatorHASigner } from './validator_ha_signer.js';
|
|
|
66
81
|
// Create metrics
|
|
67
82
|
const metrics = new HASignerMetrics(telemetryClient, signerConfig.nodeId);
|
|
68
83
|
// Create signer
|
|
69
|
-
const signer = new ValidatorHASigner(db, {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
84
|
+
const signer = new ValidatorHASigner(db, signerConfig, {
|
|
85
|
+
metrics,
|
|
86
|
+
dateProvider
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
signer,
|
|
90
|
+
db
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Create a local (single-node) signing protection signer backed by LMDB.
|
|
95
|
+
*
|
|
96
|
+
* This provides double-signing protection for nodes that are NOT running in a
|
|
97
|
+
* high-availability (multi-node) setup. It prevents a proposer from sending two
|
|
98
|
+
* proposals for the same slot if the node crashes and restarts mid-proposal.
|
|
99
|
+
*
|
|
100
|
+
* `config.dataDirectory` is required so the protection database is persisted to disk and survives
|
|
101
|
+
* crashes/restarts. Booting without it throws, since an ephemeral store silently drops all
|
|
102
|
+
* double-signing protection across restarts. Set `config.allowEphemeralSigningProtection` to opt
|
|
103
|
+
* into the ephemeral store anyway (dev/test networks only) — a loud warning is logged in that case.
|
|
104
|
+
*
|
|
105
|
+
* @param config - Local signer config
|
|
106
|
+
* @param deps - Optional dependencies (telemetry, date provider).
|
|
107
|
+
* @returns An object containing the signer and database instances.
|
|
108
|
+
*/ export async function createLocalSignerWithProtection(config, deps) {
|
|
109
|
+
const telemetryClient = deps?.telemetryClient ?? getTelemetryClient();
|
|
110
|
+
const dateProvider = deps?.dateProvider ?? new DateProvider();
|
|
111
|
+
const log = createLogger('validator-ha-signer:factory');
|
|
112
|
+
if (!config.dataDirectory) {
|
|
113
|
+
if (!config.allowEphemeralSigningProtection) {
|
|
114
|
+
throw new Error('Local signing protection requires a persistent data directory, but none was configured. ' + 'Set DATA_DIRECTORY so double-signing protection survives restarts, or explicitly opt into an ' + 'ephemeral store (dev/test only) with VALIDATOR_ALLOW_EPHEMERAL_SIGNING_PROTECTION=true.');
|
|
115
|
+
}
|
|
116
|
+
log.warn('Local signing protection is running with an EPHEMERAL store: no data directory is configured. ' + 'Double-signing protection will NOT survive a restart. This is unsafe for production validators.');
|
|
117
|
+
}
|
|
118
|
+
const kvStore = await createStore('signing-protection', LmdbSlashingProtectionDatabase.SCHEMA_VERSION, {
|
|
119
|
+
dataDirectory: config.dataDirectory,
|
|
120
|
+
dataStoreMapSizeKb: config.signingProtectionMapSizeKb ?? config.dataStoreMapSizeKb,
|
|
121
|
+
rollupAddress: config.rollupAddress
|
|
122
|
+
}, undefined, {
|
|
123
|
+
onUpgrade: (dataDirectory, currentVersion, latestVersion)=>migrateLmdbSlashingProtectionDatabase(dataDirectory, currentVersion, latestVersion, config.signingProtectionMapSizeKb ?? config.dataStoreMapSizeKb),
|
|
124
|
+
schemaVersionMismatchPolicy: 'throw',
|
|
125
|
+
versionFileReadFailurePolicy: 'throw'
|
|
126
|
+
});
|
|
127
|
+
const db = new LmdbSlashingProtectionDatabase(kvStore, dateProvider);
|
|
128
|
+
const signerConfig = {
|
|
129
|
+
...config,
|
|
130
|
+
nodeId: config.nodeId || 'local'
|
|
131
|
+
};
|
|
132
|
+
const metrics = new HASignerMetrics(telemetryClient, signerConfig.nodeId, 'LocalSigningProtectionMetrics');
|
|
133
|
+
const signer = new ValidatorHASigner(db, signerConfig, {
|
|
134
|
+
metrics,
|
|
135
|
+
dateProvider
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
signer,
|
|
139
|
+
db
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create an in-memory LMDB-backed SlashingProtectionDatabase that can be shared across
|
|
144
|
+
* multiple validator nodes in the same process. Used for testing HA setups.
|
|
145
|
+
*/ export async function createSharedSlashingProtectionDb(dateProvider = new DateProvider()) {
|
|
146
|
+
const kvStore = await createStore('shared-signing-protection', LmdbSlashingProtectionDatabase.SCHEMA_VERSION, {
|
|
147
|
+
dataStoreMapSizeKb: 1024 * 1024
|
|
148
|
+
});
|
|
149
|
+
return new LmdbSlashingProtectionDatabase(kvStore, dateProvider);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a ValidatorHASigner backed by a pre-existing SlashingProtectionDatabase.
|
|
153
|
+
* Used for testing HA setups where multiple nodes share the same protection database.
|
|
154
|
+
*/ export function createSignerFromSharedDb(db, config, deps) {
|
|
155
|
+
const telemetryClient = deps?.telemetryClient ?? getTelemetryClient();
|
|
156
|
+
const dateProvider = deps?.dateProvider ?? new DateProvider();
|
|
157
|
+
const metrics = new HASignerMetrics(telemetryClient, config.nodeId, 'SharedSigningProtectionMetrics');
|
|
158
|
+
const signer = new ValidatorHASigner(db, config, {
|
|
73
159
|
metrics,
|
|
74
160
|
dateProvider
|
|
75
161
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
2
|
-
import type {
|
|
2
|
+
import type { BaseSignerConfig } from '@aztec/stdlib/ha-signing';
|
|
3
3
|
import { type CheckAndRecordParams, type DeleteDutyParams, type RecordSuccessParams } from './db/types.js';
|
|
4
4
|
import type { HASignerMetrics } from './metrics.js';
|
|
5
5
|
import type { SlashingProtectionDatabase } from './types.js';
|
|
@@ -7,6 +7,8 @@ export interface SlashingProtectionServiceDeps {
|
|
|
7
7
|
metrics: HASignerMetrics;
|
|
8
8
|
dateProvider: DateProvider;
|
|
9
9
|
}
|
|
10
|
+
/** Default max age (ms) of a stuck SIGNING duty before cleanup reclaims it: 2x the 72s Aztec slot duration. */
|
|
11
|
+
export declare const DEFAULT_MAX_STUCK_DUTIES_AGE_MS = 144000;
|
|
10
12
|
/**
|
|
11
13
|
* Slashing Protection Service
|
|
12
14
|
*
|
|
@@ -27,13 +29,13 @@ export declare class SlashingProtectionService {
|
|
|
27
29
|
private readonly config;
|
|
28
30
|
private readonly log;
|
|
29
31
|
private readonly pollingIntervalMs;
|
|
30
|
-
private readonly
|
|
32
|
+
private readonly peerSigningTimeoutMs;
|
|
31
33
|
private readonly maxStuckDutiesAgeMs;
|
|
32
34
|
private readonly metrics;
|
|
33
35
|
private readonly dateProvider;
|
|
34
36
|
private cleanupRunningPromise;
|
|
35
37
|
private lastOldDutiesCleanupAtMs?;
|
|
36
|
-
constructor(db: SlashingProtectionDatabase, config:
|
|
38
|
+
constructor(db: SlashingProtectionDatabase, config: BaseSignerConfig, deps: SlashingProtectionServiceDeps);
|
|
37
39
|
/**
|
|
38
40
|
* Check if a duty can be performed and acquire the lock if so.
|
|
39
41
|
*
|
|
@@ -90,4 +92,4 @@ export declare class SlashingProtectionService {
|
|
|
90
92
|
close(): Promise<void>;
|
|
91
93
|
private cleanup;
|
|
92
94
|
}
|
|
93
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xhc2hpbmdfcHJvdGVjdGlvbl9zZXJ2aWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2xhc2hpbmdfcHJvdGVjdGlvbl9zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVNBLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFakUsT0FBTyxFQUNMLEtBQUssb0JBQW9CLEVBQ3pCLEtBQUssZ0JBQWdCLEVBRXJCLEtBQUssbUJBQW1CLEVBRXpCLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSwwQkFBMEIsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUU3RCxNQUFNLFdBQVcsNkJBQTZCO0lBQzVDLE9BQU8sRUFBRSxlQUFlLENBQUM7SUFDekIsWUFBWSxFQUFFLFlBQVksQ0FBQztDQUM1QjtBQUVELCtHQUErRztBQUMvRyxlQUFPLE1BQU0sK0JBQStCLFNBQVUsQ0FBQztBQUV2RDs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUNILHFCQUFhLHlCQUF5QjtJQWFsQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUU7SUFDbkIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNO0lBYnpCLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFTO0lBQzdCLE9BQU8sQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQVM7SUFDM0MsT0FBTyxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBUztJQUM5QyxPQUFPLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFTO0lBRTdDLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFrQjtJQUMxQyxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBZTtJQUU1QyxPQUFPLENBQUMscUJBQXFCLENBQWlCO0lBQzlDLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQyxDQUFTO0lBRTFDLFlBQ21CLEVBQUUsRUFBRSwwQkFBMEIsRUFDOUIsTUFBTSxFQUFFLGdCQUFnQixFQUN6QyxJQUFJLEVBQUUsNkJBQTZCLEVBVXBDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7O09BY0c7SUFDRyxjQUFjLENBQUMsTUFBTSxFQUFFLG9CQUFvQixHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FxRWxFO0lBRUQ7Ozs7OztPQU1HO0lBQ0csYUFBYSxDQUFDLE1BQU0sRUFBRSxtQkFBbUIsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBMkJqRTtJQUVEOzs7Ozs7T0FNRztJQUNHLFVBQVUsQ0FBQyxNQUFNLEVBQUUsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQXdCM0Q7SUFFRDs7T0FFRztJQUNILElBQUksTUFBTSxJQUFJLE1BQU0sQ0FFbkI7SUFFRDs7O09BR0c7SUFDSDs7O09BR0c7SUFDRyxLQUFLLGtCQVlWO0lBRUQ7O09BRUc7SUFDRyxJQUFJLGtCQUdUO0lBRUQ7OztPQUdHO0lBQ0csS0FBSyxrQkFHVjtZQU1hLE9BQU87Q0FrQ3RCIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slashing_protection_service.d.ts","sourceRoot":"","sources":["../src/slashing_protection_service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"slashing_protection_service.d.ts","sourceRoot":"","sources":["../src/slashing_protection_service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAErB,KAAK,mBAAmB,EAEzB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,eAAe,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,+GAA+G;AAC/G,eAAO,MAAM,+BAA+B,SAAU,CAAC;AAEvD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,yBAAyB;IAalC,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAE7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAE5C,OAAO,CAAC,qBAAqB,CAAiB;IAC9C,OAAO,CAAC,wBAAwB,CAAC,CAAS;IAE1C,YACmB,EAAE,EAAE,0BAA0B,EAC9B,MAAM,EAAE,gBAAgB,EACzC,IAAI,EAAE,6BAA6B,EAUpC;IAED;;;;;;;;;;;;;;OAcG;IACG,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqElE;IAED;;;;;;OAMG;IACG,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CA2BjE;IAED;;;;;;OAMG;IACG,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwB3D;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;OAGG;IACH;;;OAGG;IACG,KAAK,kBAYV;IAED;;OAEG;IACG,IAAI,kBAGT;IAED;;;OAGG;IACG,KAAK,kBAGV;YAMa,OAAO;CAkCtB"}
|