prune beacon_chain/validators/keystore_management.nim
This commit is contained in:
parent
7da48baba0
commit
f6022e33e0
|
@ -1,20 +1,15 @@
|
||||||
{.push raises: [].}
|
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[os, unicode],
|
std/os,
|
||||||
chronicles, chronos, json_serialization,
|
chronicles, chronos, json_serialization,
|
||||||
bearssl/rand,
|
|
||||||
serialization, blscurve, eth/common/eth_types, confutils,
|
serialization, blscurve, eth/common/eth_types, confutils,
|
||||||
".."/spec/[eth2_merkleization, keystore, crypto],
|
".."/spec/[eth2_merkleization, keystore, crypto],
|
||||||
".."/spec/datatypes/base,
|
".."/spec/datatypes/base,
|
||||||
stew/io2, libp2p/crypto/crypto as lcrypto,
|
stew/io2, libp2p/crypto/crypto as lcrypto,
|
||||||
nimcrypto/utils as ncrutils,
|
|
||||||
".."/[conf, filepath, beacon_clock],
|
".."/[conf, filepath, beacon_clock],
|
||||||
".."/networking/network_metadata,
|
|
||||||
./validator_pool
|
./validator_pool
|
||||||
|
|
||||||
export
|
export
|
||||||
keystore, validator_pool, crypto, rand
|
keystore, validator_pool, crypto
|
||||||
|
|
||||||
{.localPassC: "-fno-lto".} # no LTO for crypto
|
{.localPassC: "-fno-lto".} # no LTO for crypto
|
||||||
|
|
||||||
|
@ -119,9 +114,6 @@ proc loadKeystore(validatorsDir, secretsDir, keyName: string,
|
||||||
error "Unable to find any keystore files", keystorePath
|
error "Unable to find any keystore files", keystorePath
|
||||||
Opt.none(KeystoreData)
|
Opt.none(KeystoreData)
|
||||||
|
|
||||||
func fsName(pubkey: ValidatorPubKey|CookedPubKey): string =
|
|
||||||
"0x" & pubkey.toHex()
|
|
||||||
|
|
||||||
func checkKeyName(keyName: string): Result[void, string] =
|
func checkKeyName(keyName: string): Result[void, string] =
|
||||||
const keyAlphabet = {'a'..'f', 'A'..'F', '0'..'9'}
|
const keyAlphabet = {'a'..'f', 'A'..'F', '0'..'9'}
|
||||||
if len(keyName) != KeyNameSize:
|
if len(keyName) != KeyNameSize:
|
||||||
|
@ -179,183 +171,3 @@ iterator listLoadableKeystores*(config: AnyConf,
|
||||||
config.nonInteractive,
|
config.nonInteractive,
|
||||||
cache):
|
cache):
|
||||||
yield el
|
yield el
|
||||||
|
|
||||||
type
|
|
||||||
KeystoreGenerationErrorKind = enum
|
|
||||||
FailedToCreateValidatorsDir
|
|
||||||
FailedToCreateKeystoreDir
|
|
||||||
FailedToCreateSecretsDir
|
|
||||||
FailedToCreateSecretFile
|
|
||||||
FailedToCreateKeystoreFile
|
|
||||||
DuplicateKeystoreDir
|
|
||||||
DuplicateKeystoreFile
|
|
||||||
|
|
||||||
KeystoreGenerationError = object
|
|
||||||
case kind: KeystoreGenerationErrorKind
|
|
||||||
of FailedToCreateKeystoreDir,
|
|
||||||
FailedToCreateValidatorsDir,
|
|
||||||
FailedToCreateSecretsDir,
|
|
||||||
FailedToCreateSecretFile,
|
|
||||||
FailedToCreateKeystoreFile,
|
|
||||||
DuplicateKeystoreDir,
|
|
||||||
DuplicateKeystoreFile:
|
|
||||||
error: string
|
|
||||||
|
|
||||||
func mapErrTo[T, E](r: Result[T, E], v: static KeystoreGenerationErrorKind):
|
|
||||||
Result[T, KeystoreGenerationError] =
|
|
||||||
r.mapErr(proc (e: E): KeystoreGenerationError =
|
|
||||||
KeystoreGenerationError(kind: v, error: $e))
|
|
||||||
|
|
||||||
proc createLocalValidatorFiles(
|
|
||||||
secretsDir, validatorsDir, keystoreDir,
|
|
||||||
secretFile, passwordAsString, keystoreFile,
|
|
||||||
encodedStorage: string
|
|
||||||
): Result[void, KeystoreGenerationError] {.raises: [].} =
|
|
||||||
|
|
||||||
var success = false # becomes true when everything is created successfully
|
|
||||||
|
|
||||||
# secretsDir:
|
|
||||||
let secretsDirExisted: bool = dirExists(secretsDir)
|
|
||||||
if not(secretsDirExisted):
|
|
||||||
? secureCreatePath(secretsDir).mapErrTo(FailedToCreateSecretsDir)
|
|
||||||
defer:
|
|
||||||
if not (success or secretsDirExisted):
|
|
||||||
discard io2.removeDir(secretsDir)
|
|
||||||
|
|
||||||
# validatorsDir:
|
|
||||||
let validatorsDirExisted: bool = dirExists(validatorsDir)
|
|
||||||
if not(validatorsDirExisted):
|
|
||||||
? secureCreatePath(validatorsDir).mapErrTo(FailedToCreateValidatorsDir)
|
|
||||||
defer:
|
|
||||||
if not (success or validatorsDirExisted):
|
|
||||||
discard io2.removeDir(validatorsDir)
|
|
||||||
|
|
||||||
# keystoreDir:
|
|
||||||
? secureCreatePath(keystoreDir).mapErrTo(FailedToCreateKeystoreDir)
|
|
||||||
defer:
|
|
||||||
if not success:
|
|
||||||
discard io2.removeDir(keystoreDir)
|
|
||||||
|
|
||||||
# secretFile:
|
|
||||||
? secureWriteFile(secretFile,
|
|
||||||
passwordAsString).mapErrTo(FailedToCreateSecretFile)
|
|
||||||
defer:
|
|
||||||
if not success:
|
|
||||||
discard io2.removeFile(secretFile)
|
|
||||||
|
|
||||||
# keystoreFile:
|
|
||||||
? secureWriteFile(keystoreFile,
|
|
||||||
encodedStorage).mapErrTo(FailedToCreateKeystoreFile)
|
|
||||||
|
|
||||||
success = true
|
|
||||||
ok()
|
|
||||||
|
|
||||||
proc saveKeystore(
|
|
||||||
rng: var HmacDrbgContext,
|
|
||||||
validatorsDir, secretsDir: string,
|
|
||||||
signingKey: ValidatorPrivKey,
|
|
||||||
signingPubKey: CookedPubKey,
|
|
||||||
signingKeyPath: KeyPath,
|
|
||||||
password: string,
|
|
||||||
salt: openArray[byte] = @[],
|
|
||||||
mode = Secure
|
|
||||||
): Result[void, KeystoreGenerationError] {.raises: [].} =
|
|
||||||
let
|
|
||||||
keypass = KeystorePass.init(password)
|
|
||||||
keyName = signingPubKey.fsName
|
|
||||||
keystoreDir = validatorsDir / keyName
|
|
||||||
keystoreFile = keystoreDir / KeystoreFileName
|
|
||||||
|
|
||||||
if dirExists(keystoreDir):
|
|
||||||
return err(KeystoreGenerationError(kind: DuplicateKeystoreDir,
|
|
||||||
error: "Keystore directory already exists"))
|
|
||||||
if fileExists(keystoreFile):
|
|
||||||
return err(KeystoreGenerationError(kind: DuplicateKeystoreFile,
|
|
||||||
error: "Keystore file already exists"))
|
|
||||||
|
|
||||||
let keyStore = createKeystore(kdfPbkdf2, rng, signingKey,
|
|
||||||
keypass, signingKeyPath,
|
|
||||||
mode = mode, salt = salt)
|
|
||||||
let encodedStorage = Json.encode(keyStore)
|
|
||||||
|
|
||||||
? createLocalValidatorFiles(secretsDir, validatorsDir,
|
|
||||||
keystoreDir,
|
|
||||||
secretsDir / keyName, keypass.str,
|
|
||||||
keystoreFile, encodedStorage)
|
|
||||||
ok()
|
|
||||||
|
|
||||||
proc generateDeposits*(cfg: RuntimeConfig,
|
|
||||||
rng: var HmacDrbgContext,
|
|
||||||
seed: KeySeed,
|
|
||||||
firstValidatorIdx, totalNewValidators: int,
|
|
||||||
validatorsDir: string,
|
|
||||||
secretsDir: string,
|
|
||||||
mode = Secure): Result[seq[DepositData],
|
|
||||||
KeystoreGenerationError] =
|
|
||||||
var deposits: seq[DepositData]
|
|
||||||
|
|
||||||
notice "Generating deposits", totalNewValidators, validatorsDir, secretsDir
|
|
||||||
|
|
||||||
# We'll reuse a single variable here to make the secret
|
|
||||||
# scrubbing (burnMem) easier to handle:
|
|
||||||
var baseKey = deriveMasterKey(seed)
|
|
||||||
defer: burnMem(baseKey)
|
|
||||||
baseKey = deriveChildKey(baseKey, baseKeyPath)
|
|
||||||
|
|
||||||
var
|
|
||||||
salt = rng.generateKeystoreSalt()
|
|
||||||
password = KeystorePass.init ncrutils.toHex(rng.generateBytes(32))
|
|
||||||
|
|
||||||
defer:
|
|
||||||
burnMem(salt)
|
|
||||||
burnMem(password)
|
|
||||||
|
|
||||||
let localValidatorsCount = totalNewValidators
|
|
||||||
for i in 0 ..< localValidatorsCount:
|
|
||||||
let validatorIdx = firstValidatorIdx + i
|
|
||||||
|
|
||||||
# We'll reuse a single variable here to make the secret
|
|
||||||
# scrubbing (burnMem) easier to handle:
|
|
||||||
var derivedKey = baseKey
|
|
||||||
defer: burnMem(derivedKey)
|
|
||||||
derivedKey = deriveChildKey(derivedKey, validatorIdx)
|
|
||||||
derivedKey = deriveChildKey(derivedKey, 0) # This is witdrawal key
|
|
||||||
let withdrawalPubKey = derivedKey.toPubKey
|
|
||||||
derivedKey = deriveChildKey(derivedKey, 0) # This is the signing key
|
|
||||||
let signingPubKey = derivedKey.toPubKey
|
|
||||||
|
|
||||||
? saveKeystore(rng, validatorsDir, secretsDir,
|
|
||||||
derivedKey, signingPubKey,
|
|
||||||
makeKeyPath(validatorIdx, signingKeyKind), password.str,
|
|
||||||
salt, mode)
|
|
||||||
|
|
||||||
deposits.add prepareDeposit(
|
|
||||||
cfg, withdrawalPubKey, derivedKey, signingPubKey)
|
|
||||||
|
|
||||||
ok deposits
|
|
||||||
|
|
||||||
type
|
|
||||||
LaunchPadDeposit* = object
|
|
||||||
pubkey*: ValidatorPubKey
|
|
||||||
withdrawal_credentials*: Eth2Digest
|
|
||||||
amount*: Gwei
|
|
||||||
signature*: ValidatorSig
|
|
||||||
deposit_message_root*: Eth2Digest
|
|
||||||
deposit_data_root*: Eth2Digest
|
|
||||||
fork_version*: Version
|
|
||||||
|
|
||||||
func init*(T: type LaunchPadDeposit,
|
|
||||||
cfg: RuntimeConfig, d: DepositData): T =
|
|
||||||
T(pubkey: d.pubkey,
|
|
||||||
withdrawal_credentials: d.withdrawal_credentials,
|
|
||||||
amount: d.amount,
|
|
||||||
signature: d.signature,
|
|
||||||
deposit_message_root: hash_tree_root(d as DepositMessage),
|
|
||||||
deposit_data_root: hash_tree_root(d),
|
|
||||||
fork_version: cfg.GENESIS_FORK_VERSION)
|
|
||||||
|
|
||||||
func `as`*(copied: LaunchPadDeposit, T: type DepositData): T =
|
|
||||||
T(pubkey: copied.pubkey,
|
|
||||||
withdrawal_credentials: copied.withdrawal_credentials,
|
|
||||||
amount: copied.amount,
|
|
||||||
signature: copied.signature)
|
|
||||||
|
|
Loading…
Reference in New Issue