lnd.xprv/chanbackup/recover.go
Olaoluwa Osuntokun 7fcab83bb4
chanbackup: add functions to allow recovery of existing channel backups
In this commit, we add a series of functions that will allow users to
recover existing channel backups. We do this using two primary
interfaces: the ChannelRestorer, and the PeerConnector. The first
interfaces allows us to abstract away the details w.r.t exactly how a
channel is restored. Instead, we simply expect that the channel backup
will be inserted as a sort of "channel shell" which contains only the
data required to initiate the data loss protection protocol. The second
interface is how we instruct the Lightning node to connect out to the
channel peer given its known addresses.
2019-01-23 18:11:29 -08:00

115 lines
4.3 KiB
Go

package chanbackup
import (
"net"
"github.com/btcsuite/btcd/btcec"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/keychain"
)
// ChannelRestorer is an interface that allows the Recover method to map the
// set of single channel backups into a set of "channel shells" and store these
// persistently on disk. The channel shell should contain all the information
// needed to execute the data loss recovery protocol once the channel peer is
// connected to.
type ChannelRestorer interface {
// RestoreChansFromSingles attempts to map the set of single channel
// backups to channel shells that will be stored persistently. Once
// these shells have been stored on disk, we'll be able to connect to
// the channel peer an execute the data loss recovery protocol.
RestoreChansFromSingles(...Single) error
}
// PeerConnector is an interface that allows the Recover method to connect to
// the target node given the set of possible addresses.
type PeerConnector interface {
// ConnectPeer attempts to connect to the target node at the set of
// available addresses. Once this method returns with a non-nil error,
// the connector should attempt to persistently connect to the target
// peer in the background as a persistent attempt.
ConnectPeer(node *btcec.PublicKey, addrs []net.Addr) error
}
// Recover attempts to recover the static channel state from a set of static
// channel backups. If successfully, the database will be populated with a
// series of "shell" channels. These "shell" channels cannot be used to operate
// the channel as normal, but instead are meant to be used to enter the data
// loss recovery phase, and recover the settled funds within
// the channel. In addition a LinkNode will be created for each new peer as
// well, in order to expose the addressing information required to locate to
// and connect to each peer in order to initiate the recovery protocol.
func Recover(backups []Single, restorer ChannelRestorer,
peerConnector PeerConnector) error {
for _, backup := range backups {
log.Infof("Restoring ChannelPoint(%v) to disk: ",
backup.FundingOutpoint)
err := restorer.RestoreChansFromSingles(backup)
if err != nil {
return err
}
log.Infof("Attempting to connect to node=%x (addrs=%v) to "+
"restore ChannelPoint(%v)",
backup.RemoteNodePub.SerializeCompressed(),
newLogClosure(func() string {
return spew.Sdump(backup.Addresses)
}), backup.FundingOutpoint)
err = peerConnector.ConnectPeer(
backup.RemoteNodePub, backup.Addresses,
)
if err != nil {
return err
}
// TODO(roasbeef): to handle case where node has changed addrs,
// need to subscribe to new updates for target node pub to
// attempt to connect to other addrs
//
// * just to to fresh w/ call to node addrs and de-dup?
}
return nil
}
// TODO(roasbeef): more specific keychain interface?
// UnpackAndRecoverSingles is a one-shot method, that given a set of packed
// single channel backups, will restore the channel state to a channel shell,
// and also reach out to connect to any of the known node addresses for that
// channel. It is assumes that after this method exists, if a connection we
// able to be established, then then PeerConnector will continue to attempt to
// re-establish a persistent connection in the background.
func UnpackAndRecoverSingles(singles PackedSingles,
keyChain keychain.KeyRing, restorer ChannelRestorer,
peerConnector PeerConnector) error {
chanBackups, err := singles.Unpack(keyChain)
if err != nil {
return err
}
return Recover(chanBackups, restorer, peerConnector)
}
// UnpackAndRecoverMulti is a one-shot method, that given a set of packed
// multi-channel backups, will restore the channel states to channel shells,
// and also reach out to connect to any of the known node addresses for that
// channel. It is assumes that after this method exists, if a connection we
// able to be established, then then PeerConnector will continue to attempt to
// re-establish a persistent connection in the background.
func UnpackAndRecoverMulti(packedMulti PackedMulti,
keyChain keychain.KeyRing, restorer ChannelRestorer,
peerConnector PeerConnector) error {
chanBackups, err := packedMulti.Unpack(keyChain)
if err != nil {
return err
}
return Recover(chanBackups.StaticBackups, restorer, peerConnector)
}