@aztec/validator-ha-signer 0.0.1-commit.8c0b8ff → 0.0.1-commit.8cb2d04d8

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.
Files changed (58) hide show
  1. package/README.md +0 -2
  2. package/dest/db/index.d.ts +2 -1
  3. package/dest/db/index.d.ts.map +1 -1
  4. package/dest/db/index.js +1 -0
  5. package/dest/db/lmdb.d.ts +66 -0
  6. package/dest/db/lmdb.d.ts.map +1 -0
  7. package/dest/db/lmdb.js +189 -0
  8. package/dest/db/migrations/1_initial-schema.d.ts +4 -2
  9. package/dest/db/migrations/1_initial-schema.d.ts.map +1 -1
  10. package/dest/db/migrations/1_initial-schema.js +34 -4
  11. package/dest/db/migrations/2_add-checkpoint-number.d.ts +7 -0
  12. package/dest/db/migrations/2_add-checkpoint-number.d.ts.map +1 -0
  13. package/dest/db/migrations/2_add-checkpoint-number.js +17 -0
  14. package/dest/db/postgres.d.ts +4 -2
  15. package/dest/db/postgres.d.ts.map +1 -1
  16. package/dest/db/postgres.js +15 -13
  17. package/dest/db/schema.d.ts +6 -6
  18. package/dest/db/schema.d.ts.map +1 -1
  19. package/dest/db/schema.js +9 -4
  20. package/dest/db/types.d.ts +46 -21
  21. package/dest/db/types.d.ts.map +1 -1
  22. package/dest/db/types.js +31 -15
  23. package/dest/factory.d.ts +29 -7
  24. package/dest/factory.d.ts.map +1 -1
  25. package/dest/factory.js +64 -19
  26. package/dest/metrics.d.ts +51 -0
  27. package/dest/metrics.d.ts.map +1 -0
  28. package/dest/metrics.js +103 -0
  29. package/dest/slashing_protection_service.d.ts +12 -3
  30. package/dest/slashing_protection_service.d.ts.map +1 -1
  31. package/dest/slashing_protection_service.js +15 -4
  32. package/dest/types.d.ts +18 -70
  33. package/dest/types.d.ts.map +1 -1
  34. package/dest/types.js +4 -20
  35. package/dest/validator_ha_signer.d.ts +12 -4
  36. package/dest/validator_ha_signer.d.ts.map +1 -1
  37. package/dest/validator_ha_signer.js +18 -8
  38. package/package.json +10 -6
  39. package/src/db/index.ts +1 -0
  40. package/src/db/lmdb.ts +265 -0
  41. package/src/db/migrations/1_initial-schema.ts +35 -4
  42. package/src/db/migrations/2_add-checkpoint-number.ts +19 -0
  43. package/src/db/postgres.ts +15 -11
  44. package/src/db/schema.ts +9 -4
  45. package/src/db/types.ts +66 -19
  46. package/src/factory.ts +74 -17
  47. package/src/metrics.ts +138 -0
  48. package/src/slashing_protection_service.ts +26 -5
  49. package/src/types.ts +38 -104
  50. package/src/validator_ha_signer.ts +36 -12
  51. package/dest/config.d.ts +0 -101
  52. package/dest/config.d.ts.map +0 -1
  53. package/dest/config.js +0 -92
  54. package/dest/db/in_memory.d.ts +0 -20
  55. package/dest/db/in_memory.d.ts.map +0 -1
  56. package/dest/db/in_memory.js +0 -73
  57. package/src/config.ts +0 -149
  58. package/src/db/in_memory.ts +0 -107
package/dest/config.d.ts DELETED
@@ -1,101 +0,0 @@
1
- import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
2
- import { type ConfigMappingsType } from '@aztec/foundation/config';
3
- import { EthAddress } from '@aztec/foundation/eth-address';
4
- import { z } from 'zod';
5
- /**
6
- * Configuration for the Validator HA Signer
7
- *
8
- * This config is used for distributed locking and slashing protection
9
- * when running multiple validator nodes in a high-availability setup.
10
- */
11
- export interface ValidatorHASignerConfig {
12
- /** Whether HA signing / slashing protection is enabled */
13
- haSigningEnabled: boolean;
14
- /** L1 contract addresses (rollup address required) */
15
- l1Contracts: Pick<L1ContractAddresses, 'rollupAddress'>;
16
- /** Unique identifier for this node */
17
- nodeId: string;
18
- /** How long to wait between polls when a duty is being signed (ms) */
19
- pollingIntervalMs: number;
20
- /** Maximum time to wait for a duty being signed to complete (ms) */
21
- signingTimeoutMs: number;
22
- /** Maximum age of a stuck duty in ms (defaults to 2x hardcoded Aztec slot duration if not set) */
23
- maxStuckDutiesAgeMs?: number;
24
- /** Optional: clean up old duties after this many hours (disabled if not set) */
25
- cleanupOldDutiesAfterHours?: number;
26
- /**
27
- * PostgreSQL connection string
28
- * Format: postgresql://user:password@host:port/database
29
- */
30
- databaseUrl?: string;
31
- /**
32
- * PostgreSQL connection pool configuration
33
- */
34
- /** Maximum number of clients in the pool (default: 10) */
35
- poolMaxCount?: number;
36
- /** Minimum number of clients in the pool (default: 0) */
37
- poolMinCount?: number;
38
- /** Idle timeout in milliseconds (default: 10000) */
39
- poolIdleTimeoutMs?: number;
40
- /** Connection timeout in milliseconds (default: 0, no timeout) */
41
- poolConnectionTimeoutMs?: number;
42
- }
43
- export declare const validatorHASignerConfigMappings: ConfigMappingsType<ValidatorHASignerConfig>;
44
- export declare const defaultValidatorHASignerConfig: ValidatorHASignerConfig;
45
- /**
46
- * Returns the validator HA signer configuration from environment variables.
47
- * Note: If an environment variable is not set, the default value is used.
48
- * @returns The validator HA signer configuration.
49
- */
50
- export declare function getConfigEnvVars(): ValidatorHASignerConfig;
51
- export declare const ValidatorHASignerConfigSchema: z.ZodObject<{
52
- haSigningEnabled: z.ZodBoolean;
53
- l1Contracts: z.ZodObject<{
54
- rollupAddress: z.ZodType<EthAddress, z.ZodTypeDef, EthAddress>;
55
- }, "strip", z.ZodTypeAny, {
56
- rollupAddress: EthAddress;
57
- }, {
58
- rollupAddress: EthAddress;
59
- }>;
60
- nodeId: z.ZodString;
61
- pollingIntervalMs: z.ZodNumber;
62
- signingTimeoutMs: z.ZodNumber;
63
- maxStuckDutiesAgeMs: z.ZodOptional<z.ZodNumber>;
64
- cleanupOldDutiesAfterHours: z.ZodOptional<z.ZodNumber>;
65
- databaseUrl: z.ZodOptional<z.ZodString>;
66
- poolMaxCount: z.ZodOptional<z.ZodNumber>;
67
- poolMinCount: z.ZodOptional<z.ZodNumber>;
68
- poolIdleTimeoutMs: z.ZodOptional<z.ZodNumber>;
69
- poolConnectionTimeoutMs: z.ZodOptional<z.ZodNumber>;
70
- }, "strip", z.ZodTypeAny, {
71
- haSigningEnabled: boolean;
72
- l1Contracts: {
73
- rollupAddress: EthAddress;
74
- };
75
- nodeId: string;
76
- pollingIntervalMs: number;
77
- signingTimeoutMs: number;
78
- maxStuckDutiesAgeMs?: number | undefined;
79
- cleanupOldDutiesAfterHours?: number | undefined;
80
- databaseUrl?: string | undefined;
81
- poolMaxCount?: number | undefined;
82
- poolMinCount?: number | undefined;
83
- poolIdleTimeoutMs?: number | undefined;
84
- poolConnectionTimeoutMs?: number | undefined;
85
- }, {
86
- haSigningEnabled: boolean;
87
- l1Contracts: {
88
- rollupAddress: EthAddress;
89
- };
90
- nodeId: string;
91
- pollingIntervalMs: number;
92
- signingTimeoutMs: number;
93
- maxStuckDutiesAgeMs?: number | undefined;
94
- cleanupOldDutiesAfterHours?: number | undefined;
95
- databaseUrl?: string | undefined;
96
- poolMaxCount?: number | undefined;
97
- poolMinCount?: number | undefined;
98
- poolIdleTimeoutMs?: number | undefined;
99
- poolConnectionTimeoutMs?: number | undefined;
100
- }>;
101
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDakYsT0FBTyxFQUNMLEtBQUssa0JBQWtCLEVBTXhCLE1BQU0sMEJBQTBCLENBQUM7QUFDbEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRzNELE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEI7Ozs7O0dBS0c7QUFDSCxNQUFNLFdBQVcsdUJBQXVCO0lBQ3RDLDBEQUEwRDtJQUMxRCxnQkFBZ0IsRUFBRSxPQUFPLENBQUM7SUFDMUIsc0RBQXNEO0lBQ3RELFdBQVcsRUFBRSxJQUFJLENBQUMsbUJBQW1CLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDeEQsc0NBQXNDO0lBQ3RDLE1BQU0sRUFBRSxNQUFNLENBQUM7SUFDZixzRUFBc0U7SUFDdEUsaUJBQWlCLEVBQUUsTUFBTSxDQUFDO0lBQzFCLG9FQUFvRTtJQUNwRSxnQkFBZ0IsRUFBRSxNQUFNLENBQUM7SUFDekIsa0dBQWtHO0lBQ2xHLG1CQUFtQixDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQzdCLGdGQUFnRjtJQUNoRiwwQkFBMEIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNwQzs7O09BR0c7SUFDSCxXQUFXLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDckI7O09BRUc7SUFDSCwwREFBMEQ7SUFDMUQsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLHlEQUF5RDtJQUN6RCxZQUFZLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDdEIsb0RBQW9EO0lBQ3BELGlCQUFpQixDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQzNCLGtFQUFrRTtJQUNsRSx1QkFBdUIsQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUNsQztBQUVELGVBQU8sTUFBTSwrQkFBK0IsRUFBRSxrQkFBa0IsQ0FBQyx1QkFBdUIsQ0FpRXZGLENBQUM7QUFFRixlQUFPLE1BQU0sOEJBQThCLEVBQUUsdUJBRTVDLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsd0JBQWdCLGdCQUFnQixJQUFJLHVCQUF1QixDQUUxRDtBQUVELGVBQU8sTUFBTSw2QkFBNkI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUFlRSxDQUFDIn0=
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EACL,KAAK,kBAAkB,EAMxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAG3D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,gBAAgB,EAAE,OAAO,CAAC;IAC1B,sDAAsD;IACtD,WAAW,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACxD,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;IACzB,kGAAkG;IAClG,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gFAAgF;IAChF,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,eAAO,MAAM,+BAA+B,EAAE,kBAAkB,CAAC,uBAAuB,CAiEvF,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,uBAE5C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,uBAAuB,CAE1D;AAED,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAeE,CAAC"}
package/dest/config.js DELETED
@@ -1,92 +0,0 @@
1
- import { booleanConfigHelper, getConfigFromMappings, getDefaultConfig, numberConfigHelper, optionalNumberConfigHelper } from '@aztec/foundation/config';
2
- import { EthAddress } from '@aztec/foundation/eth-address';
3
- import { z } from 'zod';
4
- export const validatorHASignerConfigMappings = {
5
- haSigningEnabled: {
6
- env: 'VALIDATOR_HA_SIGNING_ENABLED',
7
- description: 'Whether HA signing / slashing protection is enabled',
8
- ...booleanConfigHelper(false)
9
- },
10
- l1Contracts: {
11
- description: 'L1 contract addresses (rollup address required)',
12
- nested: {
13
- rollupAddress: {
14
- description: 'The Ethereum address of the rollup contract (must be set programmatically)',
15
- parseEnv: (val)=>EthAddress.fromString(val)
16
- }
17
- }
18
- },
19
- nodeId: {
20
- env: 'VALIDATOR_HA_NODE_ID',
21
- description: 'The unique identifier for this node',
22
- defaultValue: ''
23
- },
24
- pollingIntervalMs: {
25
- env: 'VALIDATOR_HA_POLLING_INTERVAL_MS',
26
- description: 'The number of ms to wait between polls when a duty is being signed',
27
- ...numberConfigHelper(100)
28
- },
29
- signingTimeoutMs: {
30
- env: 'VALIDATOR_HA_SIGNING_TIMEOUT_MS',
31
- description: 'The maximum time to wait for a duty being signed to complete',
32
- ...numberConfigHelper(3_000)
33
- },
34
- maxStuckDutiesAgeMs: {
35
- env: 'VALIDATOR_HA_MAX_STUCK_DUTIES_AGE_MS',
36
- description: 'The maximum age of a stuck duty in ms (defaults to 2x Aztec slot duration)',
37
- ...optionalNumberConfigHelper()
38
- },
39
- cleanupOldDutiesAfterHours: {
40
- env: 'VALIDATOR_HA_OLD_DUTIES_MAX_AGE_H',
41
- description: 'Optional: clean up old duties after this many hours (disabled if not set)',
42
- ...optionalNumberConfigHelper()
43
- },
44
- databaseUrl: {
45
- env: 'VALIDATOR_HA_DATABASE_URL',
46
- description: 'PostgreSQL connection string for validator HA signer (format: postgresql://user:password@host:port/database)'
47
- },
48
- poolMaxCount: {
49
- env: 'VALIDATOR_HA_POOL_MAX',
50
- description: 'Maximum number of clients in the pool',
51
- ...numberConfigHelper(10)
52
- },
53
- poolMinCount: {
54
- env: 'VALIDATOR_HA_POOL_MIN',
55
- description: 'Minimum number of clients in the pool',
56
- ...numberConfigHelper(0)
57
- },
58
- poolIdleTimeoutMs: {
59
- env: 'VALIDATOR_HA_POOL_IDLE_TIMEOUT_MS',
60
- description: 'Idle timeout in milliseconds',
61
- ...numberConfigHelper(10_000)
62
- },
63
- poolConnectionTimeoutMs: {
64
- env: 'VALIDATOR_HA_POOL_CONNECTION_TIMEOUT_MS',
65
- description: 'Connection timeout in milliseconds (0 means no timeout)',
66
- ...numberConfigHelper(0)
67
- }
68
- };
69
- export const defaultValidatorHASignerConfig = getDefaultConfig(validatorHASignerConfigMappings);
70
- /**
71
- * Returns the validator HA signer configuration from environment variables.
72
- * Note: If an environment variable is not set, the default value is used.
73
- * @returns The validator HA signer configuration.
74
- */ export function getConfigEnvVars() {
75
- return getConfigFromMappings(validatorHASignerConfigMappings);
76
- }
77
- export const ValidatorHASignerConfigSchema = z.object({
78
- haSigningEnabled: z.boolean(),
79
- l1Contracts: z.object({
80
- rollupAddress: z.instanceof(EthAddress)
81
- }),
82
- nodeId: z.string(),
83
- pollingIntervalMs: z.number().min(0),
84
- signingTimeoutMs: z.number().min(0),
85
- maxStuckDutiesAgeMs: z.number().min(0).optional(),
86
- cleanupOldDutiesAfterHours: z.number().min(0).optional(),
87
- databaseUrl: z.string().optional(),
88
- poolMaxCount: z.number().min(0).optional(),
89
- poolMinCount: z.number().min(0).optional(),
90
- poolIdleTimeoutMs: z.number().min(0).optional(),
91
- poolConnectionTimeoutMs: z.number().min(0).optional()
92
- });
@@ -1,20 +0,0 @@
1
- /**
2
- * In-memory implementation of SlashingProtectionDatabase for testing.
3
- * Used to simulate shared slashing protection in HA test setups without requiring PostgreSQL.
4
- */
5
- import type { SlotNumber } from '@aztec/foundation/branded-types';
6
- import type { EthAddress } from '@aztec/foundation/eth-address';
7
- import type { SlashingProtectionDatabase, TryInsertOrGetResult } from '../types.js';
8
- import type { CheckAndRecordParams, DutyType } from './types.js';
9
- /** In-memory slashing protection database for testing HA setups. */
10
- export declare class InMemorySlashingProtectionDatabase implements SlashingProtectionDatabase {
11
- private duties;
12
- tryInsertOrGetExisting(params: CheckAndRecordParams): Promise<TryInsertOrGetResult>;
13
- updateDutySigned(rollupAddress: EthAddress, validatorAddress: EthAddress, slot: SlotNumber, dutyType: DutyType, signature: string, lockToken: string, blockIndexWithinCheckpoint: number): Promise<boolean>;
14
- deleteDuty(rollupAddress: EthAddress, validatorAddress: EthAddress, slot: SlotNumber, dutyType: DutyType, lockToken: string, blockIndexWithinCheckpoint: number): Promise<boolean>;
15
- cleanupOwnStuckDuties(_nodeId: string, _maxAgeMs: number): Promise<number>;
16
- cleanupOutdatedRollupDuties(_currentRollupAddress: EthAddress): Promise<number>;
17
- cleanupOldDuties(_maxAgeMs: number): Promise<number>;
18
- close(): Promise<void>;
19
- }
20
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5fbWVtb3J5LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGIvaW5fbWVtb3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUNILE9BQU8sS0FBSyxFQUFlLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQy9FLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRWhFLE9BQU8sS0FBSyxFQUFFLDBCQUEwQixFQUFFLG9CQUFvQixFQUF1QixNQUFNLGFBQWEsQ0FBQztBQUN6RyxPQUFPLEtBQUssRUFBRSxvQkFBb0IsRUFBRSxRQUFRLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFjakUsb0VBQW9FO0FBQ3BFLHFCQUFhLGtDQUFtQyxZQUFXLDBCQUEwQjtJQUNuRixPQUFPLENBQUMsTUFBTSxDQUEwQztJQUV4RCxzQkFBc0IsQ0FBQyxNQUFNLEVBQUUsb0JBQW9CLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBeUJsRjtJQUVELGdCQUFnQixDQUNkLGFBQWEsRUFBRSxVQUFVLEVBQ3pCLGdCQUFnQixFQUFFLFVBQVUsRUFDNUIsSUFBSSxFQUFFLFVBQVUsRUFDaEIsUUFBUSxFQUFFLFFBQVEsRUFDbEIsU0FBUyxFQUFFLE1BQU0sRUFDakIsU0FBUyxFQUFFLE1BQU0sRUFDakIsMEJBQTBCLEVBQUUsTUFBTSxHQUNqQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBVWxCO0lBRUQsVUFBVSxDQUNSLGFBQWEsRUFBRSxVQUFVLEVBQ3pCLGdCQUFnQixFQUFFLFVBQVUsRUFDNUIsSUFBSSxFQUFFLFVBQVUsRUFDaEIsUUFBUSxFQUFFLFFBQVEsRUFDbEIsU0FBUyxFQUFFLE1BQU0sRUFDakIsMEJBQTBCLEVBQUUsTUFBTSxHQUNqQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBUWxCO0lBRUQscUJBQXFCLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FFekU7SUFFRCwyQkFBMkIsQ0FBQyxxQkFBcUIsRUFBRSxVQUFVLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUU5RTtJQUVELGdCQUFnQixDQUFDLFNBQVMsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUVuRDtJQUVELEtBQUssSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBR3JCO0NBQ0YifQ==
@@ -1 +0,0 @@
1
- {"version":3,"file":"in_memory.d.ts","sourceRoot":"","sources":["../../src/db/in_memory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EAAE,0BAA0B,EAAE,oBAAoB,EAAuB,MAAM,aAAa,CAAC;AACzG,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAcjE,oEAAoE;AACpE,qBAAa,kCAAmC,YAAW,0BAA0B;IACnF,OAAO,CAAC,MAAM,CAA0C;IAExD,sBAAsB,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyBlF;IAED,gBAAgB,CACd,aAAa,EAAE,UAAU,EACzB,gBAAgB,EAAE,UAAU,EAC5B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,0BAA0B,EAAE,MAAM,GACjC,OAAO,CAAC,OAAO,CAAC,CAUlB;IAED,UAAU,CACR,aAAa,EAAE,UAAU,EACzB,gBAAgB,EAAE,UAAU,EAC5B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,0BAA0B,EAAE,MAAM,GACjC,OAAO,CAAC,OAAO,CAAC,CAQlB;IAED,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEzE;IAED,2BAA2B,CAAC,qBAAqB,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAE9E;IAED,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnD;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAGrB;CACF"}
@@ -1,73 +0,0 @@
1
- /**
2
- * In-memory implementation of SlashingProtectionDatabase for testing.
3
- * Used to simulate shared slashing protection in HA test setups without requiring PostgreSQL.
4
- */ import { DutyStatus, getBlockIndexFromDutyIdentifier } from './types.js';
5
- /** Creates a unique key for a duty based on its identifying fields. */ function dutyKey(rollupAddress, validatorAddress, slot, dutyType, blockIndexWithinCheckpoint) {
6
- return `${rollupAddress}:${validatorAddress}:${slot}:${dutyType}:${blockIndexWithinCheckpoint}`;
7
- }
8
- /** In-memory slashing protection database for testing HA setups. */ export class InMemorySlashingProtectionDatabase {
9
- duties = new Map();
10
- tryInsertOrGetExisting(params) {
11
- const blockIndex = getBlockIndexFromDutyIdentifier(params);
12
- const key = dutyKey(params.rollupAddress, params.validatorAddress, params.slot, params.dutyType, blockIndex);
13
- const existing = this.duties.get(key);
14
- if (existing) {
15
- return Promise.resolve({
16
- isNew: false,
17
- record: existing
18
- });
19
- }
20
- const lockToken = `lock-${Date.now()}-${Math.random().toString(36).slice(2)}`;
21
- const record = {
22
- rollupAddress: params.rollupAddress,
23
- validatorAddress: params.validatorAddress,
24
- slot: params.slot,
25
- blockNumber: params.blockNumber,
26
- blockIndexWithinCheckpoint: blockIndex,
27
- dutyType: params.dutyType,
28
- status: DutyStatus.SIGNING,
29
- messageHash: params.messageHash,
30
- nodeId: params.nodeId,
31
- lockToken,
32
- startedAt: new Date()
33
- };
34
- this.duties.set(key, record);
35
- return Promise.resolve({
36
- isNew: true,
37
- record
38
- });
39
- }
40
- updateDutySigned(rollupAddress, validatorAddress, slot, dutyType, signature, lockToken, blockIndexWithinCheckpoint) {
41
- const key = dutyKey(rollupAddress, validatorAddress, slot, dutyType, blockIndexWithinCheckpoint);
42
- const record = this.duties.get(key);
43
- if (!record || record.lockToken !== lockToken) {
44
- return Promise.resolve(false);
45
- }
46
- record.status = DutyStatus.SIGNED;
47
- record.signature = signature;
48
- record.completedAt = new Date();
49
- return Promise.resolve(true);
50
- }
51
- deleteDuty(rollupAddress, validatorAddress, slot, dutyType, lockToken, blockIndexWithinCheckpoint) {
52
- const key = dutyKey(rollupAddress, validatorAddress, slot, dutyType, blockIndexWithinCheckpoint);
53
- const record = this.duties.get(key);
54
- if (!record || record.lockToken !== lockToken) {
55
- return Promise.resolve(false);
56
- }
57
- this.duties.delete(key);
58
- return Promise.resolve(true);
59
- }
60
- cleanupOwnStuckDuties(_nodeId, _maxAgeMs) {
61
- return Promise.resolve(0);
62
- }
63
- cleanupOutdatedRollupDuties(_currentRollupAddress) {
64
- return Promise.resolve(0);
65
- }
66
- cleanupOldDuties(_maxAgeMs) {
67
- return Promise.resolve(0);
68
- }
69
- close() {
70
- this.duties.clear();
71
- return Promise.resolve();
72
- }
73
- }
package/src/config.ts DELETED
@@ -1,149 +0,0 @@
1
- import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
2
- import {
3
- type ConfigMappingsType,
4
- booleanConfigHelper,
5
- getConfigFromMappings,
6
- getDefaultConfig,
7
- numberConfigHelper,
8
- optionalNumberConfigHelper,
9
- } from '@aztec/foundation/config';
10
- import { EthAddress } from '@aztec/foundation/eth-address';
11
- import type { ZodFor } from '@aztec/foundation/schemas';
12
-
13
- import { z } from 'zod';
14
-
15
- /**
16
- * Configuration for the Validator HA Signer
17
- *
18
- * This config is used for distributed locking and slashing protection
19
- * when running multiple validator nodes in a high-availability setup.
20
- */
21
- export interface ValidatorHASignerConfig {
22
- /** Whether HA signing / slashing protection is enabled */
23
- haSigningEnabled: boolean;
24
- /** L1 contract addresses (rollup address required) */
25
- l1Contracts: Pick<L1ContractAddresses, 'rollupAddress'>;
26
- /** Unique identifier for this node */
27
- nodeId: string;
28
- /** How long to wait between polls when a duty is being signed (ms) */
29
- pollingIntervalMs: number;
30
- /** Maximum time to wait for a duty being signed to complete (ms) */
31
- signingTimeoutMs: number;
32
- /** Maximum age of a stuck duty in ms (defaults to 2x hardcoded Aztec slot duration if not set) */
33
- maxStuckDutiesAgeMs?: number;
34
- /** Optional: clean up old duties after this many hours (disabled if not set) */
35
- cleanupOldDutiesAfterHours?: number;
36
- /**
37
- * PostgreSQL connection string
38
- * Format: postgresql://user:password@host:port/database
39
- */
40
- databaseUrl?: string;
41
- /**
42
- * PostgreSQL connection pool configuration
43
- */
44
- /** Maximum number of clients in the pool (default: 10) */
45
- poolMaxCount?: number;
46
- /** Minimum number of clients in the pool (default: 0) */
47
- poolMinCount?: number;
48
- /** Idle timeout in milliseconds (default: 10000) */
49
- poolIdleTimeoutMs?: number;
50
- /** Connection timeout in milliseconds (default: 0, no timeout) */
51
- poolConnectionTimeoutMs?: number;
52
- }
53
-
54
- export const validatorHASignerConfigMappings: ConfigMappingsType<ValidatorHASignerConfig> = {
55
- haSigningEnabled: {
56
- env: 'VALIDATOR_HA_SIGNING_ENABLED',
57
- description: 'Whether HA signing / slashing protection is enabled',
58
- ...booleanConfigHelper(false),
59
- },
60
- l1Contracts: {
61
- description: 'L1 contract addresses (rollup address required)',
62
- nested: {
63
- rollupAddress: {
64
- description: 'The Ethereum address of the rollup contract (must be set programmatically)',
65
- parseEnv: (val: string) => EthAddress.fromString(val),
66
- },
67
- },
68
- },
69
- nodeId: {
70
- env: 'VALIDATOR_HA_NODE_ID',
71
- description: 'The unique identifier for this node',
72
- defaultValue: '',
73
- },
74
- pollingIntervalMs: {
75
- env: 'VALIDATOR_HA_POLLING_INTERVAL_MS',
76
- description: 'The number of ms to wait between polls when a duty is being signed',
77
- ...numberConfigHelper(100),
78
- },
79
- signingTimeoutMs: {
80
- env: 'VALIDATOR_HA_SIGNING_TIMEOUT_MS',
81
- description: 'The maximum time to wait for a duty being signed to complete',
82
- ...numberConfigHelper(3_000),
83
- },
84
- maxStuckDutiesAgeMs: {
85
- env: 'VALIDATOR_HA_MAX_STUCK_DUTIES_AGE_MS',
86
- description: 'The maximum age of a stuck duty in ms (defaults to 2x Aztec slot duration)',
87
- ...optionalNumberConfigHelper(),
88
- },
89
- cleanupOldDutiesAfterHours: {
90
- env: 'VALIDATOR_HA_OLD_DUTIES_MAX_AGE_H',
91
- description: 'Optional: clean up old duties after this many hours (disabled if not set)',
92
- ...optionalNumberConfigHelper(),
93
- },
94
- databaseUrl: {
95
- env: 'VALIDATOR_HA_DATABASE_URL',
96
- description:
97
- 'PostgreSQL connection string for validator HA signer (format: postgresql://user:password@host:port/database)',
98
- },
99
- poolMaxCount: {
100
- env: 'VALIDATOR_HA_POOL_MAX',
101
- description: 'Maximum number of clients in the pool',
102
- ...numberConfigHelper(10),
103
- },
104
- poolMinCount: {
105
- env: 'VALIDATOR_HA_POOL_MIN',
106
- description: 'Minimum number of clients in the pool',
107
- ...numberConfigHelper(0),
108
- },
109
- poolIdleTimeoutMs: {
110
- env: 'VALIDATOR_HA_POOL_IDLE_TIMEOUT_MS',
111
- description: 'Idle timeout in milliseconds',
112
- ...numberConfigHelper(10_000),
113
- },
114
- poolConnectionTimeoutMs: {
115
- env: 'VALIDATOR_HA_POOL_CONNECTION_TIMEOUT_MS',
116
- description: 'Connection timeout in milliseconds (0 means no timeout)',
117
- ...numberConfigHelper(0),
118
- },
119
- };
120
-
121
- export const defaultValidatorHASignerConfig: ValidatorHASignerConfig = getDefaultConfig(
122
- validatorHASignerConfigMappings,
123
- );
124
-
125
- /**
126
- * Returns the validator HA signer configuration from environment variables.
127
- * Note: If an environment variable is not set, the default value is used.
128
- * @returns The validator HA signer configuration.
129
- */
130
- export function getConfigEnvVars(): ValidatorHASignerConfig {
131
- return getConfigFromMappings<ValidatorHASignerConfig>(validatorHASignerConfigMappings);
132
- }
133
-
134
- export const ValidatorHASignerConfigSchema = z.object({
135
- haSigningEnabled: z.boolean(),
136
- l1Contracts: z.object({
137
- rollupAddress: z.instanceof(EthAddress),
138
- }),
139
- nodeId: z.string(),
140
- pollingIntervalMs: z.number().min(0),
141
- signingTimeoutMs: z.number().min(0),
142
- maxStuckDutiesAgeMs: z.number().min(0).optional(),
143
- cleanupOldDutiesAfterHours: z.number().min(0).optional(),
144
- databaseUrl: z.string().optional(),
145
- poolMaxCount: z.number().min(0).optional(),
146
- poolMinCount: z.number().min(0).optional(),
147
- poolIdleTimeoutMs: z.number().min(0).optional(),
148
- poolConnectionTimeoutMs: z.number().min(0).optional(),
149
- }) satisfies ZodFor<ValidatorHASignerConfig>;
@@ -1,107 +0,0 @@
1
- /**
2
- * In-memory implementation of SlashingProtectionDatabase for testing.
3
- * Used to simulate shared slashing protection in HA test setups without requiring PostgreSQL.
4
- */
5
- import type { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
6
- import type { EthAddress } from '@aztec/foundation/eth-address';
7
-
8
- import type { SlashingProtectionDatabase, TryInsertOrGetResult, ValidatorDutyRecord } from '../types.js';
9
- import type { CheckAndRecordParams, DutyType } from './types.js';
10
- import { DutyStatus, getBlockIndexFromDutyIdentifier } from './types.js';
11
-
12
- /** Creates a unique key for a duty based on its identifying fields. */
13
- function dutyKey(
14
- rollupAddress: EthAddress,
15
- validatorAddress: EthAddress,
16
- slot: SlotNumber,
17
- dutyType: DutyType,
18
- blockIndexWithinCheckpoint: number,
19
- ): string {
20
- return `${rollupAddress}:${validatorAddress}:${slot}:${dutyType}:${blockIndexWithinCheckpoint}`;
21
- }
22
-
23
- /** In-memory slashing protection database for testing HA setups. */
24
- export class InMemorySlashingProtectionDatabase implements SlashingProtectionDatabase {
25
- private duties = new Map<string, ValidatorDutyRecord>();
26
-
27
- tryInsertOrGetExisting(params: CheckAndRecordParams): Promise<TryInsertOrGetResult> {
28
- const blockIndex = getBlockIndexFromDutyIdentifier(params);
29
- const key = dutyKey(params.rollupAddress, params.validatorAddress, params.slot, params.dutyType, blockIndex);
30
-
31
- const existing = this.duties.get(key);
32
- if (existing) {
33
- return Promise.resolve({ isNew: false, record: existing });
34
- }
35
-
36
- const lockToken = `lock-${Date.now()}-${Math.random().toString(36).slice(2)}`;
37
- const record: ValidatorDutyRecord = {
38
- rollupAddress: params.rollupAddress,
39
- validatorAddress: params.validatorAddress,
40
- slot: params.slot,
41
- blockNumber: params.blockNumber as BlockNumber,
42
- blockIndexWithinCheckpoint: blockIndex,
43
- dutyType: params.dutyType,
44
- status: DutyStatus.SIGNING,
45
- messageHash: params.messageHash,
46
- nodeId: params.nodeId,
47
- lockToken,
48
- startedAt: new Date(),
49
- };
50
- this.duties.set(key, record);
51
- return Promise.resolve({ isNew: true, record });
52
- }
53
-
54
- updateDutySigned(
55
- rollupAddress: EthAddress,
56
- validatorAddress: EthAddress,
57
- slot: SlotNumber,
58
- dutyType: DutyType,
59
- signature: string,
60
- lockToken: string,
61
- blockIndexWithinCheckpoint: number,
62
- ): Promise<boolean> {
63
- const key = dutyKey(rollupAddress, validatorAddress, slot, dutyType, blockIndexWithinCheckpoint);
64
- const record = this.duties.get(key);
65
- if (!record || record.lockToken !== lockToken) {
66
- return Promise.resolve(false);
67
- }
68
- record.status = DutyStatus.SIGNED;
69
- record.signature = signature;
70
- record.completedAt = new Date();
71
- return Promise.resolve(true);
72
- }
73
-
74
- deleteDuty(
75
- rollupAddress: EthAddress,
76
- validatorAddress: EthAddress,
77
- slot: SlotNumber,
78
- dutyType: DutyType,
79
- lockToken: string,
80
- blockIndexWithinCheckpoint: number,
81
- ): Promise<boolean> {
82
- const key = dutyKey(rollupAddress, validatorAddress, slot, dutyType, blockIndexWithinCheckpoint);
83
- const record = this.duties.get(key);
84
- if (!record || record.lockToken !== lockToken) {
85
- return Promise.resolve(false);
86
- }
87
- this.duties.delete(key);
88
- return Promise.resolve(true);
89
- }
90
-
91
- cleanupOwnStuckDuties(_nodeId: string, _maxAgeMs: number): Promise<number> {
92
- return Promise.resolve(0);
93
- }
94
-
95
- cleanupOutdatedRollupDuties(_currentRollupAddress: EthAddress): Promise<number> {
96
- return Promise.resolve(0);
97
- }
98
-
99
- cleanupOldDuties(_maxAgeMs: number): Promise<number> {
100
- return Promise.resolve(0);
101
- }
102
-
103
- close(): Promise<void> {
104
- this.duties.clear();
105
- return Promise.resolve();
106
- }
107
- }