mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-07-28 05:42:37 +02:00
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:
@@ -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
|
// 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 (
|
var (
|
||||||
hasMnemonic bool
|
hasMnemonic bool
|
||||||
|
hasXprv bool
|
||||||
)
|
)
|
||||||
|
|
||||||
mnemonicCheck:
|
mnemonicCheck:
|
||||||
for {
|
for {
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Printf("Do you have an existing cipher seed " +
|
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)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
answer, err := reader.ReadString('\n')
|
answer, err := reader.ReadString('\n')
|
||||||
@@ -240,20 +245,28 @@ mnemonicCheck:
|
|||||||
case "y":
|
case "y":
|
||||||
hasMnemonic = true
|
hasMnemonic = true
|
||||||
break mnemonicCheck
|
break mnemonicCheck
|
||||||
|
|
||||||
|
case "x":
|
||||||
|
hasXprv = true
|
||||||
|
break mnemonicCheck
|
||||||
|
|
||||||
case "n":
|
case "n":
|
||||||
hasMnemonic = false
|
|
||||||
break mnemonicCheck
|
break mnemonicCheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user *does* have an existing seed they want to use, then
|
// If the user *does* have an existing seed or root key they want to
|
||||||
// we'll read that in directly from the terminal.
|
// use, then we'll read that in directly from the terminal.
|
||||||
var (
|
var (
|
||||||
cipherSeedMnemonic []string
|
cipherSeedMnemonic []string
|
||||||
aezeedPass []byte
|
aezeedPass []byte
|
||||||
recoveryWindow int32
|
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
|
// We'll now prompt the user to enter in their 24-word
|
||||||
// mnemonic.
|
// mnemonic.
|
||||||
fmt.Printf("Input your 24-word mnemonic separated by spaces: ")
|
fmt.Printf("Input your 24-word mnemonic separated by spaces: ")
|
||||||
@@ -292,7 +305,33 @@ mnemonicCheck:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// Otherwise, if the user doesn't have a mnemonic that they
|
||||||
// want to use, we'll generate a fresh one with the GenSeed
|
// want to use, we'll generate a fresh one with the GenSeed
|
||||||
// command.
|
// command.
|
||||||
@@ -325,17 +364,21 @@ mnemonicCheck:
|
|||||||
|
|
||||||
// Before we initialize the wallet, we'll display the cipher seed to
|
// Before we initialize the wallet, we'll display the cipher seed to
|
||||||
// the user so they can write it down.
|
// 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,
|
// With either the user's prior cipher seed, or a newly generated one,
|
||||||
// we'll go ahead and initialize the wallet.
|
// we'll go ahead and initialize the wallet.
|
||||||
req := &lnrpc.InitWalletRequest{
|
req := &lnrpc.InitWalletRequest{
|
||||||
WalletPassword: walletPassword,
|
WalletPassword: walletPassword,
|
||||||
CipherSeedMnemonic: cipherSeedMnemonic,
|
CipherSeedMnemonic: cipherSeedMnemonic,
|
||||||
AezeedPassphrase: aezeedPass,
|
AezeedPassphrase: aezeedPass,
|
||||||
RecoveryWindow: recoveryWindow,
|
ExtendedMasterKey: extendedRootKey,
|
||||||
ChannelBackups: chanBackups,
|
ExtendedMasterKeyBirthdayTimestamp: extendedRootKeyBirthday,
|
||||||
StatelessInit: statelessInit,
|
RecoveryWindow: recoveryWindow,
|
||||||
|
ChannelBackups: chanBackups,
|
||||||
|
StatelessInit: statelessInit,
|
||||||
}
|
}
|
||||||
response, err := client.InitWallet(ctxc, req)
|
response, err := client.InitWallet(ctxc, req)
|
||||||
if err != nil {
|
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) {
|
func printCipherSeedWords(mnemonicWords []string) {
|
||||||
fmt.Println("!!!YOU MUST WRITE DOWN THIS SEED TO BE ABLE TO " +
|
fmt.Println("!!!YOU MUST WRITE DOWN THIS SEED TO BE ABLE TO " +
|
||||||
"RESTORE THE WALLET!!!")
|
"RESTORE THE WALLET!!!")
|
||||||
|
Reference in New Issue
Block a user