Lock keystores in validator cli (#3498)

This commit is contained in:
Lion - dapplion
2021-12-08 16:41:47 +01:00
committed by GitHub
parent 661e83c20e
commit ed7962416e
2 changed files with 35 additions and 9 deletions

View File

@@ -29,7 +29,7 @@ export async function validatorHandler(args: IValidatorCliArgs & IGlobalArgs): P
const version = getVersion();
logger.info("Lodestar", {version: version, network: args.network});
const secretKeys = await getSecretKeys(args);
const {secretKeys, unlockSecretKeys: unlockSecretKeys} = await getSecretKeys(args);
if (secretKeys.length === 0) {
throw new YargsError("No validator keystores found");
}
@@ -46,6 +46,7 @@ export async function validatorHandler(args: IValidatorCliArgs & IGlobalArgs): P
const onGracefulShutdownCbs: (() => Promise<void>)[] = [];
onGracefulShutdown(async () => {
for (const cb of onGracefulShutdownCbs) await cb();
unlockSecretKeys?.();
}, logger.info.bind(logger));
// This AbortController interrupts the sleep() calls when waiting for genesis

View File

@@ -6,11 +6,16 @@ import {deriveEth2ValidatorKeys, deriveKeyFromMnemonic} from "@chainsafe/bls-key
import {interopSecretKey} from "@chainsafe/lodestar-beacon-state-transition";
import {defaultNetwork, IGlobalArgs} from "../../options";
import {parseRange, stripOffNewlines, YargsError} from "../../util";
import {getLockFile} from "../../util/lockfile";
import {ValidatorDirManager} from "../../validatorDir";
import {getAccountPaths} from "../account/paths";
import {IValidatorCliArgs} from "./options";
export async function getSecretKeys(args: IValidatorCliArgs & IGlobalArgs): Promise<SecretKey[]> {
const LOCK_FILE_EXT = ".lock";
export async function getSecretKeys(
args: IValidatorCliArgs & IGlobalArgs
): Promise<{secretKeys: SecretKey[]; unlockSecretKeys?: () => void}> {
// UNSAFE - ONLY USE FOR TESTNETS. Derive keys directly from a mnemonic
if (args.fromMnemonic) {
if (args.network === defaultNetwork) {
@@ -22,16 +27,18 @@ export async function getSecretKeys(args: IValidatorCliArgs & IGlobalArgs): Prom
const masterSK = deriveKeyFromMnemonic(args.fromMnemonic);
const indexes = parseRange(args.mnemonicIndexes);
return indexes.map((index) => {
const {signing} = deriveEth2ValidatorKeys(masterSK, index);
return SecretKey.fromBytes(signing);
});
return {
secretKeys: indexes.map((index) => {
const {signing} = deriveEth2ValidatorKeys(masterSK, index);
return SecretKey.fromBytes(signing);
}),
};
}
// Derive interop keys
else if (args.interopIndexes) {
const indexes = parseRange(args.interopIndexes);
return indexes.map((index) => interopSecretKey(index));
return {secretKeys: indexes.map((index) => interopSecretKey(index))};
}
// Import JSON keystores and run
@@ -44,18 +51,36 @@ export async function getSecretKeys(args: IValidatorCliArgs & IGlobalArgs): Prom
const keystorePaths = args.importKeystoresPath.map((filepath) => resolveKeystorePaths(filepath)).flat(1);
return await Promise.all(
// Create lock files for all keystores
const lockFile = getLockFile();
const lockFilePaths = keystorePaths.map((keystorePath) => keystorePath + LOCK_FILE_EXT);
// Lock all keystores first
for (const lockFilePath of lockFilePaths) {
lockFile.lockSync(lockFilePath);
}
const secretKeys = await Promise.all(
keystorePaths.map(async (keystorePath) =>
SecretKey.fromBytes(await Keystore.parse(fs.readFileSync(keystorePath, "utf8")).decrypt(passphrase))
)
);
return {
secretKeys,
unlockSecretKeys: () => {
for (const lockFilePath of lockFilePaths) {
lockFile.unlockSync(lockFilePath);
}
},
};
}
// Read keys from local account manager
else {
const accountPaths = getAccountPaths(args);
const validatorDirManager = new ValidatorDirManager(accountPaths);
return await validatorDirManager.decryptAllValidators({force: args.force});
return {secretKeys: await validatorDirManager.decryptAllValidators({force: args.force})};
}
}