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 }