mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
268 lines
8.5 KiB
Go
268 lines
8.5 KiB
Go
package htlcswitch
|
|
|
|
import (
|
|
prand "math/rand"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
)
|
|
|
|
// TestMailBoxCouriers tests that both aspects of the mailBox struct works
|
|
// properly. Both packets and messages should be able to added to each
|
|
// respective mailbox concurrently, and also messages/packets should also be
|
|
// able to be received concurrently.
|
|
func TestMailBoxCouriers(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// First, we'll create new instance of the current default mailbox
|
|
// type.
|
|
mailBox := newMemoryMailBox()
|
|
mailBox.Start()
|
|
defer mailBox.Stop()
|
|
|
|
// We'll be adding 10 message of both types to the mailbox.
|
|
const numPackets = 10
|
|
const halfPackets = numPackets / 2
|
|
|
|
// We'll add a set of random packets to the mailbox.
|
|
sentPackets := make([]*htlcPacket, numPackets)
|
|
for i := 0; i < numPackets; i++ {
|
|
pkt := &htlcPacket{
|
|
outgoingChanID: lnwire.NewShortChanIDFromInt(uint64(prand.Int63())),
|
|
incomingChanID: lnwire.NewShortChanIDFromInt(uint64(prand.Int63())),
|
|
amount: lnwire.MilliSatoshi(prand.Int63()),
|
|
}
|
|
sentPackets[i] = pkt
|
|
|
|
mailBox.AddPacket(pkt)
|
|
}
|
|
|
|
// Next, we'll do the same, but this time adding wire messages.
|
|
sentMessages := make([]lnwire.Message, numPackets)
|
|
for i := 0; i < numPackets; i++ {
|
|
msg := &lnwire.UpdateAddHTLC{
|
|
ID: uint64(prand.Int63()),
|
|
Amount: lnwire.MilliSatoshi(prand.Int63()),
|
|
}
|
|
sentMessages[i] = msg
|
|
|
|
mailBox.AddMessage(msg)
|
|
}
|
|
|
|
// Now we'll attempt to read back the packets/messages we added to the
|
|
// mailbox. We'll alternative reading from the message outbox vs the
|
|
// packet outbox to ensure that they work concurrently properly.
|
|
recvdPackets := make([]*htlcPacket, 0, numPackets)
|
|
recvdMessages := make([]lnwire.Message, 0, numPackets)
|
|
for i := 0; i < numPackets*2; i++ {
|
|
timeout := time.After(time.Second * 5)
|
|
if i%2 == 0 {
|
|
select {
|
|
case <-timeout:
|
|
t.Fatalf("didn't recv pkt after timeout")
|
|
case pkt := <-mailBox.PacketOutBox():
|
|
recvdPackets = append(recvdPackets, pkt)
|
|
}
|
|
} else {
|
|
select {
|
|
case <-timeout:
|
|
t.Fatalf("didn't recv message after timeout")
|
|
case msg := <-mailBox.MessageOutBox():
|
|
recvdMessages = append(recvdMessages, msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The number of messages/packets we sent, and the number we received
|
|
// should match exactly.
|
|
if len(sentPackets) != len(recvdPackets) {
|
|
t.Fatalf("expected %v packets instead got %v", len(sentPackets),
|
|
len(recvdPackets))
|
|
}
|
|
if len(sentMessages) != len(recvdMessages) {
|
|
t.Fatalf("expected %v messages instead got %v", len(sentMessages),
|
|
len(recvdMessages))
|
|
}
|
|
|
|
// Additionally, the set of packets should match exactly, as we should
|
|
// have received the packets in the exact same ordering that we added.
|
|
if !reflect.DeepEqual(sentPackets, recvdPackets) {
|
|
t.Fatalf("recvd packets mismatched: expected %v, got %v",
|
|
spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
|
|
}
|
|
if !reflect.DeepEqual(recvdMessages, recvdMessages) {
|
|
t.Fatalf("recvd messages mismatched: expected %v, got %v",
|
|
spew.Sdump(sentMessages), spew.Sdump(recvdMessages))
|
|
}
|
|
|
|
// Now that we've received all of the intended msgs/pkts, ack back half
|
|
// of the packets.
|
|
for _, recvdPkt := range recvdPackets[:halfPackets] {
|
|
mailBox.AckPacket(recvdPkt.inKey())
|
|
}
|
|
|
|
// With the packets drained and partially acked, we reset the mailbox,
|
|
// simulating a link shutting down and then coming back up.
|
|
mailBox.ResetMessages()
|
|
mailBox.ResetPackets()
|
|
|
|
// Now, we'll use the same alternating strategy to read from our
|
|
// mailbox. All wire messages are dropped on startup, but any unacked
|
|
// packets will be replayed in the same order they were delivered
|
|
// initially.
|
|
recvdPackets2 := make([]*htlcPacket, 0, halfPackets)
|
|
for i := 0; i < 2*halfPackets; i++ {
|
|
timeout := time.After(time.Second * 5)
|
|
if i%2 == 0 {
|
|
select {
|
|
case <-timeout:
|
|
t.Fatalf("didn't recv pkt after timeout")
|
|
case pkt := <-mailBox.PacketOutBox():
|
|
recvdPackets2 = append(recvdPackets2, pkt)
|
|
}
|
|
} else {
|
|
select {
|
|
case <-mailBox.MessageOutBox():
|
|
t.Fatalf("should not receive wire msg after reset")
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
// The number of packets we received should match the number of unacked
|
|
// packets left in the mailbox.
|
|
if halfPackets != len(recvdPackets2) {
|
|
t.Fatalf("expected %v packets instead got %v", halfPackets,
|
|
len(recvdPackets))
|
|
}
|
|
|
|
// Additionally, the set of packets should match exactly with the
|
|
// unacked packets, and we should have received the packets in the exact
|
|
// same ordering that we added.
|
|
if !reflect.DeepEqual(recvdPackets[halfPackets:], recvdPackets2) {
|
|
t.Fatalf("recvd packets mismatched: expected %v, got %v",
|
|
spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
|
|
}
|
|
}
|
|
|
|
// TestMailOrchestrator asserts that the orchestrator properly buffers packets
|
|
// for channels that haven't been made live, such that they are delivered
|
|
// immediately after BindLiveShortChanID. It also tests that packets are delivered
|
|
// readily to mailboxes for channels that are already in the live state.
|
|
func TestMailOrchestrator(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// First, we'll create a new instance of our orchestrator.
|
|
mo := newMailOrchestrator()
|
|
defer mo.Stop()
|
|
|
|
// We'll be delivering 10 htlc packets via the orchestrator.
|
|
const numPackets = 10
|
|
const halfPackets = numPackets / 2
|
|
|
|
// Before any mailbox is created or made live, we will deliver half of
|
|
// the htlcs via the orchestrator.
|
|
chanID1, chanID2, aliceChanID, bobChanID := genIDs()
|
|
sentPackets := make([]*htlcPacket, halfPackets)
|
|
for i := 0; i < halfPackets; i++ {
|
|
pkt := &htlcPacket{
|
|
outgoingChanID: aliceChanID,
|
|
outgoingHTLCID: uint64(i),
|
|
incomingChanID: bobChanID,
|
|
incomingHTLCID: uint64(i),
|
|
amount: lnwire.MilliSatoshi(prand.Int63()),
|
|
}
|
|
sentPackets[i] = pkt
|
|
|
|
mo.Deliver(pkt.outgoingChanID, pkt)
|
|
}
|
|
|
|
// Now, initialize a new mailbox for Alice's chanid.
|
|
mailbox := mo.GetOrCreateMailBox(chanID1)
|
|
|
|
// Verify that no messages are received, since Alice's mailbox has not
|
|
// been made live.
|
|
for i := 0; i < halfPackets; i++ {
|
|
timeout := time.After(50 * time.Millisecond)
|
|
select {
|
|
case <-mailbox.MessageOutBox():
|
|
t.Fatalf("should not receive wire msg after reset")
|
|
case <-timeout:
|
|
}
|
|
}
|
|
|
|
// Assign a short chan id to the existing mailbox, make it available for
|
|
// capturing incoming HTLCs. The HTLCs added above should be delivered
|
|
// immediately.
|
|
mo.BindLiveShortChanID(mailbox, chanID1, aliceChanID)
|
|
|
|
// Verify that all of the packets are queued and delivered to Alice's
|
|
// mailbox.
|
|
recvdPackets := make([]*htlcPacket, 0, len(sentPackets))
|
|
for i := 0; i < halfPackets; i++ {
|
|
timeout := time.After(5 * time.Second)
|
|
select {
|
|
case <-timeout:
|
|
t.Fatalf("didn't recv pkt %d after timeout", i)
|
|
case pkt := <-mailbox.PacketOutBox():
|
|
recvdPackets = append(recvdPackets, pkt)
|
|
}
|
|
}
|
|
|
|
// We should have received half of the total number of packets.
|
|
if len(recvdPackets) != halfPackets {
|
|
t.Fatalf("expected %v packets instead got %v",
|
|
halfPackets, len(recvdPackets))
|
|
}
|
|
|
|
// Check that the received packets are equal to the sent packets.
|
|
if !reflect.DeepEqual(recvdPackets, sentPackets) {
|
|
t.Fatalf("recvd packets mismatched: expected %v, got %v",
|
|
spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
|
|
}
|
|
|
|
// For the second half of the test, create a new mailbox for Bob and
|
|
// immediately make it live with an assigned short chan id.
|
|
mailbox = mo.GetOrCreateMailBox(chanID2)
|
|
mo.BindLiveShortChanID(mailbox, chanID2, bobChanID)
|
|
|
|
// Create the second half of our htlcs, and deliver them via the
|
|
// orchestrator. We should be able to receive each of these in order.
|
|
recvdPackets = make([]*htlcPacket, 0, len(sentPackets))
|
|
for i := 0; i < halfPackets; i++ {
|
|
pkt := &htlcPacket{
|
|
outgoingChanID: aliceChanID,
|
|
outgoingHTLCID: uint64(halfPackets + i),
|
|
incomingChanID: bobChanID,
|
|
incomingHTLCID: uint64(halfPackets + i),
|
|
amount: lnwire.MilliSatoshi(prand.Int63()),
|
|
}
|
|
sentPackets[i] = pkt
|
|
|
|
mo.Deliver(pkt.incomingChanID, pkt)
|
|
|
|
timeout := time.After(50 * time.Millisecond)
|
|
select {
|
|
case <-timeout:
|
|
t.Fatalf("didn't recv pkt %d after timeout", halfPackets+i)
|
|
case pkt := <-mailbox.PacketOutBox():
|
|
recvdPackets = append(recvdPackets, pkt)
|
|
}
|
|
}
|
|
|
|
// Again, we should have received half of the total number of packets.
|
|
if len(recvdPackets) != halfPackets {
|
|
t.Fatalf("expected %v packets instead got %v",
|
|
halfPackets, len(recvdPackets))
|
|
}
|
|
|
|
// Check that the received packets are equal to the sent packets.
|
|
if !reflect.DeepEqual(recvdPackets, sentPackets) {
|
|
t.Fatalf("recvd packets mismatched: expected %v, got %v",
|
|
spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
|
|
}
|
|
}
|