diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 989afae19..b0e3c03c8 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -2314,8 +2314,9 @@ func exportChanBackup(ctx *cli.Context) error { } var ( - err error - chanPointStr string + err error + chanPointStr string + outputFileName string ) args := ctx.Args() @@ -2330,6 +2331,10 @@ func exportChanBackup(ctx *cli.Context) error { return fmt.Errorf("must specify chan_point if --all isn't set") } + if ctx.IsSet("output_file") { + outputFileName = ctx.String("output_file") + } + if chanPointStr != "" { chanPointRPC, err := parseChanPoint(chanPointStr) if err != nil { @@ -2357,6 +2362,14 @@ func exportChanBackup(ctx *cli.Context) error { Index: chanPointRPC.OutputIndex, } + if outputFileName != "" { + return os.WriteFile( + outputFileName, + chanBackup.ChanBackup, + 0666, + ) + } + printJSON(struct { ChanPoint string `json:"chan_point"` ChanBackup []byte `json:"chan_backup"` @@ -2378,9 +2391,9 @@ func exportChanBackup(ctx *cli.Context) error { return err } - if ctx.IsSet("output_file") { - return ioutil.WriteFile( - ctx.String("output_file"), + if outputFileName != "" { + return os.WriteFile( + outputFileName, chanBackup.MultiChanBackup.MultiChanBackup, 0666, ) @@ -2416,13 +2429,16 @@ var verifyChanBackupCommand = cli.Command{ backup for integrity. This is useful when a user has a backup, but is unsure as to if it's valid or for the target node. - The command will accept backups in one of three forms: + The command will accept backups in one of four forms: * A single channel packed SCB, which can be obtained from exportchanbackup. This should be passed in hex encoded format. * A packed multi-channel SCB, which couples several individual static channel backups in single blob. + + * A file path which points to a packed single-channel backup within a + file, using the same format that lnd does in its channel.backup file. * A file path which points to a packed multi-channel backup within a file, using the same format that lnd does in its channel.backup @@ -2439,6 +2455,13 @@ var verifyChanBackupCommand = cli.Command{ Usage: "a hex encoded multi-channel backup obtained " + "from exportchanbackup", }, + + cli.StringFlag{ + Name: "single_file", + Usage: "the path to a single-channel backup file", + TakesFile: true, + }, + cli.StringFlag{ Name: "multi_file", Usage: "the path to a multi-channel back up file", @@ -2499,7 +2522,7 @@ var restoreChanBackupCommand = cli.Command{ channel. If successful, this command will allows the user to recover the settled funds stored in the recovered channels. - The command will accept backups in one of three forms: + The command will accept backups in one of four forms: * A single channel packed SCB, which can be obtained from exportchanbackup. This should be passed in hex encoded format. @@ -2507,6 +2530,10 @@ var restoreChanBackupCommand = cli.Command{ * A packed multi-channel SCB, which couples several individual static channel backups in single blob. + * A file path which points to a packed single-channel backup within + a file, using the same format that lnd does in its channel.backup + file. + * A file path which points to a packed multi-channel backup within a file, using the same format that lnd does in its channel.backup file. @@ -2522,6 +2549,13 @@ var restoreChanBackupCommand = cli.Command{ Usage: "a hex encoded multi-channel backup obtained " + "from exportchanbackup", }, + + cli.StringFlag{ + Name: "single_file", + Usage: "the path to a single-channel backup file", + TakesFile: true, + }, + cli.StringFlag{ Name: "multi_file", Usage: "the path to a multi-channel back up file", @@ -2573,6 +2607,23 @@ func parseChanBackups(ctx *cli.Context) (*lnrpc.RestoreChanBackupRequest, error) }, }, nil + case ctx.IsSet("single_file"): + packedSingle, err := os.ReadFile(ctx.String("single_file")) + if err != nil { + return nil, fmt.Errorf("unable to decode single "+ + "packed backup: %v", err) + } + + return &lnrpc.RestoreChanBackupRequest{ + Backup: &lnrpc.RestoreChanBackupRequest_ChanBackups{ + ChanBackups: &lnrpc.ChannelBackups{ + ChanBackups: []*lnrpc.ChannelBackup{{ + ChanBackup: packedSingle, + }}, + }, + }, + }, nil + case ctx.IsSet("multi_file"): packedMulti, err := ioutil.ReadFile(ctx.String("multi_file")) if err != nil { diff --git a/docs/release-notes/release-notes-0.16.1.md b/docs/release-notes/release-notes-0.16.1.md index afb702380..6b6cd1346 100644 --- a/docs/release-notes/release-notes-0.16.1.md +++ b/docs/release-notes/release-notes-0.16.1.md @@ -8,6 +8,9 @@ * [Add time_lock_delta overflow check for UpdateChannelPolicy](https://github.com/lightningnetwork/lnd/pull/7350) that ensure `time_lock_delta` is greater or equal than `0` and less or equal than `65535` +* [Added ability to backup, verify and + restore single channels](https://github.com/lightningnetwork/lnd/pull/7437) + to and from a file on disk. ## Watchtowers @@ -39,6 +42,7 @@ # Contributors (Alphabetical Order) +* ardevd * Elle Mouton * Oliver Gugger * Tommy Volk