mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-23 22:46:40 +01:00
and the same for ChannelStateDB.FetchChannel. Most of the calls to these methods provide a `nil` Tx anyways. The only place that currently provides a non-nil tx is in the `localchans.Manager`. It takes the transaction provided to the `ForAllOutgoingChannels` callback and passes it to it's `updateEdge` method. Note, however, that the `ForAllOutgoingChannels` call is a call to the graph db and the call to `updateEdge` is a call to the `ChannelStateDB`. There is no reason that these two calls need to happen under the same transaction as they are reading from two completely disjoint databases. And so in the effort to completely split untangle the relationship between the two databases, we now dont use the same transaction for these two calls.
191 lines
5.2 KiB
Go
191 lines
5.2 KiB
Go
package chanbackup
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type mockChannelSource struct {
|
|
chans map[wire.OutPoint]*channeldb.OpenChannel
|
|
|
|
failQuery bool
|
|
|
|
addrs map[[33]byte][]net.Addr
|
|
}
|
|
|
|
func newMockChannelSource() *mockChannelSource {
|
|
return &mockChannelSource{
|
|
chans: make(map[wire.OutPoint]*channeldb.OpenChannel),
|
|
addrs: make(map[[33]byte][]net.Addr),
|
|
}
|
|
}
|
|
|
|
func (m *mockChannelSource) FetchAllChannels() ([]*channeldb.OpenChannel, error) {
|
|
if m.failQuery {
|
|
return nil, fmt.Errorf("fail")
|
|
}
|
|
|
|
chans := make([]*channeldb.OpenChannel, 0, len(m.chans))
|
|
for _, channel := range m.chans {
|
|
chans = append(chans, channel)
|
|
}
|
|
|
|
return chans, nil
|
|
}
|
|
|
|
func (m *mockChannelSource) FetchChannel(chanPoint wire.OutPoint) (
|
|
*channeldb.OpenChannel, error) {
|
|
|
|
if m.failQuery {
|
|
return nil, fmt.Errorf("fail")
|
|
}
|
|
|
|
channel, ok := m.chans[chanPoint]
|
|
if !ok {
|
|
return nil, fmt.Errorf("can't find chan")
|
|
}
|
|
|
|
return channel, nil
|
|
}
|
|
|
|
func (m *mockChannelSource) addAddrsForNode(nodePub *btcec.PublicKey, addrs []net.Addr) {
|
|
var nodeKey [33]byte
|
|
copy(nodeKey[:], nodePub.SerializeCompressed())
|
|
|
|
m.addrs[nodeKey] = addrs
|
|
}
|
|
|
|
func (m *mockChannelSource) AddrsForNode(nodePub *btcec.PublicKey) (bool,
|
|
[]net.Addr, error) {
|
|
|
|
if m.failQuery {
|
|
return false, nil, fmt.Errorf("fail")
|
|
}
|
|
|
|
var nodeKey [33]byte
|
|
copy(nodeKey[:], nodePub.SerializeCompressed())
|
|
|
|
addrs, ok := m.addrs[nodeKey]
|
|
|
|
return ok, addrs, nil
|
|
}
|
|
|
|
// TestFetchBackupForChan tests that we're able to construct a single channel
|
|
// backup for channels that are known, unknown, and also channels in which we
|
|
// can find addresses for and otherwise.
|
|
func TestFetchBackupForChan(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// First, we'll make two channels, only one of them will have all the
|
|
// information we need to construct set of backups for them.
|
|
randomChan1, err := genRandomOpenChannelShell()
|
|
require.NoError(t, err, "unable to generate chan")
|
|
randomChan2, err := genRandomOpenChannelShell()
|
|
require.NoError(t, err, "unable to generate chan")
|
|
|
|
chanSource := newMockChannelSource()
|
|
chanSource.chans[randomChan1.FundingOutpoint] = randomChan1
|
|
chanSource.chans[randomChan2.FundingOutpoint] = randomChan2
|
|
|
|
chanSource.addAddrsForNode(randomChan1.IdentityPub, []net.Addr{addr1})
|
|
|
|
testCases := []struct {
|
|
chanPoint wire.OutPoint
|
|
|
|
pass bool
|
|
}{
|
|
// Able to find channel, and addresses, should pass.
|
|
{
|
|
chanPoint: randomChan1.FundingOutpoint,
|
|
pass: true,
|
|
},
|
|
|
|
// Able to find channel, not able to find addrs, should fail.
|
|
{
|
|
chanPoint: randomChan2.FundingOutpoint,
|
|
pass: false,
|
|
},
|
|
|
|
// Not able to find channel, should fail.
|
|
{
|
|
chanPoint: op,
|
|
pass: false,
|
|
},
|
|
}
|
|
for i, testCase := range testCases {
|
|
_, err := FetchBackupForChan(
|
|
testCase.chanPoint, chanSource, chanSource,
|
|
)
|
|
switch {
|
|
// If this is a valid test case, and we failed, then we'll
|
|
// return an error.
|
|
case err != nil && testCase.pass:
|
|
t.Fatalf("#%v, unable to make chan backup: %v", i, err)
|
|
|
|
// If this is an invalid test case, and we passed it, then
|
|
// we'll return an error.
|
|
case err == nil && !testCase.pass:
|
|
t.Fatalf("#%v got nil error for invalid req: %v",
|
|
i, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestFetchStaticChanBackups tests that we're able to properly query the
|
|
// channel source for all channels and construct a Single for each channel.
|
|
func TestFetchStaticChanBackups(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// First, we'll make the set of channels that we want to seed the
|
|
// channel source with. Both channels will be fully populated in the
|
|
// channel source.
|
|
const numChans = 2
|
|
randomChan1, err := genRandomOpenChannelShell()
|
|
require.NoError(t, err, "unable to generate chan")
|
|
randomChan2, err := genRandomOpenChannelShell()
|
|
require.NoError(t, err, "unable to generate chan")
|
|
|
|
chanSource := newMockChannelSource()
|
|
chanSource.chans[randomChan1.FundingOutpoint] = randomChan1
|
|
chanSource.chans[randomChan2.FundingOutpoint] = randomChan2
|
|
chanSource.addAddrsForNode(randomChan1.IdentityPub, []net.Addr{addr1})
|
|
chanSource.addAddrsForNode(randomChan2.IdentityPub, []net.Addr{addr2})
|
|
|
|
// With the channel source populated, we'll now attempt to create a set
|
|
// of backups for all the channels. This should succeed, as all items
|
|
// are populated within the channel source.
|
|
backups, err := FetchStaticChanBackups(chanSource, chanSource)
|
|
require.NoError(t, err, "unable to create chan back ups")
|
|
|
|
if len(backups) != numChans {
|
|
t.Fatalf("expected %v chans, instead got %v", numChans,
|
|
len(backups))
|
|
}
|
|
|
|
// We'll attempt to create a set up backups again, but this time the
|
|
// second channel will have missing information, which should cause the
|
|
// query to fail.
|
|
var n [33]byte
|
|
copy(n[:], randomChan2.IdentityPub.SerializeCompressed())
|
|
delete(chanSource.addrs, n)
|
|
|
|
_, err = FetchStaticChanBackups(chanSource, chanSource)
|
|
if err == nil {
|
|
t.Fatalf("query with incomplete information should fail")
|
|
}
|
|
|
|
// To wrap up, we'll ensure that if we're unable to query the channel
|
|
// source at all, then we'll fail as well.
|
|
chanSource = newMockChannelSource()
|
|
chanSource.failQuery = true
|
|
_, err = FetchStaticChanBackups(chanSource, chanSource)
|
|
if err == nil {
|
|
t.Fatalf("query should fail")
|
|
}
|
|
}
|