github.com/decred/dcrlnd@v0.7.6/chanbackup/recover.go (about)

     1  package chanbackup
     2  
     3  import (
     4  	"net"
     5  
     6  	"github.com/davecgh/go-spew/spew"
     7  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     8  	"github.com/decred/dcrlnd/channeldb"
     9  	"github.com/decred/dcrlnd/keychain"
    10  )
    11  
    12  // ChannelRestorer is an interface that allows the Recover method to map the
    13  // set of single channel backups into a set of "channel shells" and store these
    14  // persistently on disk. The channel shell should contain all the information
    15  // needed to execute the data loss recovery protocol once the channel peer is
    16  // connected to.
    17  type ChannelRestorer interface {
    18  	// RestoreChansFromSingles attempts to map the set of single channel
    19  	// backups to channel shells that will be stored persistently. Once
    20  	// these shells have been stored on disk, we'll be able to connect to
    21  	// the channel peer an execute the data loss recovery protocol.
    22  	RestoreChansFromSingles(...Single) error
    23  }
    24  
    25  // PeerConnector is an interface that allows the Recover method to connect to
    26  // the target node given the set of possible addresses.
    27  type PeerConnector interface {
    28  	// ConnectPeer attempts to connect to the target node at the set of
    29  	// available addresses. Once this method returns with a non-nil error,
    30  	// the connector should attempt to persistently connect to the target
    31  	// peer in the background as a persistent attempt.
    32  	ConnectPeer(node *secp256k1.PublicKey, addrs []net.Addr) error
    33  }
    34  
    35  // Recover attempts to recover the static channel state from a set of static
    36  // channel backups. If successfully, the database will be populated with a
    37  // series of "shell" channels. These "shell" channels cannot be used to operate
    38  // the channel as normal, but instead are meant to be used to enter the data
    39  // loss recovery phase, and recover the settled funds within
    40  // the channel. In addition a LinkNode will be created for each new peer as
    41  // well, in order to expose the addressing information required to locate to
    42  // and connect to each peer in order to initiate the recovery protocol.
    43  func Recover(backups []Single, restorer ChannelRestorer,
    44  	peerConnector PeerConnector) error {
    45  
    46  	for i, backup := range backups {
    47  		log.Infof("Restoring ChannelPoint(%v) to disk: ",
    48  			backup.FundingOutpoint)
    49  
    50  		err := restorer.RestoreChansFromSingles(backup)
    51  
    52  		// If a channel is already present in the channel DB, we can
    53  		// just continue. No reason to fail a whole set of multi backups
    54  		// for example. This allows resume of a restore in case another
    55  		// error happens.
    56  		if err == channeldb.ErrChanAlreadyExists {
    57  			continue
    58  		}
    59  		if err != nil {
    60  			return err
    61  		}
    62  
    63  		log.Infof("Attempting to connect to node=%x (addrs=%v) to "+
    64  			"restore ChannelPoint(%v)",
    65  			backup.RemoteNodePub.SerializeCompressed(),
    66  			newLogClosure(func() string {
    67  				return spew.Sdump(backups[i].Addresses)
    68  			}), backup.FundingOutpoint)
    69  
    70  		err = peerConnector.ConnectPeer(
    71  			backup.RemoteNodePub, backup.Addresses,
    72  		)
    73  		if err != nil {
    74  			return err
    75  		}
    76  
    77  		// TODO(roasbeef): to handle case where node has changed addrs,
    78  		// need to subscribe to new updates for target node pub to
    79  		// attempt to connect to other addrs
    80  		//
    81  		//  * just to to fresh w/ call to node addrs and de-dup?
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  // TODO(roasbeef): more specific keychain interface?
    88  
    89  // UnpackAndRecoverSingles is a one-shot method, that given a set of packed
    90  // single channel backups, will restore the channel state to a channel shell,
    91  // and also reach out to connect to any of the known node addresses for that
    92  // channel. It is assumes that after this method exists, if a connection we
    93  // able to be established, then then PeerConnector will continue to attempt to
    94  // re-establish a persistent connection in the background.
    95  func UnpackAndRecoverSingles(singles PackedSingles,
    96  	keyChain keychain.KeyRing, restorer ChannelRestorer,
    97  	peerConnector PeerConnector) error {
    98  
    99  	chanBackups, err := singles.Unpack(keyChain)
   100  	if err != nil {
   101  		return err
   102  	}
   103  
   104  	return Recover(chanBackups, restorer, peerConnector)
   105  }
   106  
   107  // UnpackAndRecoverMulti is a one-shot method, that given a set of packed
   108  // multi-channel backups, will restore the channel states to channel shells,
   109  // and also reach out to connect to any of the known node addresses for that
   110  // channel. It is assumes that after this method exists, if a connection we
   111  // able to be established, then then PeerConnector will continue to attempt to
   112  // re-establish a persistent connection in the background.
   113  func UnpackAndRecoverMulti(packedMulti PackedMulti,
   114  	keyChain keychain.KeyRing, restorer ChannelRestorer,
   115  	peerConnector PeerConnector) error {
   116  
   117  	chanBackups, err := packedMulti.Unpack(keyChain)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	return Recover(chanBackups.StaticBackups, restorer, peerConnector)
   123  }