lncli: add extended master root key to create command

To allow users to restore a wallet from an existing extended master root
key, we accept one of three answers when asking for an existing seed.
This commit is contained in:
Oliver Gugger 2020-10-24 23:18:54 +02:00
parent 370d056863
commit bbd5980d42
No known key found for this signature in database
GPG Key ID: 8E4256593F177720

@ -214,16 +214,21 @@ func create(ctx *cli.Context) error {
}
// Next, we'll see if the user has 24-word mnemonic they want to use to
// derive a seed within the wallet.
// derive a seed within the wallet or if they want to specify an
// extended master root key (xprv) directly.
var (
hasMnemonic bool
hasXprv bool
)
mnemonicCheck:
for {
fmt.Println()
fmt.Printf("Do you have an existing cipher seed " +
"mnemonic you want to use? (Enter y/n): ")
"mnemonic or extended master root key you want to " +
"use?\nEnter 'y' to use an existing cipher seed " +
"mnemonic, 'x' to use an extended master root key " +
"\nor 'n' to create a new seed (Enter y/x/n): ")
reader := bufio.NewReader(os.Stdin)
answer, err := reader.ReadString('\n')
@ -240,20 +245,28 @@ mnemonicCheck:
case "y":
hasMnemonic = true
break mnemonicCheck
case "x":
hasXprv = true
break mnemonicCheck
case "n":
hasMnemonic = false
break mnemonicCheck
}
}
// If the user *does* have an existing seed they want to use, then
// we'll read that in directly from the terminal.
// If the user *does* have an existing seed or root key they want to
// use, then we'll read that in directly from the terminal.
var (
cipherSeedMnemonic []string
aezeedPass []byte
recoveryWindow int32
cipherSeedMnemonic []string
aezeedPass []byte
extendedRootKey string
extendedRootKeyBirthday uint64
recoveryWindow int32
)
if hasMnemonic {
switch {
// Use an existing cipher seed mnemonic in the aezeed format.
case hasMnemonic:
// We'll now prompt the user to enter in their 24-word
// mnemonic.
fmt.Printf("Input your 24-word mnemonic separated by spaces: ")
@ -292,7 +305,33 @@ mnemonicCheck:
if err != nil {
return err
}
} else {
// Use an existing extended master root key to create the wallet.
case hasXprv:
// We'll now prompt the user to enter in their extended master
// root key.
fmt.Printf("Input your extended master root key (usually " +
"starting with xprv... on mainnet): ")
reader := bufio.NewReader(os.Stdin)
extendedRootKey, err = reader.ReadString('\n')
if err != nil {
return err
}
extendedRootKey = strings.TrimSpace(extendedRootKey)
extendedRootKeyBirthday, err = askBirthdayTimestamp()
if err != nil {
return err
}
recoveryWindow, err = askRecoveryWindow()
if err != nil {
return err
}
// Neither a seed nor a master root key was specified, the user wants
// to create a new seed.
default:
// Otherwise, if the user doesn't have a mnemonic that they
// want to use, we'll generate a fresh one with the GenSeed
// command.
@ -325,17 +364,21 @@ mnemonicCheck:
// Before we initialize the wallet, we'll display the cipher seed to
// the user so they can write it down.
printCipherSeedWords(cipherSeedMnemonic)
if len(cipherSeedMnemonic) > 0 {
printCipherSeedWords(cipherSeedMnemonic)
}
// With either the user's prior cipher seed, or a newly generated one,
// we'll go ahead and initialize the wallet.
req := &lnrpc.InitWalletRequest{
WalletPassword: walletPassword,
CipherSeedMnemonic: cipherSeedMnemonic,
AezeedPassphrase: aezeedPass,
RecoveryWindow: recoveryWindow,
ChannelBackups: chanBackups,
StatelessInit: statelessInit,
WalletPassword: walletPassword,
CipherSeedMnemonic: cipherSeedMnemonic,
AezeedPassphrase: aezeedPass,
ExtendedMasterKey: extendedRootKey,
ExtendedMasterKeyBirthdayTimestamp: extendedRootKeyBirthday,
RecoveryWindow: recoveryWindow,
ChannelBackups: chanBackups,
StatelessInit: statelessInit,
}
response, err := client.InitWallet(ctxc, req)
if err != nil {
@ -648,6 +691,38 @@ func askRecoveryWindow() (int32, error) {
}
}
func askBirthdayTimestamp() (uint64, error) {
for {
fmt.Println()
fmt.Printf("Input an optional wallet birthday unix timestamp " +
"of first block to start scanning from (default 0): ")
reader := bufio.NewReader(os.Stdin)
answer, err := reader.ReadString('\n')
if err != nil {
return 0, err
}
fmt.Println()
answer = strings.TrimSpace(answer)
if len(answer) == 0 {
return 0, nil
}
birthdayTimestamp, err := strconv.ParseUint(answer, 10, 64)
if err != nil {
fmt.Printf("Unable to parse birthday timestamp: %v\n",
err)
continue
}
return birthdayTimestamp, nil
}
}
func printCipherSeedWords(mnemonicWords []string) {
fmt.Println("!!!YOU MUST WRITE DOWN THIS SEED TO BE ABLE TO " +
"RESTORE THE WALLET!!!")