lnd.xprv/chanbackup/recover.go

115 lines
4.3 KiB
Go
Raw Normal View History

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)
}