github.com/decred/dcrlnd@v0.7.6/htlcswitch/mailbox_test.go (about)

     1  package htlcswitch
     2  
     3  import (
     4  	prand "math/rand"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/davecgh/go-spew/spew"
    10  	"github.com/decred/dcrd/dcrutil/v4"
    11  	"github.com/decred/dcrlnd/channeldb"
    12  	"github.com/decred/dcrlnd/clock"
    13  	"github.com/decred/dcrlnd/lnwallet/chainfee"
    14  	"github.com/decred/dcrlnd/lnwire"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  const testExpiry = time.Minute
    19  
    20  // TestMailBoxCouriers tests that both aspects of the mailBox struct works
    21  // properly. Both packets and messages should be able to added to each
    22  // respective mailbox concurrently, and also messages/packets should also be
    23  // able to be received concurrently.
    24  func TestMailBoxCouriers(t *testing.T) {
    25  	t.Parallel()
    26  
    27  	// First, we'll create new instance of the current default mailbox
    28  	// type.
    29  	ctx := newMailboxContext(t, time.Now(), testExpiry)
    30  	defer ctx.mailbox.Stop()
    31  
    32  	// We'll be adding 10 message of both types to the mailbox.
    33  	const numPackets = 10
    34  	const halfPackets = numPackets / 2
    35  
    36  	// We'll add a set of random packets to the mailbox.
    37  	sentPackets := make([]*htlcPacket, numPackets)
    38  	for i := 0; i < numPackets; i++ {
    39  		pkt := &htlcPacket{
    40  			outgoingChanID: lnwire.NewShortChanIDFromInt(uint64(prand.Int63())),
    41  			incomingChanID: lnwire.NewShortChanIDFromInt(uint64(prand.Int63())),
    42  			amount:         lnwire.MilliAtom(prand.Int63()),
    43  			htlc: &lnwire.UpdateAddHTLC{
    44  				ID: uint64(i),
    45  			},
    46  		}
    47  		sentPackets[i] = pkt
    48  
    49  		err := ctx.mailbox.AddPacket(pkt)
    50  		if err != nil {
    51  			t.Fatalf("unable to add packet: %v", err)
    52  		}
    53  	}
    54  
    55  	// Next, we'll do the same, but this time adding wire messages.
    56  	sentMessages := make([]lnwire.Message, numPackets)
    57  	for i := 0; i < numPackets; i++ {
    58  		msg := &lnwire.UpdateAddHTLC{
    59  			ID:     uint64(prand.Int63()),
    60  			Amount: lnwire.MilliAtom(prand.Int63()),
    61  		}
    62  		sentMessages[i] = msg
    63  
    64  		err := ctx.mailbox.AddMessage(msg)
    65  		if err != nil {
    66  			t.Fatalf("unable to add message: %v", err)
    67  		}
    68  	}
    69  
    70  	// Now we'll attempt to read back the packets/messages we added to the
    71  	// mailbox. We'll alternative reading from the message outbox vs the
    72  	// packet outbox to ensure that they work concurrently properly.
    73  	recvdPackets := make([]*htlcPacket, 0, numPackets)
    74  	recvdMessages := make([]lnwire.Message, 0, numPackets)
    75  	for i := 0; i < numPackets*2; i++ {
    76  		timeout := time.After(time.Second * 5)
    77  		if i%2 == 0 {
    78  			select {
    79  			case <-timeout:
    80  				t.Fatalf("didn't recv pkt after timeout")
    81  			case pkt := <-ctx.mailbox.PacketOutBox():
    82  				recvdPackets = append(recvdPackets, pkt)
    83  			}
    84  		} else {
    85  			select {
    86  			case <-timeout:
    87  				t.Fatalf("didn't recv message after timeout")
    88  			case msg := <-ctx.mailbox.MessageOutBox():
    89  				recvdMessages = append(recvdMessages, msg)
    90  			}
    91  		}
    92  	}
    93  
    94  	// The number of messages/packets we sent, and the number we received
    95  	// should match exactly.
    96  	if len(sentPackets) != len(recvdPackets) {
    97  		t.Fatalf("expected %v packets instead got %v", len(sentPackets),
    98  			len(recvdPackets))
    99  	}
   100  	if len(sentMessages) != len(recvdMessages) {
   101  		t.Fatalf("expected %v messages instead got %v", len(sentMessages),
   102  			len(recvdMessages))
   103  	}
   104  
   105  	// Additionally, the set of packets should match exactly, as we should
   106  	// have received the packets in the exact same ordering that we added.
   107  	if !reflect.DeepEqual(sentPackets, recvdPackets) {
   108  		t.Fatalf("recvd packets mismatched: expected %v, got %v",
   109  			spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
   110  	}
   111  	if !reflect.DeepEqual(sentMessages, recvdMessages) {
   112  		t.Fatalf("recvd messages mismatched: expected %v, got %v",
   113  			spew.Sdump(sentMessages), spew.Sdump(recvdMessages))
   114  	}
   115  
   116  	// Now that we've received all of the intended msgs/pkts, ack back half
   117  	// of the packets.
   118  	for _, recvdPkt := range recvdPackets[:halfPackets] {
   119  		ctx.mailbox.AckPacket(recvdPkt.inKey())
   120  	}
   121  
   122  	// With the packets drained and partially acked,  we reset the mailbox,
   123  	// simulating a link shutting down and then coming back up.
   124  	err := ctx.mailbox.ResetMessages()
   125  	if err != nil {
   126  		t.Fatalf("unable to reset messages: %v", err)
   127  	}
   128  	err = ctx.mailbox.ResetPackets()
   129  	if err != nil {
   130  		t.Fatalf("unable to reset packets: %v", err)
   131  	}
   132  
   133  	// Now, we'll use the same alternating strategy to read from our
   134  	// mailbox. All wire messages are dropped on startup, but any unacked
   135  	// packets will be replayed in the same order they were delivered
   136  	// initially.
   137  	recvdPackets2 := make([]*htlcPacket, 0, halfPackets)
   138  	for i := 0; i < 2*halfPackets; i++ {
   139  		timeout := time.After(time.Second * 5)
   140  		if i%2 == 0 {
   141  			select {
   142  			case <-timeout:
   143  				t.Fatalf("didn't recv pkt after timeout")
   144  			case pkt := <-ctx.mailbox.PacketOutBox():
   145  				recvdPackets2 = append(recvdPackets2, pkt)
   146  			}
   147  		} else {
   148  			select {
   149  			case <-ctx.mailbox.MessageOutBox():
   150  				t.Fatalf("should not receive wire msg after reset")
   151  			default:
   152  			}
   153  		}
   154  	}
   155  
   156  	// The number of packets we received should match the number of unacked
   157  	// packets left in the mailbox.
   158  	if halfPackets != len(recvdPackets2) {
   159  		t.Fatalf("expected %v packets instead got %v", halfPackets,
   160  			len(recvdPackets))
   161  	}
   162  
   163  	// Additionally, the set of packets should match exactly with the
   164  	// unacked packets, and we should have received the packets in the exact
   165  	// same ordering that we added.
   166  	if !reflect.DeepEqual(recvdPackets[halfPackets:], recvdPackets2) {
   167  		t.Fatalf("recvd packets mismatched: expected %v, got %v",
   168  			spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
   169  	}
   170  }
   171  
   172  // TestMailBoxResetAfterShutdown tests that ResetMessages and ResetPackets
   173  // return ErrMailBoxShuttingDown after the mailbox has been stopped.
   174  func TestMailBoxResetAfterShutdown(t *testing.T) {
   175  	t.Parallel()
   176  
   177  	ctx := newMailboxContext(t, time.Now(), time.Second)
   178  
   179  	// Stop the mailbox, then try to reset the message and packet couriers.
   180  	ctx.mailbox.Stop()
   181  
   182  	err := ctx.mailbox.ResetMessages()
   183  	if err != ErrMailBoxShuttingDown {
   184  		t.Fatalf("expected ErrMailBoxShuttingDown, got: %v", err)
   185  	}
   186  
   187  	err = ctx.mailbox.ResetPackets()
   188  	if err != ErrMailBoxShuttingDown {
   189  		t.Fatalf("expected ErrMailBoxShuttingDown, got: %v", err)
   190  	}
   191  }
   192  
   193  type mailboxContext struct {
   194  	t        *testing.T
   195  	mailbox  MailBox
   196  	clock    *clock.TestClock
   197  	forwards chan *htlcPacket
   198  }
   199  
   200  func newMailboxContext(t *testing.T, startTime time.Time,
   201  	expiry time.Duration) *mailboxContext {
   202  
   203  	ctx := &mailboxContext{
   204  		t:        t,
   205  		clock:    clock.NewTestClock(startTime),
   206  		forwards: make(chan *htlcPacket, 1),
   207  	}
   208  	ctx.mailbox = newMemoryMailBox(&mailBoxConfig{
   209  		fetchUpdate: func(sid lnwire.ShortChannelID) (
   210  			*lnwire.ChannelUpdate, error) {
   211  			return &lnwire.ChannelUpdate{
   212  				ShortChannelID: sid,
   213  			}, nil
   214  		},
   215  		forwardPackets: ctx.forward,
   216  		clock:          ctx.clock,
   217  		expiry:         expiry,
   218  	})
   219  	ctx.mailbox.Start()
   220  
   221  	return ctx
   222  }
   223  
   224  func (c *mailboxContext) forward(_ chan struct{},
   225  	pkts ...*htlcPacket) error {
   226  
   227  	for _, pkt := range pkts {
   228  		c.forwards <- pkt
   229  	}
   230  
   231  	return nil
   232  }
   233  
   234  func (c *mailboxContext) sendAdds(start, num int) []*htlcPacket {
   235  	c.t.Helper()
   236  
   237  	sentPackets := make([]*htlcPacket, num)
   238  	for i := 0; i < num; i++ {
   239  		pkt := &htlcPacket{
   240  			outgoingChanID: lnwire.NewShortChanIDFromInt(
   241  				uint64(prand.Int63())),
   242  			incomingChanID: lnwire.NewShortChanIDFromInt(
   243  				uint64(prand.Int63())),
   244  			incomingHTLCID: uint64(start + i),
   245  			amount:         lnwire.MilliAtom(prand.Int63()),
   246  			htlc: &lnwire.UpdateAddHTLC{
   247  				ID: uint64(start + i),
   248  			},
   249  		}
   250  		sentPackets[i] = pkt
   251  
   252  		err := c.mailbox.AddPacket(pkt)
   253  		if err != nil {
   254  			c.t.Fatalf("unable to add packet: %v", err)
   255  		}
   256  	}
   257  
   258  	return sentPackets
   259  }
   260  
   261  func (c *mailboxContext) receivePkts(pkts []*htlcPacket) {
   262  	c.t.Helper()
   263  
   264  	for i, expPkt := range pkts {
   265  		select {
   266  		case pkt := <-c.mailbox.PacketOutBox():
   267  			if reflect.DeepEqual(expPkt, pkt) {
   268  				continue
   269  			}
   270  
   271  			c.t.Fatalf("inkey mismatch #%d, want: %v vs "+
   272  				"got: %v", i, expPkt.inKey(), pkt.inKey())
   273  
   274  		case <-time.After(50 * time.Millisecond):
   275  			c.t.Fatalf("did not receive fail for index %d", i)
   276  		}
   277  	}
   278  }
   279  
   280  func (c *mailboxContext) checkFails(adds []*htlcPacket) {
   281  	c.t.Helper()
   282  
   283  	for i, add := range adds {
   284  		select {
   285  		case fail := <-c.forwards:
   286  			if add.inKey() == fail.inKey() {
   287  				continue
   288  			}
   289  			c.t.Fatalf("inkey mismatch #%d, add: %v vs fail: %v",
   290  				i, add.inKey(), fail.inKey())
   291  
   292  		case <-time.After(250 * time.Millisecond):
   293  			c.t.Fatalf("did not receive fail for index %d", i)
   294  		}
   295  	}
   296  
   297  	select {
   298  	case pkt := <-c.forwards:
   299  		c.t.Fatalf("unexpected forward: %v", pkt)
   300  	case <-time.After(50 * time.Millisecond):
   301  	}
   302  }
   303  
   304  // TestMailBoxFailAdd asserts that FailAdd returns a response to the switch
   305  // under various interleavings with other operations on the mailbox.
   306  func TestMailBoxFailAdd(t *testing.T) {
   307  	var (
   308  		batchDelay       = time.Second
   309  		expiry           = time.Minute
   310  		firstBatchStart  = time.Now()
   311  		secondBatchStart = time.Now().Add(batchDelay)
   312  		thirdBatchStart  = time.Now().Add(2 * batchDelay)
   313  		thirdBatchExpiry = thirdBatchStart.Add(expiry)
   314  	)
   315  	ctx := newMailboxContext(t, firstBatchStart, expiry)
   316  	defer ctx.mailbox.Stop()
   317  
   318  	failAdds := func(adds []*htlcPacket) {
   319  		for _, add := range adds {
   320  			ctx.mailbox.FailAdd(add)
   321  		}
   322  	}
   323  
   324  	const numBatchPackets = 5
   325  
   326  	// Send  10 adds, and pull them from the mailbox.
   327  	firstBatch := ctx.sendAdds(0, numBatchPackets)
   328  	ctx.receivePkts(firstBatch)
   329  
   330  	// Fail all of these adds, simulating an error adding the HTLCs to the
   331  	// commitment. We should see a failure message for each.
   332  	go failAdds(firstBatch)
   333  	ctx.checkFails(firstBatch)
   334  
   335  	// As a sanity check, Fail all of them again and assert that no
   336  	// duplicate fails are sent.
   337  	go failAdds(firstBatch)
   338  	ctx.checkFails(nil)
   339  
   340  	// Now, send a second batch of adds after a short delay and deliver them
   341  	// to the link.
   342  	ctx.clock.SetTime(secondBatchStart)
   343  	secondBatch := ctx.sendAdds(numBatchPackets, numBatchPackets)
   344  	ctx.receivePkts(secondBatch)
   345  
   346  	// Reset the packet queue w/o changing the current time. This simulates
   347  	// the link flapping and coming back up before the second batch's
   348  	// expiries have elapsed. We should see no failures sent back.
   349  	err := ctx.mailbox.ResetPackets()
   350  	if err != nil {
   351  		t.Fatalf("unable to reset packets: %v", err)
   352  	}
   353  	ctx.checkFails(nil)
   354  
   355  	// Redeliver the second batch to the link and hold them there.
   356  	ctx.receivePkts(secondBatch)
   357  
   358  	// Send a third batch of adds shortly after the second batch.
   359  	ctx.clock.SetTime(thirdBatchStart)
   360  	thirdBatch := ctx.sendAdds(2*numBatchPackets, numBatchPackets)
   361  
   362  	// Advance the clock so that the third batch expires. We expect to only
   363  	// see fails for the third batch, since the second batch is still being
   364  	// held by the link.
   365  	ctx.clock.SetTime(thirdBatchExpiry)
   366  	ctx.checkFails(thirdBatch)
   367  
   368  	// Finally, reset the link which should cause the second batch to be
   369  	// cancelled immediately.
   370  	err = ctx.mailbox.ResetPackets()
   371  	if err != nil {
   372  		t.Fatalf("unable to reset packets: %v", err)
   373  	}
   374  	ctx.checkFails(secondBatch)
   375  }
   376  
   377  // TestMailBoxPacketPrioritization asserts that the mailbox will prioritize
   378  // delivering Settle and Fail packets over Adds if both are available for
   379  // delivery at the same time.
   380  func TestMailBoxPacketPrioritization(t *testing.T) {
   381  	t.Parallel()
   382  
   383  	// First, we'll create new instance of the current default mailbox
   384  	// type.
   385  	ctx := newMailboxContext(t, time.Now(), testExpiry)
   386  	defer ctx.mailbox.Stop()
   387  
   388  	const numPackets = 5
   389  
   390  	_, _, aliceChanID, bobChanID := genIDs()
   391  
   392  	// Next we'll send the following sequence of packets:
   393  	//  - Settle1
   394  	//  - Add1
   395  	//  - Add2
   396  	//  - Fail
   397  	//  - Settle2
   398  	sentPackets := make([]*htlcPacket, numPackets)
   399  	for i := 0; i < numPackets; i++ {
   400  		pkt := &htlcPacket{
   401  			outgoingChanID: aliceChanID,
   402  			outgoingHTLCID: uint64(i),
   403  			incomingChanID: bobChanID,
   404  			incomingHTLCID: uint64(i),
   405  			amount:         lnwire.MilliAtom(prand.Int63()),
   406  		}
   407  
   408  		switch i {
   409  		case 0, 4:
   410  			// First and last packets are a Settle. A non-Add is
   411  			// sent first to make the test deterministic w/o needing
   412  			// to sleep.
   413  			pkt.htlc = &lnwire.UpdateFulfillHTLC{ID: uint64(i)}
   414  		case 1, 2:
   415  			// Next two packets are Adds.
   416  			pkt.htlc = &lnwire.UpdateAddHTLC{ID: uint64(i)}
   417  		case 3:
   418  			// Last packet is a Fail.
   419  			pkt.htlc = &lnwire.UpdateFailHTLC{ID: uint64(i)}
   420  		}
   421  
   422  		sentPackets[i] = pkt
   423  
   424  		err := ctx.mailbox.AddPacket(pkt)
   425  		if err != nil {
   426  			t.Fatalf("failed to add packet: %v", err)
   427  		}
   428  	}
   429  
   430  	// When dequeueing the packets, we expect the following sequence:
   431  	//  - Settle1
   432  	//  - Fail
   433  	//  - Settle2
   434  	//  - Add1
   435  	//  - Add2
   436  	//
   437  	// We expect to see Fail and Settle2 to be delivered before either Add1
   438  	// or Add2 due to the prioritization between the split queue.
   439  	for i := 0; i < numPackets; i++ {
   440  		select {
   441  		case pkt := <-ctx.mailbox.PacketOutBox():
   442  			var expPkt *htlcPacket
   443  			switch i {
   444  			case 0:
   445  				// First packet should be Settle1.
   446  				expPkt = sentPackets[0]
   447  			case 1:
   448  				// Second packet should be Fail.
   449  				expPkt = sentPackets[3]
   450  			case 2:
   451  				// Third packet should be Settle2.
   452  				expPkt = sentPackets[4]
   453  			case 3:
   454  				// Fourth packet should be Add1.
   455  				expPkt = sentPackets[1]
   456  			case 4:
   457  				// Last packet should be Add2.
   458  				expPkt = sentPackets[2]
   459  			}
   460  
   461  			if !reflect.DeepEqual(expPkt, pkt) {
   462  				t.Fatalf("recvd packet mismatch %d, want: %v, got: %v",
   463  					i, spew.Sdump(expPkt), spew.Sdump(pkt))
   464  			}
   465  
   466  		case <-time.After(50 * time.Millisecond):
   467  			t.Fatalf("didn't receive packet %d before timeout", i)
   468  		}
   469  	}
   470  }
   471  
   472  // TestMailBoxAddExpiry asserts that the mailbox will cancel back Adds that have
   473  // reached their expiry time.
   474  func TestMailBoxAddExpiry(t *testing.T) {
   475  	var (
   476  		expiry            = time.Minute
   477  		batchDelay        = time.Second
   478  		firstBatchStart   = time.Now()
   479  		firstBatchExpiry  = firstBatchStart.Add(expiry)
   480  		secondBatchStart  = firstBatchStart.Add(batchDelay)
   481  		secondBatchExpiry = secondBatchStart.Add(expiry)
   482  	)
   483  
   484  	ctx := newMailboxContext(t, firstBatchStart, expiry)
   485  	defer ctx.mailbox.Stop()
   486  
   487  	// Each batch will consist of 10 messages.
   488  	const numBatchPackets = 10
   489  
   490  	firstBatch := ctx.sendAdds(0, numBatchPackets)
   491  
   492  	ctx.clock.SetTime(secondBatchStart)
   493  	ctx.checkFails(nil)
   494  
   495  	secondBatch := ctx.sendAdds(numBatchPackets, numBatchPackets)
   496  
   497  	ctx.clock.SetTime(firstBatchExpiry)
   498  	ctx.checkFails(firstBatch)
   499  
   500  	ctx.clock.SetTime(secondBatchExpiry)
   501  	ctx.checkFails(secondBatch)
   502  }
   503  
   504  // TestMailBoxDuplicateAddPacket asserts that the mailbox returns an
   505  // ErrPacketAlreadyExists failure when two htlcPackets are added with identical
   506  // incoming circuit keys.
   507  func TestMailBoxDuplicateAddPacket(t *testing.T) {
   508  	t.Parallel()
   509  
   510  	ctx := newMailboxContext(t, time.Now(), testExpiry)
   511  	ctx.mailbox.Start()
   512  	defer ctx.mailbox.Stop()
   513  
   514  	addTwice := func(t *testing.T, pkt *htlcPacket) {
   515  		// The first add should succeed.
   516  		err := ctx.mailbox.AddPacket(pkt)
   517  		if err != nil {
   518  			t.Fatalf("unable to add packet: %v", err)
   519  		}
   520  
   521  		// Adding again with the same incoming circuit key should fail.
   522  		err = ctx.mailbox.AddPacket(pkt)
   523  		if err != ErrPacketAlreadyExists {
   524  			t.Fatalf("expected ErrPacketAlreadyExists, got: %v", err)
   525  		}
   526  	}
   527  
   528  	// Assert duplicate AddPacket calls fail for all types of HTLCs.
   529  	addTwice(t, &htlcPacket{
   530  		incomingHTLCID: 0,
   531  		htlc:           &lnwire.UpdateAddHTLC{},
   532  	})
   533  	addTwice(t, &htlcPacket{
   534  		incomingHTLCID: 1,
   535  		htlc:           &lnwire.UpdateFulfillHTLC{},
   536  	})
   537  	addTwice(t, &htlcPacket{
   538  		incomingHTLCID: 2,
   539  		htlc:           &lnwire.UpdateFailHTLC{},
   540  	})
   541  }
   542  
   543  // TestMailBoxDustHandling tests that DustPackets returns the expected values
   544  // for the local and remote dust sum after calling SetFeeRate and
   545  // SetDustClosure.
   546  func TestMailBoxDustHandling(t *testing.T) {
   547  	t.Run("tweakless mailbox dust", func(t *testing.T) {
   548  		testMailBoxDust(t, channeldb.SingleFunderTweaklessBit)
   549  	})
   550  	t.Run("zero htlc fee anchors mailbox dust", func(t *testing.T) {
   551  		testMailBoxDust(t, channeldb.SingleFunderTweaklessBit|
   552  			channeldb.AnchorOutputsBit|
   553  			channeldb.ZeroHtlcTxFeeBit,
   554  		)
   555  	})
   556  }
   557  
   558  func testMailBoxDust(t *testing.T, chantype channeldb.ChannelType) {
   559  	t.Parallel()
   560  
   561  	ctx := newMailboxContext(t, time.Now(), testExpiry)
   562  	defer ctx.mailbox.Stop()
   563  
   564  	_, _, aliceID, bobID := genIDs()
   565  
   566  	// It should not be the case that the MailBox has packets before the
   567  	// feeRate or dustClosure is set. This is because the mailbox is always
   568  	// created *with* its associated link and attached via AttachMailbox,
   569  	// where these parameters will be set. Even though the lifetime is
   570  	// longer than the link, the setting will persist across multiple link
   571  	// creations.
   572  	ctx.mailbox.SetFeeRate(chainfee.AtomPerKByte(253))
   573  
   574  	localDustLimit := dcrutil.Amount(400)
   575  	remoteDustLimit := dcrutil.Amount(500)
   576  	isDust := dustHelper(chantype, localDustLimit, remoteDustLimit)
   577  	ctx.mailbox.SetDustClosure(isDust)
   578  
   579  	// The first packet will be dust according to the remote dust limit,
   580  	// but not the local. We set a different amount if this is a zero fee
   581  	// htlc channel type.
   582  	firstAmt := lnwire.MilliAtom(600_000)
   583  
   584  	if chantype.ZeroHtlcTxFee() {
   585  		firstAmt = lnwire.MilliAtom(450_000)
   586  	}
   587  
   588  	firstPkt := &htlcPacket{
   589  		outgoingChanID: aliceID,
   590  		outgoingHTLCID: 0,
   591  		incomingChanID: bobID,
   592  		incomingHTLCID: 0,
   593  		amount:         firstAmt,
   594  		htlc: &lnwire.UpdateAddHTLC{
   595  			ID: uint64(0),
   596  		},
   597  	}
   598  
   599  	err := ctx.mailbox.AddPacket(firstPkt)
   600  	require.NoError(t, err)
   601  
   602  	// Assert that the local sum is 0, and the remote sum accounts for this
   603  	// added packet.
   604  	localSum, remoteSum := ctx.mailbox.DustPackets()
   605  	require.Equal(t, lnwire.MilliAtom(0), localSum)
   606  	require.Equal(t, firstAmt, remoteSum)
   607  
   608  	// The next packet will be dust according to both limits.
   609  	secondAmt := lnwire.MilliAtom(300_000)
   610  	secondPkt := &htlcPacket{
   611  		outgoingChanID: aliceID,
   612  		outgoingHTLCID: 1,
   613  		incomingChanID: bobID,
   614  		incomingHTLCID: 1,
   615  		amount:         secondAmt,
   616  		htlc: &lnwire.UpdateAddHTLC{
   617  			ID: uint64(1),
   618  		},
   619  	}
   620  
   621  	err = ctx.mailbox.AddPacket(secondPkt)
   622  	require.NoError(t, err)
   623  
   624  	// Assert that both the local and remote sums have increased by the
   625  	// second amount.
   626  	localSum, remoteSum = ctx.mailbox.DustPackets()
   627  	require.Equal(t, secondAmt, localSum)
   628  	require.Equal(t, firstAmt+secondAmt, remoteSum)
   629  
   630  	// Now we pull both packets off of the queue.
   631  	for i := 0; i < 2; i++ {
   632  		select {
   633  		case <-ctx.mailbox.PacketOutBox():
   634  		case <-time.After(50 * time.Millisecond):
   635  			ctx.t.Fatalf("did not receive packet in time")
   636  		}
   637  	}
   638  
   639  	// Assert that the sums haven't changed.
   640  	localSum, remoteSum = ctx.mailbox.DustPackets()
   641  	require.Equal(t, secondAmt, localSum)
   642  	require.Equal(t, firstAmt+secondAmt, remoteSum)
   643  
   644  	// Remove the first packet from the mailbox.
   645  	removed := ctx.mailbox.AckPacket(firstPkt.inKey())
   646  	require.True(t, removed)
   647  
   648  	// Assert that the remote sum does not include the firstAmt.
   649  	localSum, remoteSum = ctx.mailbox.DustPackets()
   650  	require.Equal(t, secondAmt, localSum)
   651  	require.Equal(t, secondAmt, remoteSum)
   652  
   653  	// Remove the second packet from the mailbox.
   654  	removed = ctx.mailbox.AckPacket(secondPkt.inKey())
   655  	require.True(t, removed)
   656  
   657  	// Assert that both sums are equal to 0.
   658  	localSum, remoteSum = ctx.mailbox.DustPackets()
   659  	require.Equal(t, lnwire.MilliAtom(0), localSum)
   660  	require.Equal(t, lnwire.MilliAtom(0), remoteSum)
   661  }
   662  
   663  // TestMailOrchestrator asserts that the orchestrator properly buffers packets
   664  // for channels that haven't been made live, such that they are delivered
   665  // immediately after BindLiveShortChanID. It also tests that packets are delivered
   666  // readily to mailboxes for channels that are already in the live state.
   667  func TestMailOrchestrator(t *testing.T) {
   668  	t.Parallel()
   669  
   670  	// First, we'll create a new instance of our orchestrator.
   671  	mo := newMailOrchestrator(&mailOrchConfig{
   672  		fetchUpdate: func(sid lnwire.ShortChannelID) (
   673  			*lnwire.ChannelUpdate, error) {
   674  			return &lnwire.ChannelUpdate{
   675  				ShortChannelID: sid,
   676  			}, nil
   677  		},
   678  		forwardPackets: func(_ chan struct{},
   679  			pkts ...*htlcPacket) error {
   680  			return nil
   681  		},
   682  		clock:  clock.NewTestClock(time.Now()),
   683  		expiry: testExpiry,
   684  	})
   685  	defer mo.Stop()
   686  
   687  	// We'll be delivering 10 htlc packets via the orchestrator.
   688  	const numPackets = 10
   689  	const halfPackets = numPackets / 2
   690  
   691  	// Before any mailbox is created or made live, we will deliver half of
   692  	// the htlcs via the orchestrator.
   693  	chanID1, chanID2, aliceChanID, bobChanID := genIDs()
   694  	sentPackets := make([]*htlcPacket, halfPackets)
   695  	for i := 0; i < halfPackets; i++ {
   696  		pkt := &htlcPacket{
   697  			outgoingChanID: aliceChanID,
   698  			outgoingHTLCID: uint64(i),
   699  			incomingChanID: bobChanID,
   700  			incomingHTLCID: uint64(i),
   701  			amount:         lnwire.MilliAtom(prand.Int63()),
   702  			htlc: &lnwire.UpdateAddHTLC{
   703  				ID: uint64(i),
   704  			},
   705  		}
   706  		sentPackets[i] = pkt
   707  
   708  		mo.Deliver(pkt.outgoingChanID, pkt)
   709  	}
   710  
   711  	// Now, initialize a new mailbox for Alice's chanid.
   712  	mailbox := mo.GetOrCreateMailBox(chanID1, aliceChanID)
   713  
   714  	// Verify that no messages are received, since Alice's mailbox has not
   715  	// been made live.
   716  	for i := 0; i < halfPackets; i++ {
   717  		timeout := time.After(50 * time.Millisecond)
   718  		select {
   719  		case <-mailbox.MessageOutBox():
   720  			t.Fatalf("should not receive wire msg after reset")
   721  		case <-timeout:
   722  		}
   723  	}
   724  
   725  	// Assign a short chan id to the existing mailbox, make it available for
   726  	// capturing incoming HTLCs. The HTLCs added above should be delivered
   727  	// immediately.
   728  	mo.BindLiveShortChanID(mailbox, chanID1, aliceChanID)
   729  
   730  	// Verify that all of the packets are queued and delivered to Alice's
   731  	// mailbox.
   732  	recvdPackets := make([]*htlcPacket, 0, len(sentPackets))
   733  	for i := 0; i < halfPackets; i++ {
   734  		timeout := time.After(5 * time.Second)
   735  		select {
   736  		case <-timeout:
   737  			t.Fatalf("didn't recv pkt %d after timeout", i)
   738  		case pkt := <-mailbox.PacketOutBox():
   739  			recvdPackets = append(recvdPackets, pkt)
   740  		}
   741  	}
   742  
   743  	// We should have received half of the total number of packets.
   744  	if len(recvdPackets) != halfPackets {
   745  		t.Fatalf("expected %v packets instead got %v",
   746  			halfPackets, len(recvdPackets))
   747  	}
   748  
   749  	// Check that the received packets are equal to the sent packets.
   750  	if !reflect.DeepEqual(recvdPackets, sentPackets) {
   751  		t.Fatalf("recvd packets mismatched: expected %v, got %v",
   752  			spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
   753  	}
   754  
   755  	// For the second half of the test, create a new mailbox for Bob and
   756  	// immediately make it live with an assigned short chan id.
   757  	mailbox = mo.GetOrCreateMailBox(chanID2, bobChanID)
   758  	mo.BindLiveShortChanID(mailbox, chanID2, bobChanID)
   759  
   760  	// Create the second half of our htlcs, and deliver them via the
   761  	// orchestrator. We should be able to receive each of these in order.
   762  	recvdPackets = make([]*htlcPacket, 0, len(sentPackets))
   763  	for i := 0; i < halfPackets; i++ {
   764  		pkt := &htlcPacket{
   765  			outgoingChanID: aliceChanID,
   766  			outgoingHTLCID: uint64(halfPackets + i),
   767  			incomingChanID: bobChanID,
   768  			incomingHTLCID: uint64(halfPackets + i),
   769  			amount:         lnwire.MilliAtom(prand.Int63()),
   770  			htlc: &lnwire.UpdateAddHTLC{
   771  				ID: uint64(halfPackets + i),
   772  			},
   773  		}
   774  		sentPackets[i] = pkt
   775  
   776  		mo.Deliver(pkt.incomingChanID, pkt)
   777  
   778  		timeout := time.After(50 * time.Millisecond)
   779  		select {
   780  		case <-timeout:
   781  			t.Fatalf("didn't recv pkt %d after timeout", halfPackets+i)
   782  		case pkt := <-mailbox.PacketOutBox():
   783  			recvdPackets = append(recvdPackets, pkt)
   784  		}
   785  	}
   786  
   787  	// Again, we should have received half of the total number of packets.
   788  	if len(recvdPackets) != halfPackets {
   789  		t.Fatalf("expected %v packets instead got %v",
   790  			halfPackets, len(recvdPackets))
   791  	}
   792  
   793  	// Check that the received packets are equal to the sent packets.
   794  	if !reflect.DeepEqual(recvdPackets, sentPackets) {
   795  		t.Fatalf("recvd packets mismatched: expected %v, got %v",
   796  			spew.Sdump(sentPackets), spew.Sdump(recvdPackets))
   797  	}
   798  }