Add show-private-keys flag to accounts-v2 list (#7487)

* Add show-private-keys flag to accoutns-v2 list

* fix fmt

* added tests and fixed return to 32 bytes

* deferred a lock and removed unused method

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
This commit is contained in:
Potuz
2020-10-15 13:08:52 -03:00
committed by GitHub
parent ec9c6f30bf
commit 1462b7e57e
8 changed files with 279 additions and 27 deletions

View File

@@ -36,13 +36,14 @@ func ListAccountsCli(cliCtx *cli.Context) error {
return errors.Wrap(err, "could not initialize keymanager")
}
showDepositData := cliCtx.Bool(flags.ShowDepositDataFlag.Name)
showPrivateKeys := cliCtx.Bool(flags.ShowPrivateKeysFlag.Name)
switch w.KeymanagerKind() {
case v2keymanager.Direct:
km, ok := keymanager.(*direct.Keymanager)
if !ok {
return errors.New("could not assert keymanager interface to concrete type")
}
if err := listDirectKeymanagerAccounts(cliCtx.Context, showDepositData, km); err != nil {
if err := listDirectKeymanagerAccounts(cliCtx.Context, showDepositData, showPrivateKeys, km); err != nil {
return errors.Wrap(err, "could not list validator accounts with direct keymanager")
}
case v2keymanager.Derived:
@@ -50,7 +51,7 @@ func ListAccountsCli(cliCtx *cli.Context) error {
if !ok {
return errors.New("could not assert keymanager interface to concrete type")
}
if err := listDerivedKeymanagerAccounts(cliCtx.Context, showDepositData, km); err != nil {
if err := listDerivedKeymanagerAccounts(cliCtx.Context, showDepositData, showPrivateKeys, km); err != nil {
return errors.Wrap(err, "could not list validator accounts with derived keymanager")
}
case v2keymanager.Remote:
@@ -70,6 +71,7 @@ func ListAccountsCli(cliCtx *cli.Context) error {
func listDirectKeymanagerAccounts(
ctx context.Context,
showDepositData bool,
showPrivateKeys bool,
keymanager *direct.Keymanager,
) error {
// We initialize the wallet's keymanager.
@@ -94,10 +96,20 @@ func listDirectKeymanagerAccounts(
if err != nil {
return errors.Wrap(err, "could not fetch validating public keys")
}
var privateKeys [][32]byte
if showPrivateKeys {
privateKeys, err = keymanager.FetchValidatingPrivateKeys(ctx)
if err != nil {
return errors.Wrap(err, "could not fetch private keys")
}
}
for i := 0; i < len(accountNames); i++ {
fmt.Println("")
fmt.Printf("%s | %s\n", au.BrightBlue(fmt.Sprintf("Account %d", i)).Bold(), au.BrightGreen(accountNames[i]).Bold())
fmt.Printf("%s %#x\n", au.BrightMagenta("[validating public key]").Bold(), pubKeys[i])
if showPrivateKeys {
fmt.Printf("%s %#x\n", au.BrightRed("[validating private key]").Bold(), privateKeys[i])
}
if !showDepositData {
continue
}
@@ -115,6 +127,7 @@ func listDirectKeymanagerAccounts(
func listDerivedKeymanagerAccounts(
ctx context.Context,
showDepositData bool,
showPrivateKeys bool,
keymanager *derived.Keymanager,
) error {
au := aurora.NewAurora(true)
@@ -124,10 +137,24 @@ func listDerivedKeymanagerAccounts(
if err != nil {
return errors.Wrap(err, "could not fetch validating public keys")
}
var validatingPrivateKeys [][32]byte
if showPrivateKeys {
validatingPrivateKeys, err = keymanager.FetchValidatingPrivateKeys(ctx)
if err != nil {
return errors.Wrap(err, "could not fetch validating private keys")
}
}
withdrawalPublicKeys, err := keymanager.FetchWithdrawalPublicKeys(ctx)
if err != nil {
return errors.Wrap(err, "could not fetch validating public keys")
}
var withdrawalPrivateKeys [][32]byte
if showPrivateKeys {
withdrawalPrivateKeys, err = keymanager.FetchWithdrawalPrivateKeys(ctx)
if err != nil {
return errors.Wrap(err, "could not fetch withdrawal private keys")
}
}
nextAccountNumber := keymanager.NextAccountNumber()
currentAccountNumber := nextAccountNumber
if nextAccountNumber > 0 {
@@ -153,10 +180,16 @@ func listDerivedKeymanagerAccounts(
// Retrieve the withdrawal key account metadata.
fmt.Printf("%s | %s\n", au.BrightBlue(fmt.Sprintf("Account %d", i)).Bold(), au.BrightGreen(accountNames[i]).Bold())
fmt.Printf("%s %#x\n", au.BrightMagenta("[withdrawal public key]").Bold(), withdrawalPublicKeys[i])
if showPrivateKeys {
fmt.Printf("%s %#x\n", au.BrightRed("[withdrawal private key]").Bold(), withdrawalPrivateKeys[i])
}
fmt.Printf("%s %s\n", au.BrightMagenta("[derivation path]").Bold(), withdrawalKeyPath)
// Retrieve the validating key account metadata.
fmt.Printf("%s %#x\n", au.BrightCyan("[validating public key]").Bold(), validatingPubKeys[i])
if showPrivateKeys {
fmt.Printf("%s %#x\n", au.BrightRed("[validating private key]").Bold(), validatingPrivateKeys[i])
}
fmt.Printf("%s %s\n", au.BrightCyan("[derivation path]").Bold(), validatingKeyPath)
if !showDepositData {

View File

@@ -71,7 +71,7 @@ func TestListAccounts_DirectKeymanager(t *testing.T) {
os.Stdout = writer
// We call the list direct keymanager accounts function.
require.NoError(t, listDirectKeymanagerAccounts(context.Background(), true /* show deposit data */, keymanager))
require.NoError(t, listDirectKeymanagerAccounts(context.Background(), true /* show deposit data */, true /*show private keys */, keymanager))
require.NoError(t, writer.Close())
out, err := ioutil.ReadAll(r)
@@ -89,28 +89,33 @@ func TestListAccounts_DirectKeymanager(t *testing.T) {
Showing 5 validator accounts
View the eth1 deposit transaction data for your accounts by running `validator accounts-v2 list --show-deposit-data
Account 0 | briefly-intimate-condor
[validating public key] 0x835980f321aa6c38cb4818f4e67ffd4e6b59e1e043f621ac8bb116dc32bbc9c950ff717edfa4d7b07b928ab072a2f9d2
Account 0 | fully-evolving-fawn
[validating public key] 0xa6669aa0381c06470b9a6faf8abf4194ad5148a62e461cbef5a6bc4d292026f58b992c4cf40e50552d301cef19da75b9
[validating private key] 0x50cabc13435fcbde9d240fe720aff84f8557a6c1c445211b904f1a9620668241
If you imported your account coming from the eth2 launchpad, you will find your deposit_data.json in the eth2.0-deposit-cli's validator_keys folder
Account 1 | notably-premium-treefrog
[validating public key] 0xb2e0179190c4270e8765ef2d38bfe89ea0d1be29ca6ba29212a2a34d4b286cae7571712593e0f30bc1645080afa3ce3c
Account 1 | preferably-mighty-heron
[validating public key] 0xa7ea37fa2e2272762ffed8486f09b13cd56d76cf03a2a3e75bc36bd1719add84c20597671750be5bc1ccd3dadfebc30f
[validating private key] 0x44563da0d11bc6a7219d18217cce8cdd064de3ebee5cdcf8d901c2fae7545116
If you imported your account coming from the eth2 launchpad, you will find your deposit_data.json in the eth2.0-deposit-cli's validator_keys folder
Account 2 | thankfully-sacred-hippo
[validating public key] 0x87941b935932ac77aeb2b825e67cf442ebf0b958341e6d604b756025c047bc9cdbb6a46e9e35ed7f2f2980cacb8b3b56
Account 2 | conversely-good-monitor
[validating public key] 0xa4c63619fb8cb87f6dd1686c9255f99c68066797bf284488ecbab64b1926d33eefdf96d1ee89ae4a89e84e7fb019d5e5
[validating private key] 0x4448d0ab17ecd73bbb636ddbfc89b181731f6cd88c33f2cecc0d04cba1a18447
If you imported your account coming from the eth2 launchpad, you will find your deposit_data.json in the eth2.0-deposit-cli's validator_keys folder
Account 3 | secondly-main-cod
[validating public key] 0xa7dd8c42a0478f995a3dccd990211486482ddb67fa3da848e08a71f9966027ecb99a8f1c3bb84520ec85a2267598ee7e
Account 3 | rarely-joint-mako
[validating public key] 0x91dd8d5bfc22aea398740ebcea66ced159df8d3f1a066d7aba9f0bef4ed6d9687fc1fd1c87bd2b6d12b0788dfb6a7d20
[validating private key] 0x4d1944bd7375185f70b3e70c68d9e6307f2009de3a4cf47ca5217443ddf81fc9
If you imported your account coming from the eth2 launchpad, you will find your deposit_data.json in the eth2.0-deposit-cli's validator_keys folder
Account 4 | regularly-safe-ghoul
[validating public key] 0x93833aeff64cd6861165e76615b7617d4ff87f33955970c37f7e7ddb3470ad040ef8508db744eef44c92f42928316e6f
Account 4 | mainly-useful-catfish
[validating public key] 0x83c4d722a98b599e2666bbe35146ff44800256190bc662f2dd5efbc0c4c0d57e5d297487a4f9c21a932d3b1b40e8379f
[validating private key] 0x284cd65030496bf82ee2d52963cd540a1abb2cc738b8164901bbe7e2df4d57bd
If you imported your account coming from the eth2 launchpad, you will find your deposit_data.json in the eth2.0-deposit-cli's validator_keys folder
@@ -119,10 +124,11 @@ func TestListAccounts_DirectKeymanager(t *testing.T) {
// Expected output format definition
const prologLength = 4
const accountLength = 5
const accountLength = 6
const epilogLength = 2
const nameOffset = 1
const keyOffset = 2
const privkeyOffset = 3
// Require the output has correct number of lines
lineCount := prologLength + accountLength*numAccounts + epilogLength
@@ -157,6 +163,19 @@ func TestListAccounts_DirectKeymanager(t *testing.T) {
keyFound := strings.Contains(lines[lineNumber], keyString)
assert.Equal(t, true, keyFound, "Public Key %s not found on line number %d", keyString, lineNumber)
}
// Get private keys and require the correct count
privKeys, err := keymanager.FetchValidatingPrivateKeys(cliCtx.Context)
require.NoError(t, err)
require.Equal(t, numAccounts, len(pubKeys))
// Assert that private keys are printed on the correct lines
for i, key := range privKeys {
lineNumber := prologLength + accountLength*i + privkeyOffset
keyString := fmt.Sprintf("%#x", key)
keyFound := strings.Contains(lines[lineNumber], keyString)
assert.Equal(t, true, keyFound, "Private Key %s not found on line number %d", keyString, lineNumber)
}
}
func TestListAccounts_DerivedKeymanager(t *testing.T) {
@@ -202,7 +221,7 @@ func TestListAccounts_DerivedKeymanager(t *testing.T) {
os.Stdout = writer
// We call the list direct keymanager accounts function.
require.NoError(t, listDerivedKeymanagerAccounts(cliCtx.Context, true /* show deposit data */, keymanager))
require.NoError(t, listDerivedKeymanagerAccounts(cliCtx.Context, true /* show deposit data */, true /*show private keys */, keymanager))
require.NoError(t, writer.Close())
out, err := ioutil.ReadAll(r)
@@ -219,39 +238,46 @@ func TestListAccounts_DerivedKeymanager(t *testing.T) {
(derivation format) m / purpose / coin_type / account_index / withdrawal_key / validating_key
Showing 2 validator accounts
Account 0 | uniformly-winning-gopher
[withdrawal public key] 0xad416c4ba9a729921036563ceb66a556692a21613a1a09f19260292dd9573ee50cb0614087d65bd48fe645232d2ca2a6
Account 0 | uniquely-sunny-tarpon
[withdrawal public key] 0xa5faa97252104b408340b5d8cae3fa01023fa4dc9e7c7b470821433cf3a2a18158410b7d8a6dcdcd176c6552c2526681
[withdrawal private key] 0x5266fd1f13d7af74614fde4fed3b664bfd529bc4ad91118e3db73647b99546df
[derivation path] m/12381/3600/0/0
[validating public key] 0xa9c2202dc0fdc74f00261947f325216246c34eafe76c327c5e2c88a5756c03a0f464b3b595af6511ffd212ecd45e07dd
[validating public key] 0xa7292d8f8d1c1f3d42cacefd2fc4cd3b82651be37c1eb790bbd294a874829f4b7e1c167345dcc1966cc844132b38097e
[validating private key] 0x590707187dae64b42b8d36a95f3d7e11313ddd8b8d871b09e478e08c9bc8740b
[derivation path] m/12381/3600/0/0/0
======================Eth1 Deposit Transaction Data=====================
0x22895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120a3b144364879ec579415348630371a16ad52314ba7342a0635425512c7d9fdaa0000000000000000000000000000000000000000000000000000000000000030a9c2202dc0fdc74f00261947f325216246c34eafe76c327c5e2c88a5756c03a0f464b3b595af6511ffd212ecd45e07dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000fc991cc3a9babe8fbf430d819c7d79f6350927114fa7ce6593a97c235aca2a0000000000000000000000000000000000000000000000000000000000000060a96f65132f70bf053779bedc3a943c2f1ac6a96e896ca7159521f7663968bb4c79a5307eb22ff58f8de35749c824382617654a8f072efb24cd77739538bebaef1ea5b0943188ecbc5e1785feb48c4e6e9d129478e40bafba8d9f21140de5da55
0x22895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001205a9e92992d6a97ad113d217fa35cbe0659c662afe913ffd3a3ba61d7473be5630000000000000000000000000000000000000000000000000000000000000030a7292d8f8d1c1f3d42cacefd2fc4cd3b82651be37c1eb790bbd294a874829f4b7e1c167345dcc1966cc844132b38097e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003b8f70706c37fb0b8dcbd95340889bad7d7f29121ea895052a8b216de95e480000000000000000000000000000000000000000000000000000000000000060b6727242b055448defbf54292c65e30ae28ca3aef8a07c8fe674abc0ca42a324be2e7592d3e45bba84ca364d7fe1f0ce073bf8b3692246395aa127cdbf93c64ae9ca48f85cb4b1e519f6821998181de1c7465b2bdcae4ddd0dbc2d02a56219d9
===================================================================
Account 1 | curiously-diverse-rooster
[withdrawal public key] 0x98d9bdf1fc2fc7c237d903e92c38e30f049412fba879923d9f6400fb8f0bc57e43fc5406917f66a445f7a0ab3214ac28
Account 1 | usually-obliging-pelican
[withdrawal public key] 0xb91840d33bb87338bb28605cff837acd50e43a174a8a6d3893108fb91217fa428c12f1b2a25cf3c7aca75d418bcf0384
[withdrawal private key] 0x72c5ffa7d08fb16cd35a9cb10494dfd49b46842ea1bcc1a4cf46b46680b66810
[derivation path] m/12381/3600/1/0
[validating public key] 0x849d5d2802d17cda4e9e79a7ca98534a5b35e165631ec8325b5cdcea0ec2a83c2cc1955ca3cc0c16a3b4f051473f471d
[validating public key] 0x8447f878b701dad4dfa5a884cebc4745b0e8f21340dc56c840826537764dcc54e2e68f80b8d4e5737180212a26211891
[validating private key] 0x2cd5b1cddc9d96e50a16bea05d0953447655e3dd59fa1bfefad467c73d6c164a
[derivation path] m/12381/3600/1/0/0
======================Eth1 Deposit Transaction Data=====================
0x22895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012027dc7cc27483f42ee9f98b9a48105239de731db98d81f32dfe690d221f4fec340000000000000000000000000000000000000000000000000000000000000030849d5d2802d17cda4e9e79a7ca98534a5b35e165631ec8325b5cdcea0ec2a83c2cc1955ca3cc0c16a3b4f051473f471d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000007c25d0d2051e8c77b9e2f0eb8184df4ca561f6597ad9029cb5a963bedf29000000000000000000000000000000000000000000000000000000000000006090fa0b1263164a0d4b3db35c6a4af0cfef19faf722fc44de263bc5a1a1ac8c0f2e8e7b18964798e9bc7a494f82cf735b0d5a7049e6bc0224c8a1000ef33c67e136d49560668d5ae6e95816997d9ed5165ee8ed5be02df63a9c88239e33551787
0x22895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200a0b9079c33cc40d602a50f5c51f6db30b0f959fc6f58048d6d43319fea6c09000000000000000000000000000000000000000000000000000000000000000308447f878b701dad4dfa5a884cebc4745b0e8f21340dc56c840826537764dcc54e2e68f80b8d4e5737180212a2621189100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000d6ac42bde23388e7428c1247364347c027c3507e461d68b851d506c60364cf0000000000000000000000000000000000000000000000000000000000000060801a2d432595164d7d88ae1695618db511d1507108573b8471098536b2b5a23f6711235f0a9c6fa65ac26cbd0f2d97e013e0c72ab6b5cff406c48d99ec0a2439aa9faa4557d20bb210d451519101616fa20b1ff2c67fae561cdff160fbc7dc98
===================================================================
*/
// Expected output format definition
const prologLength = 3
const accountLength = 12
const accountLength = 14
const epilogLength = 1
const nameOffset = 1
const keyOffset = 4
const depositOffset = 9
const keyOffset = 5
const validatingPrivateKeyOffset = 6
const withdrawalPrivateKeyOffset = 3
const depositOffset = 11
// Require the output has correct number of lines
lineCount := prologLength + accountLength*numAccounts + epilogLength
@@ -287,6 +313,32 @@ func TestListAccounts_DerivedKeymanager(t *testing.T) {
assert.Equal(t, true, keyFound, "Public Key %s not found on line number %d", keyString, lineNumber)
}
// Get validating private keys and require the correct count
validatingPrivKeys, err := keymanager.FetchValidatingPrivateKeys(cliCtx.Context)
require.NoError(t, err)
require.Equal(t, numAccounts, len(pubKeys))
// Assert that validating private keys are printed on the correct lines
for i, key := range validatingPrivKeys {
lineNumber := prologLength + accountLength*i + validatingPrivateKeyOffset
keyString := fmt.Sprintf("%#x", key)
keyFound := strings.Contains(lines[lineNumber], keyString)
assert.Equal(t, true, keyFound, "Validating Private Key %s not found on line number %d", keyString, lineNumber)
}
// Get withdrawal private keys and require the correct count
withdrawalPrivKeys, err := keymanager.FetchWithdrawalPrivateKeys(cliCtx.Context)
require.NoError(t, err)
require.Equal(t, numAccounts, len(pubKeys))
// Assert that withdrawal private keys are printed on the correct lines
for i, key := range withdrawalPrivKeys {
lineNumber := prologLength + accountLength*i + withdrawalPrivateKeyOffset
keyString := fmt.Sprintf("%#x", key)
keyFound := strings.Contains(lines[lineNumber], keyString)
assert.Equal(t, true, keyFound, "Withdrawal Private Key %s not found on line number %d", keyString, lineNumber)
}
// Assert that deposit data are printed on the correct lines
for i, deposit := range depositDataForAccounts {
lineNumber := prologLength + accountLength*i + depositOffset

View File

@@ -73,6 +73,7 @@ this command outputs a deposit data string which is required to become a validat
flags.WalletDirFlag,
flags.WalletPasswordFileFlag,
flags.ShowDepositDataFlag,
flags.ShowPrivateKeysFlag,
featureconfig.AltonaTestnet,
featureconfig.OnyxTestnet,
featureconfig.MedallaTestnet,

View File

@@ -155,6 +155,12 @@ var (
Usage: "Display raw eth1 tx deposit data for validator accounts-v2",
Value: false,
}
// ShowPrivateKeysFlag for accounts-v2.
ShowPrivateKeysFlag = &cli.BoolFlag{
Name: "show-private-keys",
Usage: "Display the private keys for validator accounts-v2",
Value: false,
}
// NumAccountsFlag defines the amount of accounts to generate for derived wallets.
NumAccountsFlag = &cli.IntFlag{
Name: "num-accounts",

View File

@@ -369,6 +369,26 @@ func (dr *Keymanager) FetchValidatingPublicKeys(_ context.Context) ([][48]byte,
return result, nil
}
// FetchValidatingPrivateKeys fetches the list of validating private keys from the keymanager.
func (dr *Keymanager) FetchValidatingPrivateKeys(ctx context.Context) ([][32]byte, error) {
lock.RLock()
defer lock.RUnlock()
privKeys := make([][32]byte, len(secretKeysCache))
pubKeys, err := dr.FetchValidatingPublicKeys(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve public keys")
}
for i, pk := range pubKeys {
seckey, ok := secretKeysCache[pk]
if !ok {
return nil, errors.New("Could not fetch private key")
}
privKeys[i] = bytesutil.ToBytes32(seckey.Marshal())
}
return privKeys, nil
}
// FetchWithdrawalPublicKeys fetches the list of withdrawal public keys from keymanager
func (dr *Keymanager) FetchWithdrawalPublicKeys(_ context.Context) ([][48]byte, error) {
publicKeys := make([][48]byte, 0)
@@ -376,13 +396,27 @@ func (dr *Keymanager) FetchWithdrawalPublicKeys(_ context.Context) ([][48]byte,
withdrawalKeyPath := fmt.Sprintf(WithdrawalKeyDerivationPathTemplate, i)
withdrawalKey, err := util.PrivateKeyFromSeedAndPath(dr.seed, withdrawalKeyPath)
if err != nil {
return nil, errors.Wrapf(err, "failed to create validating key for account %d", i)
return nil, errors.Wrapf(err, "failed to create withdrawal key for account %d", i)
}
publicKeys = append(publicKeys, bytesutil.ToBytes48(withdrawalKey.PublicKey().Marshal()))
}
return publicKeys, nil
}
// FetchWithdrawalPrivateKeys fetches the list of withdrawal private keys from the keymanager.
func (dr *Keymanager) FetchWithdrawalPrivateKeys(ctx context.Context) ([][32]byte, error) {
privKeys := make([][32]byte, 0)
for i := uint64(0); i < dr.seedCfg.NextAccount; i++ {
withdrawalKeyPath := fmt.Sprintf(WithdrawalKeyDerivationPathTemplate, i)
withdrawalKey, err := util.PrivateKeyFromSeedAndPath(dr.seed, withdrawalKeyPath)
if err != nil {
return nil, errors.Wrapf(err, "failed to create withdrawal key for account %d", i)
}
privKeys = append(privKeys, bytesutil.ToBytes32(withdrawalKey.Marshal()))
}
return privKeys, nil
}
// DepositDataForAccount with a given index returns the RLP encoded eth1 deposit transaction data.
func (dr *Keymanager) DepositDataForAccount(accountIndex uint64) ([]byte, error) {
withdrawalKeyPath := fmt.Sprintf(WithdrawalKeyDerivationPathTemplate, accountIndex)

View File

@@ -128,6 +128,80 @@ func TestDerivedKeymanager_FetchValidatingPublicKeys(t *testing.T) {
}
}
func TestDerivedKeymanager_FetchValidatingPrivateKeys(t *testing.T) {
wallet := &mock.Wallet{
Files: make(map[string]map[string][]byte),
AccountPasswords: make(map[string]string),
WalletPassword: "secretPassw0rd$1999",
}
dr := &Keymanager{
wallet: wallet,
seedCfg: &SeedConfig{
NextAccount: 0,
},
seed: make([]byte, 32),
}
require.NoError(t, dr.initializeKeysCachesFromSeed())
// First, generate accounts and their keystore.json files.
ctx := context.Background()
numAccounts := 20
wantedPrivateKeys := make([][32]byte, numAccounts)
for i := 0; i < numAccounts; i++ {
_, _, err := dr.CreateAccount(ctx)
require.NoError(t, err)
validatingKeyPath := fmt.Sprintf(ValidatingKeyDerivationPathTemplate, i)
validatingKey, err := util.PrivateKeyFromSeedAndPath(dr.seed, validatingKeyPath)
require.NoError(t, err)
wantedPrivateKeys[i] = bytesutil.ToBytes32(validatingKey.Marshal())
}
privateKeys, err := dr.FetchValidatingPrivateKeys(ctx)
require.NoError(t, err)
require.Equal(t, numAccounts, len(privateKeys))
// FetchValidatingPrivateKeys is also used in generating the output of account list
// therefore the results must be in the same order as the order in which the accounts were derived
for i, key := range wantedPrivateKeys {
assert.Equal(t, key, privateKeys[i])
}
}
func TestDerivedKeymanager_FetchWithdrawalPrivateKeys(t *testing.T) {
wallet := &mock.Wallet{
Files: make(map[string]map[string][]byte),
AccountPasswords: make(map[string]string),
WalletPassword: "secretPassw0rd$1999",
}
dr := &Keymanager{
wallet: wallet,
seedCfg: &SeedConfig{
NextAccount: 0,
},
seed: make([]byte, 32),
}
require.NoError(t, dr.initializeKeysCachesFromSeed())
// First, generate accounts and their keystore.json files.
ctx := context.Background()
numAccounts := 20
wantedPrivateKeys := make([][32]byte, numAccounts)
for i := 0; i < numAccounts; i++ {
_, _, err := dr.CreateAccount(ctx)
require.NoError(t, err)
withdrawalKeyPath := fmt.Sprintf(WithdrawalKeyDerivationPathTemplate, i)
withdrawalKey, err := util.PrivateKeyFromSeedAndPath(dr.seed, withdrawalKeyPath)
require.NoError(t, err)
wantedPrivateKeys[i] = bytesutil.ToBytes32(withdrawalKey.Marshal())
}
privateKeys, err := dr.FetchWithdrawalPrivateKeys(ctx)
require.NoError(t, err)
require.Equal(t, numAccounts, len(privateKeys))
// FetchWithdrawalPrivateKeys is also used in generating the output of account list
// therefore the results must be in the same order as the order in which the accounts were derived
for i, key := range wantedPrivateKeys {
assert.Equal(t, key, privateKeys[i])
}
}
func TestDerivedKeymanager_Sign(t *testing.T) {
wallet := &mock.Wallet{
Files: make(map[string]map[string][]byte),

View File

@@ -349,6 +349,25 @@ func (dr *Keymanager) FetchValidatingPublicKeys(ctx context.Context) ([][48]byte
return result, nil
}
// FetchValidatingPrivateKeys fetches the list of private keys from the secret keys cache
func (dr *Keymanager) FetchValidatingPrivateKeys(ctx context.Context) ([][32]byte, error) {
lock.RLock()
defer lock.RUnlock()
privKeys := make([][32]byte, len(secretKeysCache))
pubKeys, err := dr.FetchValidatingPublicKeys(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve public keys")
}
for i, pk := range pubKeys {
seckey, ok := secretKeysCache[pk]
if !ok {
return nil, errors.New("Could not fetch private key")
}
privKeys[i] = bytesutil.ToBytes32(seckey.Marshal())
}
return privKeys, nil
}
// Sign signs a message using a validator key.
func (dr *Keymanager) Sign(ctx context.Context, req *validatorpb.SignRequest) (bls.Signature, error) {
ctx, span := trace.StartSpan(ctx, "keymanager.Sign")

View File

@@ -145,6 +145,39 @@ func TestDirectKeymanager_FetchValidatingPublicKeys(t *testing.T) {
}
}
func TestDirectKeymanager_FetchValidatingPrivateKeys(t *testing.T) {
password := "secretPassw0rd$1999"
wallet := &mock.Wallet{
Files: make(map[string]map[string][]byte),
WalletPassword: password,
}
dr := &Keymanager{
wallet: wallet,
accountsStore: &AccountStore{},
}
// First, generate accounts and their keystore.json files.
ctx := context.Background()
numAccounts := 10
wantedPrivateKeys := make([][32]byte, numAccounts)
for i := 0; i < numAccounts; i++ {
privKey := bls.RandKey()
privKeyData := privKey.Marshal()
pubKey := bytesutil.ToBytes48(privKey.PublicKey().Marshal())
wantedPrivateKeys[i] = bytesutil.ToBytes32(privKeyData)
dr.accountsStore.PublicKeys = append(dr.accountsStore.PublicKeys, pubKey[:])
dr.accountsStore.PrivateKeys = append(dr.accountsStore.PrivateKeys, privKeyData)
}
require.NoError(t, dr.initializeKeysCachesFromKeystore())
privateKeys, err := dr.FetchValidatingPrivateKeys(ctx)
require.NoError(t, err)
assert.Equal(t, numAccounts, len(privateKeys))
// FetchValidatingPrivateKeys is also used in generating the output of account list
// therefore the results must be in the same order as the order in which the accounts were created
for i, key := range wantedPrivateKeys {
assert.Equal(t, key, privateKeys[i])
}
}
func TestDirectKeymanager_Sign(t *testing.T) {
password := "secretPassw0rd$1999"
wallet := &mock.Wallet{