You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
4.6 KiB
123 lines
4.6 KiB
package chanbackup |
|
|
|
import ( |
|
"net" |
|
|
|
"github.com/btcsuite/btcd/btcec" |
|
"github.com/davecgh/go-spew/spew" |
|
"github.com/lightningnetwork/lnd/channeldb" |
|
"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 i, backup := range backups { |
|
log.Infof("Restoring ChannelPoint(%v) to disk: ", |
|
backup.FundingOutpoint) |
|
|
|
err := restorer.RestoreChansFromSingles(backup) |
|
|
|
// If a channel is already present in the channel DB, we can |
|
// just continue. No reason to fail a whole set of multi backups |
|
// for example. This allows resume of a restore in case another |
|
// error happens. |
|
if err == channeldb.ErrChanAlreadyExists { |
|
continue |
|
} |
|
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(backups[i].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) |
|
}
|
|
|