From 651ca47f3761be7a0a67f7adae48474c44e1785e Mon Sep 17 00:00:00 2001 From: "Andreas M. Antonopoulos" Date: Sat, 9 Nov 2019 11:37:03 -0500 Subject: [PATCH] Warn user before doing SCB restore SCB restore closes all open channels. We need to warn users that this is what will happen if they try to do an SCB restore. --- cmd/lncli/commands.go | 110 +++++++++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 29 deletions(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 48de53ce..a021d844 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -1401,6 +1401,86 @@ func create(ctx *cli.Context) error { client, cleanUp := getWalletUnlockerClient(ctx) defer cleanUp() + var ( + chanBackups *lnrpc.ChanBackupSnapshot + + // We use var restoreSCB to track if we will be including an SCB + // recovery in the init wallet request. + restoreSCB = false + ) + + backups, err := parseChanBackups(ctx) + + // We'll check to see if the user provided any static channel backups (SCB), + // if so, we will warn the user that SCB recovery closes all open channels + // and ask them to confirm their intention. + // If the user agrees, we'll add the SCB recovery onto the final init wallet + // request. + switch { + // parseChanBackups returns an errMissingBackup error (which we ignore) if + // the user did not request a SCB recovery. + case err == errMissingChanBackup: + + // Passed an invalid channel backup file. + case err != nil: + return fmt.Errorf("unable to parse chan backups: %v", err) + + // We have an SCB recovery option with a valid backup file. + default: + + warningLoop: + for { + + fmt.Println() + fmt.Printf("WARNING: You are attempting to restore from a " + + "static channel backup (SCB) file.\nThis action will CLOSE " + + "all currently open channels, and you will pay on-chain fees." + + "\n\nAre you sure you want to recover funds from a" + + " static channel backup? (Enter y/n): ") + + reader := bufio.NewReader(os.Stdin) + answer, err := reader.ReadString('\n') + if err != nil { + return err + } + + answer = strings.TrimSpace(answer) + answer = strings.ToLower(answer) + + switch answer { + case "y": + restoreSCB = true + break warningLoop + case "n": + restoreSCB = false + break warningLoop + } + } + } + + // Proceed with SCB recovery. + if restoreSCB { + fmt.Println("Static Channel Backup (SCB) recovery selected!") + if backups != nil { + switch { + case backups.GetChanBackups() != nil: + singleBackup := backups.GetChanBackups() + chanBackups = &lnrpc.ChanBackupSnapshot{ + SingleChanBackups: singleBackup, + } + + case backups.GetMultiChanBackup() != nil: + multiBackup := backups.GetMultiChanBackup() + chanBackups = &lnrpc.ChanBackupSnapshot{ + MultiChanBackup: &lnrpc.MultiChanBackup{ + MultiChanBackup: multiBackup, + }, + } + } + } + + } + walletPassword, err := capturePassword( "Input wallet password: ", false, walletunlocker.ValidatePassword, ) @@ -1569,34 +1649,6 @@ mnemonicCheck: fmt.Println("\n!!!YOU MUST WRITE DOWN THIS SEED TO BE ABLE TO " + "RESTORE THE WALLET!!!") - // We'll also check to see if they provided any static channel backups, - // if so, then we'll also tack these onto the final init wallet request. - // We can ignore the errMissingChanBackup error as it's an optional - // field. - backups, err := parseChanBackups(ctx) - if err != nil && err != errMissingChanBackup { - return fmt.Errorf("unable to parse chan backups: %v", err) - } - - var chanBackups *lnrpc.ChanBackupSnapshot - if backups != nil { - switch { - case backups.GetChanBackups() != nil: - singleBackup := backups.GetChanBackups() - chanBackups = &lnrpc.ChanBackupSnapshot{ - SingleChanBackups: singleBackup, - } - - case backups.GetMultiChanBackup() != nil: - multiBackup := backups.GetMultiChanBackup() - chanBackups = &lnrpc.ChanBackupSnapshot{ - MultiChanBackup: &lnrpc.MultiChanBackup{ - MultiChanBackup: multiBackup, - }, - } - } - } - // With either the user's prior cipher seed, or a newly generated one, // we'll go ahead and initialize the wallet. req := &lnrpc.InitWalletRequest{ @@ -2404,7 +2456,7 @@ var sendToRouteCommand = cli.Command{ Send a payment over Lightning using a specific route. One must specify the route to attempt and the payment hash. This command can even be chained with the response to queryroutes or buildroute. This command - can be used to implement channel rebalancing by crafting a self-route, + can be used to implement channel rebalancing by crafting a self-route, or even atomic swaps using a self-route that crosses multiple chains. There are three ways to specify a route: