chanbackup+rpcserver+server: return number of recovered channels
This commit is contained in:
4 files changed
+70
-79
No files matched your search
+19
-14
@@ -40,9 +40,11 @@ type PeerConnector interface {
|
|||||||
// the channel. In addition a LinkNode will be created for each new peer as
|
// 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
|
// well, in order to expose the addressing information required to locate to
|
||||||
// and connect to each peer in order to initiate the recovery protocol.
|
// and connect to each peer in order to initiate the recovery protocol.
|
||||||
|
// The number of channels that were successfully restored is returned.
|
||||||
func Recover(backups []Single, restorer ChannelRestorer,
|
func Recover(backups []Single, restorer ChannelRestorer,
|
||||||
peerConnector PeerConnector) error {
|
peerConnector PeerConnector) (int, error) {
|
||||||
|
|
||||||
|
var numRestored int
|
||||||
for i, backup := range backups {
|
for i, backup := range backups {
|
||||||
log.Infof("Restoring ChannelPoint(%v) to disk: ",
|
log.Infof("Restoring ChannelPoint(%v) to disk: ",
|
||||||
backup.FundingOutpoint)
|
backup.FundingOutpoint)
|
||||||
@@ -57,9 +59,10 @@ func Recover(backups []Single, restorer ChannelRestorer,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return numRestored, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
numRestored++
|
||||||
log.Infof("Attempting to connect to node=%x (addrs=%v) to "+
|
log.Infof("Attempting to connect to node=%x (addrs=%v) to "+
|
||||||
"restore ChannelPoint(%v)",
|
"restore ChannelPoint(%v)",
|
||||||
backup.RemoteNodePub.SerializeCompressed(),
|
backup.RemoteNodePub.SerializeCompressed(),
|
||||||
@@ -70,7 +73,7 @@ func Recover(backups []Single, restorer ChannelRestorer,
|
|||||||
backup.RemoteNodePub, backup.Addresses,
|
backup.RemoteNodePub, backup.Addresses,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return numRestored, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): to handle case where node has changed addrs,
|
// TODO(roasbeef): to handle case where node has changed addrs,
|
||||||
@@ -80,7 +83,7 @@ func Recover(backups []Single, restorer ChannelRestorer,
|
|||||||
// * just to to fresh w/ call to node addrs and de-dup?
|
// * just to to fresh w/ call to node addrs and de-dup?
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return numRestored, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): more specific keychain interface?
|
// TODO(roasbeef): more specific keychain interface?
|
||||||
@@ -88,16 +91,17 @@ func Recover(backups []Single, restorer ChannelRestorer,
|
|||||||
// UnpackAndRecoverSingles is a one-shot method, that given a set of packed
|
// UnpackAndRecoverSingles is a one-shot method, that given a set of packed
|
||||||
// single channel backups, will restore the channel state to a channel shell,
|
// 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
|
// 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
|
// channel. It is assumes that after this method exists, if a connection was
|
||||||
// able to be established, then then PeerConnector will continue to attempt to
|
// established, then the PeerConnector will continue to attempt to re-establish
|
||||||
// re-establish a persistent connection in the background.
|
// a persistent connection in the background. The number of channels that were
|
||||||
|
// successfully restored is returned.
|
||||||
func UnpackAndRecoverSingles(singles PackedSingles,
|
func UnpackAndRecoverSingles(singles PackedSingles,
|
||||||
keyChain keychain.KeyRing, restorer ChannelRestorer,
|
keyChain keychain.KeyRing, restorer ChannelRestorer,
|
||||||
peerConnector PeerConnector) error {
|
peerConnector PeerConnector) (int, error) {
|
||||||
|
|
||||||
chanBackups, err := singles.Unpack(keyChain)
|
chanBackups, err := singles.Unpack(keyChain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Recover(chanBackups, restorer, peerConnector)
|
return Recover(chanBackups, restorer, peerConnector)
|
||||||
@@ -106,16 +110,17 @@ func UnpackAndRecoverSingles(singles PackedSingles,
|
|||||||
// UnpackAndRecoverMulti is a one-shot method, that given a set of packed
|
// UnpackAndRecoverMulti is a one-shot method, that given a set of packed
|
||||||
// multi-channel backups, will restore the channel states to channel shells,
|
// 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
|
// 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
|
// channel. It is assumes that after this method exists, if a connection was
|
||||||
// able to be established, then then PeerConnector will continue to attempt to
|
// established, then the PeerConnector will continue to attempt to re-establish
|
||||||
// re-establish a persistent connection in the background.
|
// a persistent connection in the background. The number of channels that were
|
||||||
|
// successfully restored is returned.
|
||||||
func UnpackAndRecoverMulti(packedMulti PackedMulti,
|
func UnpackAndRecoverMulti(packedMulti PackedMulti,
|
||||||
keyChain keychain.KeyRing, restorer ChannelRestorer,
|
keyChain keychain.KeyRing, restorer ChannelRestorer,
|
||||||
peerConnector PeerConnector) error {
|
peerConnector PeerConnector) (int, error) {
|
||||||
|
|
||||||
chanBackups, err := packedMulti.Unpack(keyChain)
|
chanBackups, err := packedMulti.Unpack(keyChain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Recover(chanBackups.StaticBackups, restorer, peerConnector)
|
return Recover(chanBackups.StaticBackups, restorer, peerConnector)
|
||||||
|
|||||||
+47
-61
@@ -2,7 +2,7 @@ package chanbackup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -11,6 +11,12 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errRestoreFail = errors.New("restore fail")
|
||||||
|
|
||||||
|
errConnectFail = errors.New("connect fail")
|
||||||
|
)
|
||||||
|
|
||||||
type mockChannelRestorer struct {
|
type mockChannelRestorer struct {
|
||||||
fail bool
|
fail bool
|
||||||
|
|
||||||
@@ -19,7 +25,7 @@ type mockChannelRestorer struct {
|
|||||||
|
|
||||||
func (m *mockChannelRestorer) RestoreChansFromSingles(...Single) error {
|
func (m *mockChannelRestorer) RestoreChansFromSingles(...Single) error {
|
||||||
if m.fail {
|
if m.fail {
|
||||||
return fmt.Errorf("fail")
|
return errRestoreFail
|
||||||
}
|
}
|
||||||
|
|
||||||
m.callCount++
|
m.callCount++
|
||||||
@@ -33,11 +39,11 @@ type mockPeerConnector struct {
|
|||||||
callCount int
|
callCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockPeerConnector) ConnectPeer(node *btcec.PublicKey,
|
func (m *mockPeerConnector) ConnectPeer(_ *btcec.PublicKey,
|
||||||
addrs []net.Addr) error {
|
_ []net.Addr) error {
|
||||||
|
|
||||||
if m.fail {
|
if m.fail {
|
||||||
return fmt.Errorf("fail")
|
return errConnectFail
|
||||||
}
|
}
|
||||||
|
|
||||||
m.callCount++
|
m.callCount++
|
||||||
@@ -59,16 +65,13 @@ func TestUnpackAndRecoverSingles(t *testing.T) {
|
|||||||
var packedBackups PackedSingles
|
var packedBackups PackedSingles
|
||||||
for i := 0; i < numSingles; i++ {
|
for i := 0; i < numSingles; i++ {
|
||||||
channel, err := genRandomOpenChannelShell()
|
channel, err := genRandomOpenChannelShell()
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatalf("unable make channel: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
single := NewSingle(channel, nil)
|
single := NewSingle(channel, nil)
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := single.PackToWriter(&b, keyRing); err != nil {
|
err = single.PackToWriter(&b, keyRing)
|
||||||
t.Fatalf("unable to pack single: %v", err)
|
require.NoError(t, err)
|
||||||
}
|
|
||||||
|
|
||||||
backups = append(backups, single)
|
backups = append(backups, single)
|
||||||
packedBackups = append(packedBackups, b.Bytes())
|
packedBackups = append(packedBackups, b.Bytes())
|
||||||
@@ -83,54 +86,47 @@ func TestUnpackAndRecoverSingles(t *testing.T) {
|
|||||||
// If we make the channel restore fail, then the entire method should
|
// If we make the channel restore fail, then the entire method should
|
||||||
// as well
|
// as well
|
||||||
chanRestorer.fail = true
|
chanRestorer.fail = true
|
||||||
err := UnpackAndRecoverSingles(
|
_, err := UnpackAndRecoverSingles(
|
||||||
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
if err == nil {
|
require.ErrorIs(t, err, errRestoreFail)
|
||||||
t.Fatalf("restoration should have failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
chanRestorer.fail = false
|
chanRestorer.fail = false
|
||||||
|
|
||||||
// If we make the peer connector fail, then the entire method should as
|
// If we make the peer connector fail, then the entire method should as
|
||||||
// well
|
// well
|
||||||
peerConnector.fail = true
|
peerConnector.fail = true
|
||||||
err = UnpackAndRecoverSingles(
|
_, err = UnpackAndRecoverSingles(
|
||||||
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
if err == nil {
|
require.ErrorIs(t, err, errConnectFail)
|
||||||
t.Fatalf("restoration should have failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
chanRestorer.callCount--
|
chanRestorer.callCount--
|
||||||
peerConnector.fail = false
|
peerConnector.fail = false
|
||||||
|
|
||||||
// Next, we'll ensure that if all the interfaces function as expected,
|
// Next, we'll ensure that if all the interfaces function as expected,
|
||||||
// then the channels will properly be unpacked and restored.
|
// then the channels will properly be unpacked and restored.
|
||||||
err = UnpackAndRecoverSingles(
|
numRestored, err := UnpackAndRecoverSingles(
|
||||||
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to recover chans")
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, numSingles, numRestored)
|
||||||
|
|
||||||
// Both the restorer, and connector should have been called 10 times,
|
// Both the restorer, and connector should have been called 10 times,
|
||||||
// once for each backup.
|
// once for each backup.
|
||||||
if chanRestorer.callCount != numSingles {
|
require.EqualValues(
|
||||||
t.Fatalf("expected %v calls, instead got %v",
|
t, numSingles, chanRestorer.callCount, "restorer call count",
|
||||||
numSingles, chanRestorer.callCount)
|
)
|
||||||
}
|
require.EqualValues(
|
||||||
if peerConnector.callCount != numSingles {
|
t, numSingles, peerConnector.callCount, "peer call count",
|
||||||
t.Fatalf("expected %v calls, instead got %v",
|
)
|
||||||
numSingles, peerConnector.callCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we modify the keyRing, then unpacking should fail.
|
// If we modify the keyRing, then unpacking should fail.
|
||||||
keyRing.Fail = true
|
keyRing.Fail = true
|
||||||
err = UnpackAndRecoverSingles(
|
_, err = UnpackAndRecoverSingles(
|
||||||
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
if err == nil {
|
require.ErrorContains(t, err, "fail")
|
||||||
t.Fatalf("unpacking should have failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(roasbeef): verify proper call args
|
// TODO(roasbeef): verify proper call args
|
||||||
}
|
}
|
||||||
@@ -148,9 +144,7 @@ func TestUnpackAndRecoverMulti(t *testing.T) {
|
|||||||
backups := make([]Single, 0, numSingles)
|
backups := make([]Single, 0, numSingles)
|
||||||
for i := 0; i < numSingles; i++ {
|
for i := 0; i < numSingles; i++ {
|
||||||
channel, err := genRandomOpenChannelShell()
|
channel, err := genRandomOpenChannelShell()
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatalf("unable make channel: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
single := NewSingle(channel, nil)
|
single := NewSingle(channel, nil)
|
||||||
|
|
||||||
@@ -162,9 +156,8 @@ func TestUnpackAndRecoverMulti(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := multi.PackToWriter(&b, keyRing); err != nil {
|
err := multi.PackToWriter(&b, keyRing)
|
||||||
t.Fatalf("unable to pack multi: %v", err)
|
require.NoError(t, err)
|
||||||
}
|
|
||||||
|
|
||||||
// Next, we'll pack the set of singles into a packed multi, and also
|
// Next, we'll pack the set of singles into a packed multi, and also
|
||||||
// create the set of interfaces we need to carry out the remainder of
|
// create the set of interfaces we need to carry out the remainder of
|
||||||
@@ -177,54 +170,47 @@ func TestUnpackAndRecoverMulti(t *testing.T) {
|
|||||||
// If we make the channel restore fail, then the entire method should
|
// If we make the channel restore fail, then the entire method should
|
||||||
// as well
|
// as well
|
||||||
chanRestorer.fail = true
|
chanRestorer.fail = true
|
||||||
err := UnpackAndRecoverMulti(
|
_, err = UnpackAndRecoverMulti(
|
||||||
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
if err == nil {
|
require.ErrorIs(t, err, errRestoreFail)
|
||||||
t.Fatalf("restoration should have failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
chanRestorer.fail = false
|
chanRestorer.fail = false
|
||||||
|
|
||||||
// If we make the peer connector fail, then the entire method should as
|
// If we make the peer connector fail, then the entire method should as
|
||||||
// well
|
// well
|
||||||
peerConnector.fail = true
|
peerConnector.fail = true
|
||||||
err = UnpackAndRecoverMulti(
|
_, err = UnpackAndRecoverMulti(
|
||||||
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
if err == nil {
|
require.ErrorIs(t, err, errConnectFail)
|
||||||
t.Fatalf("restoration should have failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
chanRestorer.callCount--
|
chanRestorer.callCount--
|
||||||
peerConnector.fail = false
|
peerConnector.fail = false
|
||||||
|
|
||||||
// Next, we'll ensure that if all the interfaces function as expected,
|
// Next, we'll ensure that if all the interfaces function as expected,
|
||||||
// then the channels will properly be unpacked and restored.
|
// then the channels will properly be unpacked and restored.
|
||||||
err = UnpackAndRecoverMulti(
|
numRestored, err := UnpackAndRecoverMulti(
|
||||||
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to recover chans")
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, numSingles, numRestored)
|
||||||
|
|
||||||
// Both the restorer, and connector should have been called 10 times,
|
// Both the restorer, and connector should have been called 10 times,
|
||||||
// once for each backup.
|
// once for each backup.
|
||||||
if chanRestorer.callCount != numSingles {
|
require.EqualValues(
|
||||||
t.Fatalf("expected %v calls, instead got %v",
|
t, numSingles, chanRestorer.callCount, "restorer call count",
|
||||||
numSingles, chanRestorer.callCount)
|
)
|
||||||
}
|
require.EqualValues(
|
||||||
if peerConnector.callCount != numSingles {
|
t, numSingles, peerConnector.callCount, "peer call count",
|
||||||
t.Fatalf("expected %v calls, instead got %v",
|
)
|
||||||
numSingles, peerConnector.callCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we modify the keyRing, then unpacking should fail.
|
// If we modify the keyRing, then unpacking should fail.
|
||||||
keyRing.Fail = true
|
keyRing.Fail = true
|
||||||
err = UnpackAndRecoverMulti(
|
_, err = UnpackAndRecoverMulti(
|
||||||
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
||||||
)
|
)
|
||||||
if err == nil {
|
require.ErrorContains(t, err, "fail")
|
||||||
t.Fatalf("unpacking should have failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(roasbeef): verify proper call args
|
// TODO(roasbeef): verify proper call args
|
||||||
}
|
}
|
||||||
+2
-2
@@ -8159,7 +8159,7 @@ func (r *rpcServer) RestoreChannelBackups(ctx context.Context,
|
|||||||
// write the new backups to disk, and then attempt to connect
|
// write the new backups to disk, and then attempt to connect
|
||||||
// out to any peers that we know of which were our prior
|
// out to any peers that we know of which were our prior
|
||||||
// channel peers.
|
// channel peers.
|
||||||
err := chanbackup.UnpackAndRecoverSingles(
|
_, err := chanbackup.UnpackAndRecoverSingles(
|
||||||
chanbackup.PackedSingles(packedBackups),
|
chanbackup.PackedSingles(packedBackups),
|
||||||
r.server.cc.KeyRing, chanRestorer, r.server,
|
r.server.cc.KeyRing, chanRestorer, r.server,
|
||||||
)
|
)
|
||||||
@@ -8176,7 +8176,7 @@ func (r *rpcServer) RestoreChannelBackups(ctx context.Context,
|
|||||||
// out to any peers that we know of which were our prior
|
// out to any peers that we know of which were our prior
|
||||||
// channel peers.
|
// channel peers.
|
||||||
packedMulti := chanbackup.PackedMulti(packedMultiBackup)
|
packedMulti := chanbackup.PackedMulti(packedMultiBackup)
|
||||||
err := chanbackup.UnpackAndRecoverMulti(
|
_, err := chanbackup.UnpackAndRecoverMulti(
|
||||||
packedMulti, r.server.cc.KeyRing, chanRestorer,
|
packedMulti, r.server.cc.KeyRing, chanRestorer,
|
||||||
r.server,
|
r.server,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2248,7 +2248,7 @@ func (s *server) Start() error {
|
|||||||
chainArb: s.chainArb,
|
chainArb: s.chainArb,
|
||||||
}
|
}
|
||||||
if len(s.chansToRestore.PackedSingleChanBackups) != 0 {
|
if len(s.chansToRestore.PackedSingleChanBackups) != 0 {
|
||||||
err := chanbackup.UnpackAndRecoverSingles(
|
_, err := chanbackup.UnpackAndRecoverSingles(
|
||||||
s.chansToRestore.PackedSingleChanBackups,
|
s.chansToRestore.PackedSingleChanBackups,
|
||||||
s.cc.KeyRing, chanRestorer, s,
|
s.cc.KeyRing, chanRestorer, s,
|
||||||
)
|
)
|
||||||
@@ -2259,7 +2259,7 @@ func (s *server) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(s.chansToRestore.PackedMultiChanBackup) != 0 {
|
if len(s.chansToRestore.PackedMultiChanBackup) != 0 {
|
||||||
err := chanbackup.UnpackAndRecoverMulti(
|
_, err := chanbackup.UnpackAndRecoverMulti(
|
||||||
s.chansToRestore.PackedMultiChanBackup,
|
s.chansToRestore.PackedMultiChanBackup,
|
||||||
s.cc.KeyRing, chanRestorer, s,
|
s.cc.KeyRing, chanRestorer, s,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user