-
-
Notifications
You must be signed in to change notification settings - Fork 291
/
export.ts
112 lines (95 loc) · 4.3 KB
/
export.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import path from "node:path";
import {toHexString} from "@chainsafe/ssz";
import {InterchangeFormatVersion} from "@lodestar/validator";
import {getNodeLogger} from "@lodestar/logger/node";
import {CliCommand, YargsError, ensure0xPrefix, isValidatePubkeyHex, writeFile600Perm} from "../../../util/index.js";
import {parseLoggerArgs} from "../../../util/logger.js";
import {GlobalArgs} from "../../../options/index.js";
import {LogArgs} from "../../../options/logOptions.js";
import {AccountValidatorArgs} from "../options.js";
import {getBeaconConfigFromArgs} from "../../../config/index.js";
import {getValidatorPaths} from "../paths.js";
import {getGenesisValidatorsRoot, getSlashingProtection} from "./utils.js";
import {ISlashingProtectionArgs} from "./options.js";
type ExportArgs = {
file?: string;
pubkeys?: string[];
};
export const exportCmd: CliCommand<ExportArgs, ISlashingProtectionArgs & AccountValidatorArgs & GlobalArgs & LogArgs> =
{
command: "export",
describe: "Export an interchange file.",
examples: [
{
command: "validator slashing-protection export --network goerli --file interchange.json",
description: "Export an interchange JSON file for all validators in the slashing protection DB",
},
],
options: {
file: {
description: "The slashing protection interchange file to export to (.json).",
demandOption: true,
type: "string",
},
pubkeys: {
description: "Export slashing protection data only for a given subset of public keys",
type: "array",
string: true, // Ensures the pubkey string is not automatically converted to numbers
coerce: (pubkeys: string[]): string[] =>
// Parse ["0x11,0x22"] to ["0x11", "0x22"]
pubkeys
.map((item) => item.split(","))
.flat(1)
.map(ensure0xPrefix),
},
},
handler: async (args) => {
const {file} = args;
if (!file) throw new YargsError("must provide file arg");
const {config, network} = getBeaconConfigFromArgs(args);
const validatorPaths = getValidatorPaths(args, network);
// slashingProtection commands are fast so do not require logFile feature
const logger = getNodeLogger(
parseLoggerArgs(args, {defaultLogFilepath: path.join(validatorPaths.dataDir, "validator.log")}, config)
);
const {validatorsDbDir: dbPath} = getValidatorPaths(args, network);
const formatVersion: InterchangeFormatVersion = {version: "5"};
logger.info("Exporting slashing protection data", {...formatVersion, dbPath});
const {slashingProtection, metadata} = await getSlashingProtection(args, network, logger);
// When exporting validator DB should already have genesisValidatorsRoot persisted.
// For legacy node and general fallback, fetch from:
// - known genesis data from existing network
// - else fetch from beacon node
const genesisValidatorsRoot =
(await metadata.getGenesisValidatorsRoot()) ?? (await getGenesisValidatorsRoot(args));
logger.verbose("Fetching pubkeys from slashing protection db");
const allPubkeys = await slashingProtection.listPubkeys();
let pubkeysToExport = allPubkeys;
if (args.pubkeys) {
logger.verbose("Filtering by pubkeys from args", {count: args.pubkeys.length});
const filteredPubkeys = [];
for (const pubkeyHex of args.pubkeys) {
if (!isValidatePubkeyHex(pubkeyHex)) {
throw new YargsError(`Invalid pubkey ${pubkeyHex}`);
}
const existingPubkey = allPubkeys.find((pubkey) => toHexString(pubkey) === pubkeyHex);
if (!existingPubkey) {
logger.warn("Pubkey not found in slashing protection db", {pubkey: pubkeyHex});
} else {
filteredPubkeys.push(existingPubkey);
}
}
pubkeysToExport = filteredPubkeys;
}
logger.info("Starting export for pubkeys found", {count: pubkeysToExport.length});
const interchange = await slashingProtection.exportInterchange(
genesisValidatorsRoot,
pubkeysToExport,
formatVersion,
logger
);
logger.info("Writing slashing protection data", {file});
writeFile600Perm(file, interchange);
logger.info("Export completed successfully");
},
};