2018-12-10 03:51:58 +01:00
|
|
|
package chanbackup
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
2018-12-10 03:51:58 +01:00
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2023-11-05 23:39:35 +01:00
|
|
|
"github.com/lightningnetwork/lnd/fn"
|
2021-08-23 12:16:37 +02:00
|
|
|
"github.com/lightningnetwork/lnd/kvdb"
|
2018-12-10 03:51:58 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// LiveChannelSource is an interface that allows us to query for the set of
|
|
|
|
// live channels. A live channel is one that is open, and has not had a
|
|
|
|
// commitment transaction broadcast.
|
|
|
|
type LiveChannelSource interface {
|
|
|
|
// FetchAllChannels returns all known live channels.
|
|
|
|
FetchAllChannels() ([]*channeldb.OpenChannel, error)
|
|
|
|
|
|
|
|
// FetchChannel attempts to locate a live channel identified by the
|
2021-08-23 12:16:37 +02:00
|
|
|
// passed chanPoint. Optionally an existing db tx can be supplied.
|
|
|
|
FetchChannel(tx kvdb.RTx, chanPoint wire.OutPoint) (
|
|
|
|
*channeldb.OpenChannel, error)
|
2021-09-21 19:18:16 +02:00
|
|
|
}
|
2018-12-10 03:51:58 +01:00
|
|
|
|
2021-09-21 19:18:16 +02:00
|
|
|
// AddressSource is an interface that allows us to query for the set of
|
|
|
|
// addresses a node can be connected to.
|
|
|
|
type AddressSource interface {
|
2018-12-10 03:51:58 +01:00
|
|
|
// AddrsForNode returns all known addresses for the target node public
|
|
|
|
// key.
|
|
|
|
AddrsForNode(nodePub *btcec.PublicKey) ([]net.Addr, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// assembleChanBackup attempts to assemble a static channel backup for the
|
|
|
|
// passed open channel. The backup includes all information required to restore
|
|
|
|
// the channel, as well as addressing information so we can find the peer and
|
|
|
|
// reconnect to them to initiate the protocol.
|
2021-09-21 19:18:16 +02:00
|
|
|
func assembleChanBackup(addrSource AddressSource,
|
2018-12-10 03:51:58 +01:00
|
|
|
openChan *channeldb.OpenChannel) (*Single, error) {
|
|
|
|
|
|
|
|
log.Debugf("Crafting backup for ChannelPoint(%v)",
|
|
|
|
openChan.FundingOutpoint)
|
|
|
|
|
|
|
|
// First, we'll query the channel source to obtain all the addresses
|
2021-09-21 19:18:16 +02:00
|
|
|
// that are associated with the peer for this channel.
|
|
|
|
nodeAddrs, err := addrSource.AddrsForNode(openChan.IdentityPub)
|
2018-12-10 03:51:58 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
single := NewSingle(openChan, nodeAddrs)
|
|
|
|
|
|
|
|
return &single, nil
|
|
|
|
}
|
|
|
|
|
2023-11-05 23:39:35 +01:00
|
|
|
// buildCloseTxInputs generates inputs needed to force close a channel from
|
|
|
|
// an open channel. Anyone having these inputs and the signer, can sign the
|
|
|
|
// force closure transaction. Warning! If the channel state updates, an attempt
|
|
|
|
// to close the channel using this method with outdated CloseTxInputs can result
|
|
|
|
// in loss of funds! This may happen if an outdated channel backup is attempted
|
|
|
|
// to be used to force close the channel.
|
|
|
|
func buildCloseTxInputs(
|
|
|
|
targetChan *channeldb.OpenChannel) fn.Option[CloseTxInputs] {
|
|
|
|
|
|
|
|
log.Debugf("Crafting CloseTxInputs for ChannelPoint(%v)",
|
|
|
|
targetChan.FundingOutpoint)
|
|
|
|
|
|
|
|
localCommit := targetChan.LocalCommitment
|
|
|
|
|
|
|
|
if localCommit.CommitTx == nil {
|
|
|
|
log.Infof("CommitTx is nil for ChannelPoint(%v), "+
|
|
|
|
"skipping CloseTxInputs. This is possible when "+
|
|
|
|
"DLP is active.", targetChan.FundingOutpoint)
|
|
|
|
|
|
|
|
return fn.None[CloseTxInputs]()
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need unsigned force close tx and the counterparty's signature.
|
|
|
|
inputs := CloseTxInputs{
|
|
|
|
CommitTx: localCommit.CommitTx,
|
|
|
|
CommitSig: localCommit.CommitSig,
|
|
|
|
}
|
|
|
|
|
|
|
|
// In case of a taproot channel, commit height is needed as well to
|
|
|
|
// produce verification nonce for the taproot channel using shachain.
|
|
|
|
if targetChan.ChanType.IsTaproot() {
|
|
|
|
inputs.CommitHeight = localCommit.CommitHeight
|
|
|
|
}
|
|
|
|
|
|
|
|
// In case of a custom taproot channel, TapscriptRoot is needed as well.
|
|
|
|
if targetChan.ChanType.HasTapscriptRoot() {
|
|
|
|
inputs.TapscriptRoot = targetChan.TapscriptRoot
|
|
|
|
}
|
|
|
|
|
|
|
|
return fn.Some(inputs)
|
|
|
|
}
|
|
|
|
|
2018-12-10 03:51:58 +01:00
|
|
|
// 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.
|
2021-09-21 19:18:16 +02:00
|
|
|
func FetchBackupForChan(chanPoint wire.OutPoint, chanSource LiveChannelSource,
|
|
|
|
addrSource AddressSource) (*Single, error) {
|
2018-12-10 03:51:58 +01:00
|
|
|
|
|
|
|
// First, we'll query the channel source to see if the channel is known
|
|
|
|
// and open within the database.
|
2021-08-23 12:16:37 +02:00
|
|
|
targetChan, err := chanSource.FetchChannel(nil, chanPoint)
|
2018-12-10 03:51:58 +01:00
|
|
|
if err != nil {
|
|
|
|
// If we can't find the channel, then we return with an error,
|
|
|
|
// as we have nothing to backup.
|
|
|
|
return nil, fmt.Errorf("unable to find target channel")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we have the target channel, we can assemble the backup using
|
|
|
|
// the source to obtain any extra information that we may need.
|
2021-09-21 19:18:16 +02:00
|
|
|
staticChanBackup, err := assembleChanBackup(addrSource, targetChan)
|
2018-12-10 03:51:58 +01:00
|
|
|
if err != nil {
|
2024-02-26 12:19:38 +01:00
|
|
|
return nil, fmt.Errorf("unable to create chan backup: %w", err)
|
2018-12-10 03:51:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return staticChanBackup, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// FetchStaticChanBackups will return a plaintext static channel back up for
|
|
|
|
// all known active/open channels within the passed channel source.
|
2021-09-21 19:18:16 +02:00
|
|
|
func FetchStaticChanBackups(chanSource LiveChannelSource,
|
|
|
|
addrSource AddressSource) ([]Single, error) {
|
|
|
|
|
2018-12-10 03:51:58 +01:00
|
|
|
// First, we'll query the backup source for information concerning all
|
|
|
|
// currently open and available channels.
|
|
|
|
openChans, err := chanSource.FetchAllChannels()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we have all the channels, we'll use the chanSource to
|
|
|
|
// obtain any auxiliary information we need to craft a backup for each
|
|
|
|
// channel.
|
2020-03-06 16:11:48 +01:00
|
|
|
staticChanBackups := make([]Single, 0, len(openChans))
|
|
|
|
for _, openChan := range openChans {
|
2021-09-21 19:18:16 +02:00
|
|
|
chanBackup, err := assembleChanBackup(addrSource, openChan)
|
2018-12-10 03:51:58 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-03-06 16:11:48 +01:00
|
|
|
staticChanBackups = append(staticChanBackups, *chanBackup)
|
2018-12-10 03:51:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return staticChanBackups, nil
|
|
|
|
}
|