mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
99b86ba462
This will be used in the gossiper to disconnect from peers if their ban score passes the ban threshold.
292 lines
8.9 KiB
Go
292 lines
8.9 KiB
Go
package discovery
|
|
|
|
import (
|
|
"fmt"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/davecgh/go-spew/spew"
|
|
"github.com/lightningnetwork/lnd/lnpeer"
|
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
)
|
|
|
|
// newTestReliableSender creates a new reliable sender instance used for
|
|
// testing.
|
|
func newTestReliableSender(t *testing.T) *reliableSender {
|
|
t.Helper()
|
|
|
|
cfg := &reliableSenderCfg{
|
|
NotifyWhenOnline: func(pubKey [33]byte,
|
|
peerChan chan<- lnpeer.Peer) {
|
|
pk, err := btcec.ParsePubKey(pubKey[:])
|
|
if err != nil {
|
|
t.Fatalf("unable to parse pubkey: %v", err)
|
|
}
|
|
peerChan <- &mockPeer{pk: pk}
|
|
},
|
|
NotifyWhenOffline: func(_ [33]byte) <-chan struct{} {
|
|
c := make(chan struct{}, 1)
|
|
return c
|
|
},
|
|
MessageStore: newMockMessageStore(),
|
|
IsMsgStale: func(lnwire.Message) bool {
|
|
return false
|
|
},
|
|
}
|
|
|
|
return newReliableSender(cfg)
|
|
}
|
|
|
|
// assertMsgsSent ensures that the given messages can be read from a mock peer's
|
|
// msgChan.
|
|
func assertMsgsSent(t *testing.T, msgChan chan lnwire.Message,
|
|
msgs ...lnwire.Message) {
|
|
|
|
t.Helper()
|
|
|
|
m := make(map[lnwire.Message]struct{}, len(msgs))
|
|
for _, msg := range msgs {
|
|
m[msg] = struct{}{}
|
|
}
|
|
|
|
for i := 0; i < len(msgs); i++ {
|
|
select {
|
|
case msg := <-msgChan:
|
|
if _, ok := m[msg]; !ok {
|
|
t.Fatalf("found unexpected message sent: %v",
|
|
spew.Sdump(msg))
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("reliable sender did not send message to peer")
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestReliableSenderFlow ensures that the flow for sending messages reliably to
|
|
// a peer while taking into account its connection lifecycle works as expected.
|
|
func TestReliableSenderFlow(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reliableSender := newTestReliableSender(t)
|
|
|
|
// Create a mock peer to send the messages to.
|
|
pubKey := randPubKey(t)
|
|
msgsSent := make(chan lnwire.Message)
|
|
peer := &mockPeer{pubKey, msgsSent, reliableSender.quit, atomic.Bool{}}
|
|
|
|
// Override NotifyWhenOnline and NotifyWhenOffline to provide the
|
|
// notification channels so that we can control when notifications get
|
|
// dispatched.
|
|
notifyOnline := make(chan chan<- lnpeer.Peer, 2)
|
|
notifyOffline := make(chan chan struct{}, 1)
|
|
|
|
reliableSender.cfg.NotifyWhenOnline = func(_ [33]byte,
|
|
peerChan chan<- lnpeer.Peer) {
|
|
notifyOnline <- peerChan
|
|
}
|
|
reliableSender.cfg.NotifyWhenOffline = func(_ [33]byte) <-chan struct{} {
|
|
c := make(chan struct{}, 1)
|
|
notifyOffline <- c
|
|
return c
|
|
}
|
|
|
|
// We'll start by creating our first message which we should reliably
|
|
// send to our peer.
|
|
msg1 := randChannelUpdate()
|
|
var peerPubKey [33]byte
|
|
copy(peerPubKey[:], pubKey.SerializeCompressed())
|
|
if err := reliableSender.sendMessage(msg1, peerPubKey); err != nil {
|
|
t.Fatalf("unable to reliably send message: %v", err)
|
|
}
|
|
|
|
// Since there isn't a peerHandler for this peer currently active due to
|
|
// this being the first message being sent reliably, we should expect to
|
|
// see a notification request for when the peer is online.
|
|
var peerChan chan<- lnpeer.Peer
|
|
select {
|
|
case peerChan = <-notifyOnline:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("reliable sender did not request online notification")
|
|
}
|
|
|
|
// We'll then attempt to send another additional message reliably.
|
|
msg2 := randAnnounceSignatures()
|
|
if err := reliableSender.sendMessage(msg2, peerPubKey); err != nil {
|
|
t.Fatalf("unable to reliably send message: %v", err)
|
|
}
|
|
|
|
// This should not however request another peer online notification as
|
|
// the peerHandler has already been started and is waiting for the
|
|
// notification to be dispatched.
|
|
select {
|
|
case <-notifyOnline:
|
|
t.Fatal("reliable sender should not request online notification")
|
|
case <-time.After(time.Second):
|
|
}
|
|
|
|
// We'll go ahead and notify the peer.
|
|
peerChan <- peer
|
|
|
|
// By doing so, we should expect to see a notification request for when
|
|
// the peer is offline.
|
|
var offlineChan chan struct{}
|
|
select {
|
|
case offlineChan = <-notifyOffline:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("reliable sender did not request offline notification")
|
|
}
|
|
|
|
// We should also see the messages arrive at the peer since they are now
|
|
// seen as online.
|
|
assertMsgsSent(t, peer.sentMsgs, msg1, msg2)
|
|
|
|
// Then, we'll send one more message reliably.
|
|
msg3 := randChannelUpdate()
|
|
if err := reliableSender.sendMessage(msg3, peerPubKey); err != nil {
|
|
t.Fatalf("unable to reliably send message: %v", err)
|
|
}
|
|
|
|
// Again, this should not request another peer online notification
|
|
// request since we are currently waiting for the peer to be offline.
|
|
select {
|
|
case <-notifyOnline:
|
|
t.Fatal("reliable sender should not request online notification")
|
|
case <-time.After(time.Second):
|
|
}
|
|
|
|
// The expected message should be sent to the peer.
|
|
assertMsgsSent(t, peer.sentMsgs, msg3)
|
|
|
|
// We'll then notify that the peer is offline.
|
|
close(offlineChan)
|
|
|
|
// This should cause an online notification to be requested.
|
|
select {
|
|
case peerChan = <-notifyOnline:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("reliable sender did not request online notification")
|
|
}
|
|
|
|
// Once we dispatch it, we should expect to see the messages be resent
|
|
// to the peer as they are not stale.
|
|
peerChan <- peer
|
|
|
|
select {
|
|
case <-notifyOffline:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("reliable sender did not request offline notification")
|
|
}
|
|
|
|
assertMsgsSent(t, peer.sentMsgs, msg1, msg2, msg3)
|
|
}
|
|
|
|
// TestReliableSenderStaleMessages ensures that the reliable sender is no longer
|
|
// active for a peer which has successfully sent all of its messages and deemed
|
|
// them as stale.
|
|
func TestReliableSenderStaleMessages(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reliableSender := newTestReliableSender(t)
|
|
|
|
// Create a mock peer to send the messages to.
|
|
pubKey := randPubKey(t)
|
|
msgsSent := make(chan lnwire.Message)
|
|
peer := &mockPeer{pubKey, msgsSent, reliableSender.quit, atomic.Bool{}}
|
|
|
|
// Override NotifyWhenOnline to provide the notification channel so that
|
|
// we can control when notifications get dispatched.
|
|
notifyOnline := make(chan chan<- lnpeer.Peer, 1)
|
|
reliableSender.cfg.NotifyWhenOnline = func(_ [33]byte,
|
|
peerChan chan<- lnpeer.Peer) {
|
|
notifyOnline <- peerChan
|
|
}
|
|
|
|
// We'll also override IsMsgStale to mark all messages as stale as we're
|
|
// interested in testing the stale message behavior.
|
|
reliableSender.cfg.IsMsgStale = func(_ lnwire.Message) bool {
|
|
return true
|
|
}
|
|
|
|
// We'll start by creating our first message which we should reliably
|
|
// send to our peer, but will be seen as stale.
|
|
msg1 := randAnnounceSignatures()
|
|
var peerPubKey [33]byte
|
|
copy(peerPubKey[:], pubKey.SerializeCompressed())
|
|
if err := reliableSender.sendMessage(msg1, peerPubKey); err != nil {
|
|
t.Fatalf("unable to reliably send message: %v", err)
|
|
}
|
|
|
|
// Since there isn't a peerHandler for this peer currently active due to
|
|
// this being the first message being sent reliably, we should expect to
|
|
// see a notification request for when the peer is online.
|
|
var peerChan chan<- lnpeer.Peer
|
|
select {
|
|
case peerChan = <-notifyOnline:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("reliable sender did not request online notification")
|
|
}
|
|
|
|
// We'll go ahead and notify the peer.
|
|
peerChan <- peer
|
|
|
|
// This should cause the message to be sent to the peer since they are
|
|
// now seen as online. The message will be sent at least once to ensure
|
|
// they can propagate before deciding whether they are stale or not.
|
|
assertMsgsSent(t, peer.sentMsgs, msg1)
|
|
|
|
// We'll create another message which we'll send reliably. This one
|
|
// won't be seen as stale.
|
|
msg2 := randChannelUpdate()
|
|
|
|
// We'll then wait for the message to be removed from the backing
|
|
// message store since it is seen as stale and has been sent at least
|
|
// once. Once the message is removed, the peerHandler should be torn
|
|
// down as there are no longer any pending messages within the store.
|
|
err := wait.NoError(func() error {
|
|
msgs, err := reliableSender.cfg.MessageStore.MessagesForPeer(
|
|
peerPubKey,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to retrieve messages for "+
|
|
"peer: %v", err)
|
|
}
|
|
if len(msgs) != 0 {
|
|
return fmt.Errorf("expected to not find any "+
|
|
"messages for peer, found %d", len(msgs))
|
|
}
|
|
|
|
return nil
|
|
}, time.Second)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Override IsMsgStale to no longer mark messages as stale.
|
|
reliableSender.cfg.IsMsgStale = func(_ lnwire.Message) bool {
|
|
return false
|
|
}
|
|
|
|
// We'll request the message to be sent reliably.
|
|
if err := reliableSender.sendMessage(msg2, peerPubKey); err != nil {
|
|
t.Fatalf("unable to reliably send message: %v", err)
|
|
}
|
|
|
|
// We should see an online notification request indicating that a new
|
|
// peerHandler has been spawned since it was previously torn down.
|
|
select {
|
|
case peerChan = <-notifyOnline:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("reliable sender did not request online notification")
|
|
}
|
|
|
|
// Finally, notifying the peer is online should prompt the message to be
|
|
// sent. Only the ChannelUpdate will be sent in this case since the
|
|
// AnnounceSignatures message above was seen as stale.
|
|
peerChan <- peer
|
|
|
|
assertMsgsSent(t, peer.sentMsgs, msg2)
|
|
}
|