chanbackup+rpcserver+server: return number of recovered channels

This commit is contained in:
Oliver Gugger committed 2024-11-06 15:30:23 +01:00
1 parent 15a5fe7704
commit d8c920fa7a
4 files changed
+70 -79

No files matched your search

+19 -14
View File
@@ -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
View File
@@ -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
View File
@@ -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,
) )
+2 -2
View File
@@ -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,
) )