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 }