From 7b2eb0b5ff05d3b1c86b76e04fb97d85e2ad91c2 Mon Sep 17 00:00:00 2001 From: Boris Nagaev Date: Sun, 5 Nov 2023 19:43:33 -0300 Subject: [PATCH] rpcserver, chanbackup: save CloseTx in chanbackup --- chanbackup/backup.go | 63 ++++++++++++++++++++++++++++++++++++++++++-- chanbackup/pubsub.go | 27 ++++++++++++++++--- rpcserver.go | 3 +++ server.go | 2 ++ 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/chanbackup/backup.go b/chanbackup/backup.go index 9a61d23cd3..e1142551e6 100644 --- a/chanbackup/backup.go +++ b/chanbackup/backup.go @@ -1,13 +1,16 @@ package chanbackup import ( + "bytes" "fmt" "net" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/lnwallet" ) // LiveChannelSource is an interface that allows us to query for the set of @@ -53,11 +56,44 @@ func assembleChanBackup(addrSource AddressSource, return &single, nil } +func buildCloseTx(targetChan *channeldb.OpenChannel, signer input.Signer) ([]byte, error) { + chanMachine, err := lnwallet.NewLightningChannel(signer, targetChan, nil) + if err != nil { + return nil, fmt.Errorf("lnwallet.NewLightningChannel failed: %w", err) + } + closeSummary, err := chanMachine.GetLocalForceCloseSummary() + if err != nil { + return nil, fmt.Errorf("GetLocalForceCloseSummary failed: %w", err) + } + var txBuf bytes.Buffer + if err := closeSummary.CloseTx.Serialize(&txBuf); err != nil { + return nil, fmt.Errorf("CloseTx.Serialize failed: %w", err) + } + return txBuf.Bytes(), nil +} + +type BackupConfig struct { + signer input.Signer +} + +type BackupOption func(*BackupConfig) + +func WithCloseTx(signer input.Signer) BackupOption { + return func(c *BackupConfig) { + c.signer = signer + } +} + // FetchBackupForChan attempts to create a plaintext static channel backup for // the target channel identified by its channel point. If we're unable to find // the target channel, then an error will be returned. func FetchBackupForChan(chanPoint wire.OutPoint, chanSource LiveChannelSource, - addrSource AddressSource) (*Single, error) { + addrSource AddressSource, options ...BackupOption) (*Single, error) { + + var config BackupConfig + for _, opt := range options { + opt(&config) + } // First, we'll query the channel source to see if the channel is known // and open within the database. @@ -75,13 +111,27 @@ func FetchBackupForChan(chanPoint wire.OutPoint, chanSource LiveChannelSource, return nil, fmt.Errorf("unable to create chan backup: %v", err) } + if config.signer != nil { + // Add CloseTx. + closeTx, err := buildCloseTx(targetChan, config.signer) + if err != nil { + return nil, fmt.Errorf("unable to create close tx for ChannelPoint(%v): %w", targetChan, err) + } + staticChanBackup.CloseTx = closeTx + } + return staticChanBackup, nil } // FetchStaticChanBackups will return a plaintext static channel back up for // all known active/open channels within the passed channel source. func FetchStaticChanBackups(chanSource LiveChannelSource, - addrSource AddressSource) ([]Single, error) { + addrSource AddressSource, options ...BackupOption) ([]Single, error) { + + var config BackupConfig + for _, opt := range options { + opt(&config) + } // First, we'll query the backup source for information concerning all // currently open and available channels. @@ -100,6 +150,15 @@ func FetchStaticChanBackups(chanSource LiveChannelSource, return nil, err } + if config.signer != nil { + // Add CloseTx. + closeTx, err := buildCloseTx(openChan, config.signer) + if err != nil { + return nil, fmt.Errorf("unable to create close tx for ChannelPoint(%v): %w", openChan, err) + } + chanBackup.CloseTx = closeTx + } + staticChanBackups = append(staticChanBackups, *chanBackup) } diff --git a/chanbackup/pubsub.go b/chanbackup/pubsub.go index 3e1580ddd2..af8f3011bf 100644 --- a/chanbackup/pubsub.go +++ b/chanbackup/pubsub.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" ) @@ -93,6 +94,9 @@ type SubSwapper struct { // multi backup. keyRing keychain.KeyRing + // signer is used to sign CloseTx. + signer input.Signer + Swapper quit chan struct{} @@ -104,7 +108,13 @@ type SubSwapper struct { // updates, pack a multi backup, and swap the current best backup from its // storage location. func NewSubSwapper(startingChans []Single, chanNotifier ChannelNotifier, - keyRing keychain.KeyRing, backupSwapper Swapper) (*SubSwapper, error) { + keyRing keychain.KeyRing, backupSwapper Swapper, + options ...BackupOption) (*SubSwapper, error) { + + var config BackupConfig + for _, opt := range options { + opt(&config) + } // First, we'll subscribe to the latest set of channel updates given // the set of channels we already know of. @@ -128,6 +138,7 @@ func NewSubSwapper(startingChans []Single, chanNotifier ChannelNotifier, backupState: backupState, chanEvents: chanEvents, keyRing: keyRing, + signer: config.signer, Swapper: backupSwapper, quit: make(chan struct{}), }, nil @@ -265,9 +276,17 @@ func (s *SubSwapper) backupUpdater() { log.Debugf("Adding channel %v to backup state", newChan.FundingOutpoint) - s.backupState[newChan.FundingOutpoint] = NewSingle( - newChan.OpenChannel, newChan.Addrs, - ) + single := NewSingle(newChan.OpenChannel, newChan.Addrs) + if s.signer != nil { + // Add CloseTx. + closeTx, err := buildCloseTx(newChan.OpenChannel, s.signer) + if err != nil { + log.Errorf("unable to create close tx for ChannelPoint(%v): %v", newChan.OpenChannel, err) + } else { + single.CloseTx = closeTx + } + } + s.backupState[newChan.FundingOutpoint] = single } // For all closed channels, we'll remove the prior diff --git a/rpcserver.go b/rpcserver.go index 42eb09d22a..b78a4193d2 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -7191,6 +7191,7 @@ func (r *rpcServer) ExportChannelBackup(ctx context.Context, // unknown, then we'll return an error unpackedBackup, err := chanbackup.FetchBackupForChan( chanPoint, r.server.chanStateDB, r.server.addrSource, + chanbackup.WithCloseTx(r.server.cc.Signer), ) if err != nil { return nil, err @@ -7361,6 +7362,7 @@ func (r *rpcServer) ExportAllChannelBackups(ctx context.Context, // channels from disk. allUnpackedBackups, err := chanbackup.FetchStaticChanBackups( r.server.chanStateDB, r.server.addrSource, + chanbackup.WithCloseTx(r.server.cc.Signer), ) if err != nil { return nil, fmt.Errorf("unable to fetch all static chan "+ @@ -7490,6 +7492,7 @@ func (r *rpcServer) SubscribeChannelBackups(req *lnrpc.ChannelBackupSubscription // backups from disk. chanBackups, err := chanbackup.FetchStaticChanBackups( r.server.chanStateDB, r.server.addrSource, + chanbackup.WithCloseTx(r.server.cc.Signer), ) if err != nil { return fmt.Errorf("unable to fetch all "+ diff --git a/server.go b/server.go index b59f873cf1..58baf6f90b 100644 --- a/server.go +++ b/server.go @@ -1476,12 +1476,14 @@ func newServer(cfg *Config, listenAddrs []net.Addr, backupFile := chanbackup.NewMultiFile(cfg.BackupFilePath) startingChans, err := chanbackup.FetchStaticChanBackups( s.chanStateDB, s.addrSource, + chanbackup.WithCloseTx(s.cc.Signer), ) if err != nil { return nil, err } s.chanSubSwapper, err = chanbackup.NewSubSwapper( startingChans, chanNotifier, s.cc.KeyRing, backupFile, + chanbackup.WithCloseTx(s.cc.Signer), ) if err != nil { return nil, err