2018-12-10 04:02:40 +01:00
|
|
|
package chanbackup
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"testing"
|
|
|
|
|
2022-02-23 14:48:00 +01:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
2022-05-05 22:11:50 +02:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-12-10 04:02:40 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type mockChannelRestorer struct {
|
|
|
|
fail bool
|
|
|
|
|
|
|
|
callCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockChannelRestorer) RestoreChansFromSingles(...Single) error {
|
|
|
|
if m.fail {
|
|
|
|
return fmt.Errorf("fail")
|
|
|
|
}
|
|
|
|
|
|
|
|
m.callCount++
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockPeerConnector struct {
|
|
|
|
fail bool
|
|
|
|
|
|
|
|
callCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *mockPeerConnector) ConnectPeer(node *btcec.PublicKey,
|
|
|
|
addrs []net.Addr) error {
|
|
|
|
|
|
|
|
if m.fail {
|
|
|
|
return fmt.Errorf("fail")
|
|
|
|
}
|
|
|
|
|
|
|
|
m.callCount++
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestUnpackAndRecoverSingles tests that we're able to properly unpack and
|
|
|
|
// recover a set of packed singles.
|
|
|
|
func TestUnpackAndRecoverSingles(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
keyRing := &mockKeyRing{}
|
|
|
|
|
|
|
|
// First, we'll create a number of single chan backups that we'll
|
|
|
|
// shortly back to so we can begin our recovery attempt.
|
|
|
|
numSingles := 10
|
|
|
|
backups := make([]Single, 0, numSingles)
|
|
|
|
var packedBackups PackedSingles
|
|
|
|
for i := 0; i < numSingles; i++ {
|
|
|
|
channel, err := genRandomOpenChannelShell()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable make channel: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
single := NewSingle(channel, nil)
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
if err := single.PackToWriter(&b, keyRing); err != nil {
|
|
|
|
t.Fatalf("unable to pack single: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
backups = append(backups, single)
|
|
|
|
packedBackups = append(packedBackups, b.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
chanRestorer := mockChannelRestorer{}
|
|
|
|
peerConnector := mockPeerConnector{}
|
|
|
|
|
|
|
|
// Now that we have our backups (packed and unpacked), we'll attempt to
|
|
|
|
// restore them all in a single batch.
|
|
|
|
|
|
|
|
// If we make the channel restore fail, then the entire method should
|
|
|
|
// as well
|
|
|
|
chanRestorer.fail = true
|
|
|
|
err := UnpackAndRecoverSingles(
|
|
|
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("restoration should have failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
chanRestorer.fail = false
|
|
|
|
|
|
|
|
// If we make the peer connector fail, then the entire method should as
|
|
|
|
// well
|
|
|
|
peerConnector.fail = true
|
|
|
|
err = UnpackAndRecoverSingles(
|
|
|
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("restoration should have failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
chanRestorer.callCount--
|
|
|
|
peerConnector.fail = false
|
|
|
|
|
|
|
|
// Next, we'll ensure that if all the interfaces function as expected,
|
|
|
|
// then the channels will properly be unpacked and restored.
|
|
|
|
err = UnpackAndRecoverSingles(
|
|
|
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
2022-05-05 22:11:50 +02:00
|
|
|
require.NoError(t, err, "unable to recover chans")
|
2018-12-10 04:02:40 +01:00
|
|
|
|
|
|
|
// Both the restorer, and connector should have been called 10 times,
|
|
|
|
// once for each backup.
|
|
|
|
if chanRestorer.callCount != numSingles {
|
|
|
|
t.Fatalf("expected %v calls, instead got %v",
|
|
|
|
numSingles, chanRestorer.callCount)
|
|
|
|
}
|
|
|
|
if peerConnector.callCount != numSingles {
|
|
|
|
t.Fatalf("expected %v calls, instead got %v",
|
|
|
|
numSingles, peerConnector.callCount)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we modify the keyRing, then unpacking should fail.
|
|
|
|
keyRing.fail = true
|
|
|
|
err = UnpackAndRecoverSingles(
|
|
|
|
packedBackups, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("unpacking should have failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(roasbeef): verify proper call args
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestUnpackAndRecoverMulti tests that we're able to properly unpack and
|
|
|
|
// recover a packed multi.
|
|
|
|
func TestUnpackAndRecoverMulti(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
keyRing := &mockKeyRing{}
|
|
|
|
|
|
|
|
// First, we'll create a number of single chan backups that we'll
|
|
|
|
// shortly back to so we can begin our recovery attempt.
|
|
|
|
numSingles := 10
|
|
|
|
backups := make([]Single, 0, numSingles)
|
|
|
|
for i := 0; i < numSingles; i++ {
|
|
|
|
channel, err := genRandomOpenChannelShell()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable make channel: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
single := NewSingle(channel, nil)
|
|
|
|
|
|
|
|
backups = append(backups, single)
|
|
|
|
}
|
|
|
|
|
|
|
|
multi := Multi{
|
|
|
|
StaticBackups: backups,
|
|
|
|
}
|
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
if err := multi.PackToWriter(&b, keyRing); err != nil {
|
|
|
|
t.Fatalf("unable to pack multi: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// the test.
|
|
|
|
packedMulti := PackedMulti(b.Bytes())
|
|
|
|
|
|
|
|
chanRestorer := mockChannelRestorer{}
|
|
|
|
peerConnector := mockPeerConnector{}
|
|
|
|
|
|
|
|
// If we make the channel restore fail, then the entire method should
|
|
|
|
// as well
|
|
|
|
chanRestorer.fail = true
|
|
|
|
err := UnpackAndRecoverMulti(
|
|
|
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("restoration should have failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
chanRestorer.fail = false
|
|
|
|
|
|
|
|
// If we make the peer connector fail, then the entire method should as
|
|
|
|
// well
|
|
|
|
peerConnector.fail = true
|
|
|
|
err = UnpackAndRecoverMulti(
|
|
|
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("restoration should have failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
chanRestorer.callCount--
|
|
|
|
peerConnector.fail = false
|
|
|
|
|
|
|
|
// Next, we'll ensure that if all the interfaces function as expected,
|
|
|
|
// then the channels will properly be unpacked and restored.
|
|
|
|
err = UnpackAndRecoverMulti(
|
|
|
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
2022-05-05 22:11:50 +02:00
|
|
|
require.NoError(t, err, "unable to recover chans")
|
2018-12-10 04:02:40 +01:00
|
|
|
|
|
|
|
// Both the restorer, and connector should have been called 10 times,
|
|
|
|
// once for each backup.
|
|
|
|
if chanRestorer.callCount != numSingles {
|
|
|
|
t.Fatalf("expected %v calls, instead got %v",
|
|
|
|
numSingles, chanRestorer.callCount)
|
|
|
|
}
|
|
|
|
if peerConnector.callCount != numSingles {
|
|
|
|
t.Fatalf("expected %v calls, instead got %v",
|
|
|
|
numSingles, peerConnector.callCount)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we modify the keyRing, then unpacking should fail.
|
|
|
|
keyRing.fail = true
|
|
|
|
err = UnpackAndRecoverMulti(
|
|
|
|
packedMulti, keyRing, &chanRestorer, &peerConnector,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("unpacking should have failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(roasbeef): verify proper call args
|
|
|
|
}
|