github.com/decred/dcrlnd@v0.7.6/routing/payment_lifecycle_test.go (about) 1 package routing 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "sync/atomic" 7 "testing" 8 "time" 9 10 "github.com/decred/dcrd/dcrutil/v4" 11 "github.com/decred/dcrlnd/channeldb" 12 "github.com/decred/dcrlnd/clock" 13 "github.com/decred/dcrlnd/htlcswitch" 14 "github.com/decred/dcrlnd/lntypes" 15 "github.com/decred/dcrlnd/lnwire" 16 "github.com/decred/dcrlnd/routing/route" 17 "github.com/go-errors/errors" 18 "github.com/stretchr/testify/require" 19 ) 20 21 const stepTimeout = 5 * time.Second 22 23 // createTestRoute builds a route a->b->c paying the given amt to c. 24 func createTestRoute(amt lnwire.MilliAtom, 25 aliasMap map[string]route.Vertex) (*route.Route, error) { 26 27 hopFee := lnwire.NewMAtomsFromAtoms(3) 28 hop1 := aliasMap["b"] 29 hop2 := aliasMap["c"] 30 hops := []*route.Hop{ 31 { 32 ChannelID: 1, 33 PubKeyBytes: hop1, 34 LegacyPayload: true, 35 AmtToForward: amt + hopFee, 36 }, 37 { 38 ChannelID: 2, 39 PubKeyBytes: hop2, 40 LegacyPayload: true, 41 AmtToForward: amt, 42 }, 43 } 44 45 // We create a simple route that we will supply every time the router 46 // requests one. 47 return route.NewRouteFromHops( 48 amt+2*hopFee, 100, aliasMap["a"], hops, 49 ) 50 } 51 52 // paymentLifecycleTestCase contains the steps that we expect for a payment 53 // lifecycle test, and the routes that pathfinding should deliver. 54 type paymentLifecycleTestCase struct { 55 name string 56 57 // steps is a list of steps to perform during the testcase. 58 steps []string 59 60 // routes is the sequence of routes we will provide to the 61 // router when it requests a new route. 62 routes []*route.Route 63 64 // paymentErr is the error we expect our payment to fail with. This 65 // should be nil for tests with paymentSuccess steps and non-nil for 66 // payments with paymentError steps. 67 paymentErr error 68 } 69 70 const ( 71 // routerInitPayment is a test step where we expect the router 72 // to call the InitPayment method on the control tower. 73 routerInitPayment = "Router:init-payment" 74 75 // routerRegisterAttempt is a test step where we expect the 76 // router to call the RegisterAttempt method on the control 77 // tower. 78 routerRegisterAttempt = "Router:register-attempt" 79 80 // routerSettleAttempt is a test step where we expect the 81 // router to call the SettleAttempt method on the control 82 // tower. 83 routerSettleAttempt = "Router:settle-attempt" 84 85 // routerFailAttempt is a test step where we expect the router 86 // to call the FailAttempt method on the control tower. 87 routerFailAttempt = "Router:fail-attempt" 88 89 // routerFailPayment is a test step where we expect the router 90 // to call the Fail method on the control tower. 91 routerFailPayment = "Router:fail-payment" 92 93 // routeRelease is a test step where we unblock pathfinding and 94 // allow it to respond to our test with a route. 95 routeRelease = "PaymentSession:release" 96 97 // sendToSwitchSuccess is a step where we expect the router to 98 // call send the payment attempt to the switch, and we will 99 // respond with a non-error, indicating that the payment 100 // attempt was successfully forwarded. 101 sendToSwitchSuccess = "SendToSwitch:success" 102 103 // sendToSwitchResultFailure is a step where we expect the 104 // router to send the payment attempt to the switch, and we 105 // will respond with a forwarding error. This can happen when 106 // forwarding fail on our local links. 107 sendToSwitchResultFailure = "SendToSwitch:failure" 108 109 // getPaymentResultSuccess is a test step where we expect the 110 // router to call the GetPaymentResult method, and we will 111 // respond with a successful payment result. 112 getPaymentResultSuccess = "GetPaymentResult:success" 113 114 // getPaymentResultTempFailure is a test step where we expect the 115 // router to call the GetPaymentResult method, and we will 116 // respond with a forwarding error, expecting the router to retry. 117 getPaymentResultTempFailure = "GetPaymentResult:temp-failure" 118 119 // getPaymentResultTerminalFailure is a test step where we 120 // expect the router to call the GetPaymentResult method, and 121 // we will respond with a terminal error, expecting the router 122 // to stop making payment attempts. 123 getPaymentResultTerminalFailure = "GetPaymentResult:terminal-failure" 124 125 // resendPayment is a test step where we manually try to resend 126 // the same payment, making sure the router responds with an 127 // error indicating that it is already in flight. 128 resendPayment = "ResendPayment" 129 130 // startRouter is a step where we manually start the router, 131 // used to test that it automatically will resume payments at 132 // startup. 133 startRouter = "StartRouter" 134 135 // stopRouter is a test step where we manually make the router 136 // shut down. 137 stopRouter = "StopRouter" 138 139 // paymentSuccess is a step where assert that we receive a 140 // successful result for the original payment made. 141 paymentSuccess = "PaymentSuccess" 142 143 // paymentError is a step where assert that we receive an error 144 // for the original payment made. 145 paymentError = "PaymentError" 146 147 // resentPaymentSuccess is a step where assert that we receive 148 // a successful result for a payment that was resent. 149 resentPaymentSuccess = "ResentPaymentSuccess" 150 151 // resentPaymentError is a step where assert that we receive an 152 // error for a payment that was resent. 153 resentPaymentError = "ResentPaymentError" 154 ) 155 156 // TestRouterPaymentStateMachine tests that the router interacts as expected 157 // with the ControlTower during a payment lifecycle, such that it payment 158 // attempts are not sent twice to the switch, and results are handled after a 159 // restart. 160 func TestRouterPaymentStateMachine(t *testing.T) { 161 t.Parallel() 162 163 const startingBlockHeight = 101 164 165 // Setup two simple channels such that we can mock sending along this 166 // route. 167 chanCapSat := dcrutil.Amount(100000) 168 testChannels := []*testChannel{ 169 symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{ 170 Expiry: 144, 171 FeeRate: 400, 172 MinHTLC: 1, 173 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 174 }, 1), 175 symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{ 176 Expiry: 144, 177 FeeRate: 400, 178 MinHTLC: 1, 179 MaxHTLC: lnwire.NewMAtomsFromAtoms(chanCapSat), 180 }, 2), 181 } 182 183 testGraph, err := createTestGraphFromChannels(true, testChannels, "a") 184 if err != nil { 185 t.Fatalf("unable to create graph: %v", err) 186 } 187 defer testGraph.cleanUp() 188 189 paymentAmt := lnwire.NewMAtomsFromAtoms(1000) 190 191 // We create a simple route that we will supply every time the router 192 // requests one. 193 rt, err := createTestRoute(paymentAmt, testGraph.aliasMap) 194 if err != nil { 195 t.Fatalf("unable to create route: %v", err) 196 } 197 198 tests := []paymentLifecycleTestCase{ 199 { 200 // Tests a normal payment flow that succeeds. 201 name: "single shot success", 202 203 steps: []string{ 204 routerInitPayment, 205 routeRelease, 206 routerRegisterAttempt, 207 sendToSwitchSuccess, 208 getPaymentResultSuccess, 209 routerSettleAttempt, 210 paymentSuccess, 211 }, 212 routes: []*route.Route{rt}, 213 }, 214 { 215 // A payment flow with a failure on the first attempt, 216 // but that succeeds on the second attempt. 217 name: "single shot retry", 218 219 steps: []string{ 220 routerInitPayment, 221 routeRelease, 222 routerRegisterAttempt, 223 sendToSwitchSuccess, 224 225 // Make the first sent attempt fail. 226 getPaymentResultTempFailure, 227 routerFailAttempt, 228 229 // The router should retry. 230 routeRelease, 231 routerRegisterAttempt, 232 sendToSwitchSuccess, 233 234 // Make the second sent attempt succeed. 235 getPaymentResultSuccess, 236 routerSettleAttempt, 237 paymentSuccess, 238 }, 239 routes: []*route.Route{rt, rt}, 240 }, 241 { 242 // A payment flow with a forwarding failure first time 243 // sending to the switch, but that succeeds on the 244 // second attempt. 245 name: "single shot switch failure", 246 247 steps: []string{ 248 routerInitPayment, 249 routeRelease, 250 routerRegisterAttempt, 251 252 // Make the first sent attempt fail. 253 sendToSwitchResultFailure, 254 routerFailAttempt, 255 256 // The router should retry. 257 routeRelease, 258 routerRegisterAttempt, 259 sendToSwitchSuccess, 260 261 // Make the second sent attempt succeed. 262 getPaymentResultSuccess, 263 routerSettleAttempt, 264 paymentSuccess, 265 }, 266 routes: []*route.Route{rt, rt}, 267 }, 268 { 269 // A payment that fails on the first attempt, and has 270 // only one route available to try. It will therefore 271 // fail permanently. 272 name: "single shot route fails", 273 274 steps: []string{ 275 routerInitPayment, 276 routeRelease, 277 routerRegisterAttempt, 278 sendToSwitchSuccess, 279 280 // Make the first sent attempt fail. 281 getPaymentResultTempFailure, 282 routerFailAttempt, 283 284 routeRelease, 285 286 // Since there are no more routes to try, the 287 // payment should fail. 288 routerFailPayment, 289 paymentError, 290 }, 291 routes: []*route.Route{rt}, 292 paymentErr: channeldb.FailureReasonNoRoute, 293 }, 294 { 295 // We expect the payment to fail immediately if we have 296 // no routes to try. 297 name: "single shot no route", 298 299 steps: []string{ 300 routerInitPayment, 301 routeRelease, 302 routerFailPayment, 303 paymentError, 304 }, 305 routes: []*route.Route{}, 306 paymentErr: channeldb.FailureReasonNoRoute, 307 }, 308 { 309 // A normal payment flow, where we attempt to resend 310 // the same payment after each step. This ensures that 311 // the router don't attempt to resend a payment already 312 // in flight. 313 name: "single shot resend", 314 315 steps: []string{ 316 routerInitPayment, 317 routeRelease, 318 routerRegisterAttempt, 319 320 // Manually resend the payment, the router 321 // should attempt to init with the control 322 // tower, but fail since it is already in 323 // flight. 324 resendPayment, 325 routerInitPayment, 326 resentPaymentError, 327 328 // The original payment should proceed as 329 // normal. 330 sendToSwitchSuccess, 331 332 // Again resend the payment and assert it's not 333 // allowed. 334 resendPayment, 335 routerInitPayment, 336 resentPaymentError, 337 338 // Notify about a success for the original 339 // payment. 340 getPaymentResultSuccess, 341 routerSettleAttempt, 342 343 // Now that the original payment finished, 344 // resend it again to ensure this is not 345 // allowed. 346 resendPayment, 347 routerInitPayment, 348 resentPaymentError, 349 paymentSuccess, 350 }, 351 routes: []*route.Route{rt}, 352 }, 353 { 354 // Tests that the router is able to handle the 355 // receieved payment result after a restart. 356 name: "single shot restart", 357 358 steps: []string{ 359 routerInitPayment, 360 routeRelease, 361 routerRegisterAttempt, 362 sendToSwitchSuccess, 363 364 // Shut down the router. The original caller 365 // should get notified about this. 366 stopRouter, 367 paymentError, 368 369 // Start the router again, and ensure the 370 // router registers the success with the 371 // control tower. 372 startRouter, 373 getPaymentResultSuccess, 374 routerSettleAttempt, 375 }, 376 routes: []*route.Route{rt}, 377 paymentErr: ErrRouterShuttingDown, 378 }, 379 { 380 // Tests that we are allowed to resend a payment after 381 // it has permanently failed. 382 name: "single shot resend fail", 383 384 steps: []string{ 385 routerInitPayment, 386 routeRelease, 387 routerRegisterAttempt, 388 sendToSwitchSuccess, 389 390 // Resending the payment at this stage should 391 // not be allowed. 392 resendPayment, 393 routerInitPayment, 394 resentPaymentError, 395 396 // Make the first attempt fail. 397 getPaymentResultTempFailure, 398 routerFailAttempt, 399 400 // Since we have no more routes to try, the 401 // original payment should fail. 402 routeRelease, 403 routerFailPayment, 404 paymentError, 405 406 // Now resend the payment again. This should be 407 // allowed, since the payment has failed. 408 resendPayment, 409 routerInitPayment, 410 routeRelease, 411 routerRegisterAttempt, 412 sendToSwitchSuccess, 413 getPaymentResultSuccess, 414 routerSettleAttempt, 415 resentPaymentSuccess, 416 }, 417 routes: []*route.Route{rt}, 418 paymentErr: channeldb.FailureReasonNoRoute, 419 }, 420 } 421 422 for _, test := range tests { 423 test := test 424 t.Run(test.name, func(t *testing.T) { 425 testPaymentLifecycle( 426 t, test, paymentAmt, startingBlockHeight, 427 testGraph, 428 ) 429 }) 430 } 431 } 432 433 func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase, 434 paymentAmt lnwire.MilliAtom, startingBlockHeight uint32, 435 testGraph *testGraphInstance) { 436 437 // Create a mock control tower with channels set up, that we use to 438 // synchronize and listen for events. 439 control := makeMockControlTower() 440 control.init = make(chan initArgs) 441 control.registerAttempt = make(chan registerAttemptArgs) 442 control.settleAttempt = make(chan settleAttemptArgs) 443 control.failAttempt = make(chan failAttemptArgs) 444 control.failPayment = make(chan failPaymentArgs) 445 control.fetchInFlight = make(chan struct{}) 446 447 // setupRouter is a helper method that creates and starts the router in 448 // the desired configuration for this test. 449 setupRouter := func() (*ChannelRouter, chan error, 450 chan *htlcswitch.PaymentResult) { 451 452 chain := newMockChain(startingBlockHeight) 453 chainView := newMockChainView(chain) 454 455 // We set uo the use the following channels and a mock Payer to 456 // synchonize with the interaction to the Switch. 457 sendResult := make(chan error) 458 paymentResult := make(chan *htlcswitch.PaymentResult) 459 460 payer := &mockPayerOld{ 461 sendResult: sendResult, 462 paymentResult: paymentResult, 463 } 464 465 router, err := New(Config{ 466 Graph: testGraph.graph, 467 Chain: chain, 468 ChainView: chainView, 469 Control: control, 470 SessionSource: &mockPaymentSessionSourceOld{}, 471 MissionControl: &mockMissionControlOld{}, 472 Payer: payer, 473 ChannelPruneExpiry: time.Hour * 24, 474 GraphPruneInterval: time.Hour * 2, 475 NextPaymentID: func() (uint64, error) { 476 next := atomic.AddUint64(&uniquePaymentID, 1) 477 return next, nil 478 }, 479 Clock: clock.NewTestClock(time.Unix(1, 0)), 480 }) 481 if err != nil { 482 t.Fatalf("unable to create router %v", err) 483 } 484 485 // On startup, the router should fetch all pending payments 486 // from the ControlTower, so assert that here. 487 errCh := make(chan error) 488 go func() { 489 close(errCh) 490 select { 491 case <-control.fetchInFlight: 492 return 493 case <-time.After(1 * time.Second): 494 errCh <- errors.New("router did not fetch in flight " + 495 "payments") 496 } 497 }() 498 499 if err := router.Start(); err != nil { 500 t.Fatalf("unable to start router: %v", err) 501 } 502 503 select { 504 case err := <-errCh: 505 if err != nil { 506 t.Fatalf("error in anonymous goroutine: %s", err) 507 } 508 case <-time.After(1 * time.Second): 509 t.Fatalf("did not fetch in flight payments at startup") 510 } 511 512 return router, sendResult, paymentResult 513 } 514 515 router, sendResult, getPaymentResult := setupRouter() 516 defer func() { 517 if err := router.Stop(); err != nil { 518 t.Fatal(err) 519 } 520 }() 521 522 // Craft a LightningPayment struct. 523 var preImage lntypes.Preimage 524 if _, err := rand.Read(preImage[:]); err != nil { 525 t.Fatalf("unable to generate preimage") 526 } 527 528 payHash := preImage.Hash() 529 530 payment := LightningPayment{ 531 Target: testGraph.aliasMap["c"], 532 Amount: paymentAmt, 533 FeeLimit: noFeeLimit, 534 paymentHash: &payHash, 535 } 536 537 // Setup our payment session source to block on release of 538 // routes. 539 routeChan := make(chan struct{}) 540 router.cfg.SessionSource = &mockPaymentSessionSourceOld{ 541 routes: test.routes, 542 routeRelease: routeChan, 543 } 544 545 router.cfg.MissionControl = &mockMissionControlOld{} 546 547 // Send the payment. Since this is new payment hash, the 548 // information should be registered with the ControlTower. 549 paymentResult := make(chan error) 550 done := make(chan struct{}) 551 go func() { 552 _, _, err := router.SendPayment(&payment) 553 paymentResult <- err 554 close(done) 555 }() 556 557 var resendResult chan error 558 for i, step := range test.steps { 559 i, step := i, step 560 561 // fatal is a helper closure that wraps the step info. 562 fatal := func(err string, args ...interface{}) { 563 if args != nil { 564 err = fmt.Sprintf(err, args) 565 } 566 t.Fatalf( 567 "test case: %s failed on step [%v:%s], err: %s", 568 test.name, i, step, err, 569 ) 570 } 571 572 switch step { 573 574 case routerInitPayment: 575 var args initArgs 576 select { 577 case args = <-control.init: 578 case <-time.After(stepTimeout): 579 fatal("no init payment with control") 580 } 581 582 if args.c == nil { 583 fatal("expected non-nil CreationInfo") 584 } 585 586 case routeRelease: 587 select { 588 case <-routeChan: 589 case <-time.After(stepTimeout): 590 fatal("no route requested") 591 } 592 593 // In this step we expect the router to make a call to 594 // register a new attempt with the ControlTower. 595 case routerRegisterAttempt: 596 var args registerAttemptArgs 597 select { 598 case args = <-control.registerAttempt: 599 case <-time.After(stepTimeout): 600 fatal("attempt not registered with control") 601 } 602 603 if args.a == nil { 604 fatal("expected non-nil AttemptInfo") 605 } 606 607 // In this step we expect the router to call the 608 // ControlTower's SettleAttempt method with the preimage. 609 case routerSettleAttempt: 610 select { 611 case <-control.settleAttempt: 612 case <-time.After(stepTimeout): 613 fatal("attempt settle not " + 614 "registered with control") 615 } 616 617 // In this step we expect the router to call the 618 // ControlTower's FailAttempt method with a HTLC fail 619 // info. 620 case routerFailAttempt: 621 select { 622 case <-control.failAttempt: 623 case <-time.After(stepTimeout): 624 fatal("attempt fail not " + 625 "registered with control") 626 } 627 628 // In this step we expect the router to call the 629 // ControlTower's Fail method, to indicate that the 630 // payment failed. 631 case routerFailPayment: 632 select { 633 case <-control.failPayment: 634 case <-time.After(stepTimeout): 635 fatal("payment fail not " + 636 "registered with control") 637 } 638 639 // In this step we expect the SendToSwitch method to be 640 // called, and we respond with a nil-error. 641 case sendToSwitchSuccess: 642 select { 643 case sendResult <- nil: 644 case <-time.After(stepTimeout): 645 fatal("unable to send result") 646 } 647 648 // In this step we expect the SendToSwitch method to be 649 // called, and we respond with a forwarding error 650 case sendToSwitchResultFailure: 651 select { 652 case sendResult <- htlcswitch.NewForwardingError( 653 &lnwire.FailTemporaryChannelFailure{}, 654 1, 655 ): 656 case <-time.After(stepTimeout): 657 fatal("unable to send result") 658 } 659 660 // In this step we expect the GetPaymentResult method 661 // to be called, and we respond with the preimage to 662 // complete the payment. 663 case getPaymentResultSuccess: 664 select { 665 case getPaymentResult <- &htlcswitch.PaymentResult{ 666 Preimage: preImage, 667 }: 668 case <-time.After(stepTimeout): 669 fatal("unable to send result") 670 } 671 672 // In this state we expect the GetPaymentResult method 673 // to be called, and we respond with a forwarding 674 // error, indicating that the router should retry. 675 case getPaymentResultTempFailure: 676 failure := htlcswitch.NewForwardingError( 677 &lnwire.FailTemporaryChannelFailure{}, 678 1, 679 ) 680 681 select { 682 case getPaymentResult <- &htlcswitch.PaymentResult{ 683 Error: failure, 684 }: 685 case <-time.After(stepTimeout): 686 fatal("unable to get result") 687 } 688 689 // In this state we expect the router to call the 690 // GetPaymentResult method, and we will respond with a 691 // terminal error, indiating the router should stop 692 // making payment attempts. 693 case getPaymentResultTerminalFailure: 694 failure := htlcswitch.NewForwardingError( 695 &lnwire.FailIncorrectDetails{}, 696 1, 697 ) 698 699 select { 700 case getPaymentResult <- &htlcswitch.PaymentResult{ 701 Error: failure, 702 }: 703 case <-time.After(stepTimeout): 704 fatal("unable to get result") 705 } 706 707 // In this step we manually try to resend the same 708 // payment, making sure the router responds with an 709 // error indicating that it is already in flight. 710 case resendPayment: 711 resendResult = make(chan error) 712 go func() { 713 _, _, err := router.SendPayment(&payment) 714 resendResult <- err 715 }() 716 717 // In this step we manually stop the router. 718 case stopRouter: 719 // On shutdown, the switch closes our result channel. 720 // Mimic this behavior in our mock. 721 close(getPaymentResult) 722 723 if err := router.Stop(); err != nil { 724 fatal("unable to restart: %v", err) 725 } 726 727 // In this step we manually start the router. 728 case startRouter: 729 router, sendResult, getPaymentResult = setupRouter() 730 731 // In this state we expect to receive an error for the 732 // original payment made. 733 case paymentError: 734 require.Error(t, test.paymentErr, 735 "paymentError not set") 736 737 select { 738 case err := <-paymentResult: 739 require.Equal(t, test.paymentErr, err) 740 741 case <-time.After(stepTimeout): 742 fatal("got no payment result") 743 } 744 745 // In this state we expect the original payment to 746 // succeed. 747 case paymentSuccess: 748 require.Nil(t, test.paymentErr) 749 750 select { 751 case err := <-paymentResult: 752 if err != nil { 753 t.Fatalf("did not expect "+ 754 "error %v", err) 755 } 756 757 case <-time.After(stepTimeout): 758 fatal("got no payment result") 759 } 760 761 // In this state we expect to receive an error for the 762 // resent payment made. 763 case resentPaymentError: 764 select { 765 case err := <-resendResult: 766 if err == nil { 767 t.Fatalf("expected error") 768 } 769 770 case <-time.After(stepTimeout): 771 fatal("got no payment result") 772 } 773 774 // In this state we expect the resent payment to 775 // succeed. 776 case resentPaymentSuccess: 777 select { 778 case err := <-resendResult: 779 if err != nil { 780 t.Fatalf("did not expect error %v", err) 781 } 782 783 case <-time.After(stepTimeout): 784 fatal("got no payment result") 785 } 786 787 default: 788 fatal("unknown step %v", step) 789 } 790 } 791 792 select { 793 case <-done: 794 case <-time.After(testTimeout): 795 t.Fatalf("SendPayment didn't exit") 796 } 797 } 798 799 // TestPaymentState tests that the logics implemented on paymentState struct 800 // are as expected. In particular, that the method terminated and 801 // needWaitForShards return the right values. 802 func TestPaymentState(t *testing.T) { 803 t.Parallel() 804 805 testCases := []struct { 806 name string 807 808 // Use the following three params, each is equivalent to a bool 809 // statement, to construct 8 test cases so that we can 810 // exhaustively catch all possible states. 811 numShardsInFlight int 812 remainingAmt lnwire.MilliAtom 813 terminate bool 814 815 expectedTerminated bool 816 expectedNeedWaitForShards bool 817 }{ 818 { 819 // If we have active shards and terminate is marked 820 // false, the state is not terminated. Since the 821 // remaining amount is zero, we need to wait for shards 822 // to be finished and launch no more shards. 823 name: "state 100", 824 numShardsInFlight: 1, 825 remainingAmt: lnwire.MilliAtom(0), 826 terminate: false, 827 expectedTerminated: false, 828 expectedNeedWaitForShards: true, 829 }, 830 { 831 // If we have active shards while terminate is marked 832 // true, the state is not terminated, and we need to 833 // wait for shards to be finished and launch no more 834 // shards. 835 name: "state 101", 836 numShardsInFlight: 1, 837 remainingAmt: lnwire.MilliAtom(0), 838 terminate: true, 839 expectedTerminated: false, 840 expectedNeedWaitForShards: true, 841 }, 842 843 { 844 // If we have active shards and terminate is marked 845 // false, the state is not terminated. Since the 846 // remaining amount is not zero, we don't need to wait 847 // for shards outcomes and should launch more shards. 848 name: "state 110", 849 numShardsInFlight: 1, 850 remainingAmt: lnwire.MilliAtom(1), 851 terminate: false, 852 expectedTerminated: false, 853 expectedNeedWaitForShards: false, 854 }, 855 { 856 // If we have active shards and terminate is marked 857 // true, the state is not terminated. Even the 858 // remaining amount is not zero, we need to wait for 859 // shards outcomes because state is terminated. 860 name: "state 111", 861 numShardsInFlight: 1, 862 remainingAmt: lnwire.MilliAtom(1), 863 terminate: true, 864 expectedTerminated: false, 865 expectedNeedWaitForShards: true, 866 }, 867 { 868 // If we have no active shards while terminate is marked 869 // false, the state is not terminated, and we don't 870 // need to wait for more shard outcomes because there 871 // are no active shards. 872 name: "state 000", 873 numShardsInFlight: 0, 874 remainingAmt: lnwire.MilliAtom(0), 875 terminate: false, 876 expectedTerminated: false, 877 expectedNeedWaitForShards: false, 878 }, 879 { 880 // If we have no active shards while terminate is marked 881 // true, the state is terminated, and we don't need to 882 // wait for shards to be finished. 883 name: "state 001", 884 numShardsInFlight: 0, 885 remainingAmt: lnwire.MilliAtom(0), 886 terminate: true, 887 expectedTerminated: true, 888 expectedNeedWaitForShards: false, 889 }, 890 { 891 // If we have no active shards while terminate is marked 892 // false, the state is not terminated. Since the 893 // remaining amount is not zero, we don't need to wait 894 // for shards outcomes and should launch more shards. 895 name: "state 010", 896 numShardsInFlight: 0, 897 remainingAmt: lnwire.MilliAtom(1), 898 terminate: false, 899 expectedTerminated: false, 900 expectedNeedWaitForShards: false, 901 }, 902 { 903 // If we have no active shards while terminate is marked 904 // true, the state is terminated, and we don't need to 905 // wait for shards outcomes. 906 name: "state 011", 907 numShardsInFlight: 0, 908 remainingAmt: lnwire.MilliAtom(1), 909 terminate: true, 910 expectedTerminated: true, 911 expectedNeedWaitForShards: false, 912 }, 913 } 914 915 for _, tc := range testCases { 916 tc := tc 917 t.Run(tc.name, func(t *testing.T) { 918 t.Parallel() 919 920 ps := &paymentState{ 921 numShardsInFlight: tc.numShardsInFlight, 922 remainingAmt: tc.remainingAmt, 923 terminate: tc.terminate, 924 } 925 926 require.Equal( 927 t, tc.expectedTerminated, ps.terminated(), 928 "terminated returned wrong value", 929 ) 930 require.Equal( 931 t, tc.expectedNeedWaitForShards, 932 ps.needWaitForShards(), 933 "needWaitForShards returned wrong value", 934 ) 935 }) 936 } 937 938 } 939 940 // TestUpdatePaymentState checks that the method updatePaymentState updates the 941 // paymentState as expected. 942 func TestUpdatePaymentState(t *testing.T) { 943 t.Parallel() 944 945 // paymentHash is the identifier on paymentLifecycle. 946 paymentHash := lntypes.Hash{} 947 948 // TODO(yy): make MPPayment into an interface so we can mock it. The 949 // current design implicitly tests the methods SendAmt, TerminalInfo, 950 // and InFlightHTLCs on channeldb.MPPayment, which is not good. Once 951 // MPPayment becomes an interface, we can then mock these methods here. 952 953 // SentAmt returns 90, 10 954 // TerminalInfo returns non-nil, nil 955 // InFlightHTLCs returns 0 956 var preimage lntypes.Preimage 957 paymentSettled := &channeldb.MPPayment{ 958 HTLCs: []channeldb.HTLCAttempt{ 959 makeSettledAttempt(100, 10, preimage), 960 }, 961 } 962 963 // SentAmt returns 0, 0 964 // TerminalInfo returns nil, non-nil 965 // InFlightHTLCs returns 0 966 reason := channeldb.FailureReasonError 967 paymentFailed := &channeldb.MPPayment{ 968 FailureReason: &reason, 969 } 970 971 // SentAmt returns 90, 10 972 // TerminalInfo returns nil, nil 973 // InFlightHTLCs returns 1 974 paymentActive := &channeldb.MPPayment{ 975 HTLCs: []channeldb.HTLCAttempt{ 976 makeActiveAttempt(100, 10), 977 makeFailedAttempt(100, 10), 978 }, 979 } 980 981 testCases := []struct { 982 name string 983 payment *channeldb.MPPayment 984 totalAmt int 985 feeLimit int 986 987 expectedState *paymentState 988 shouldReturnError bool 989 }{ 990 { 991 // Test that the error returned from FetchPayment is 992 // handled properly. We use a nil payment to indicate 993 // we want to return an error. 994 name: "fetch payment error", 995 payment: nil, 996 shouldReturnError: true, 997 }, 998 { 999 // Test that when the sentAmt exceeds totalAmount, the 1000 // error is returned. 1001 name: "amount exceeded error", 1002 payment: paymentSettled, 1003 totalAmt: 1, 1004 shouldReturnError: true, 1005 }, 1006 { 1007 // Test that when the fee budget is reached, the 1008 // remaining fee should be zero. 1009 name: "fee budget reached", 1010 payment: paymentActive, 1011 totalAmt: 1000, 1012 feeLimit: 1, 1013 expectedState: &paymentState{ 1014 numShardsInFlight: 1, 1015 remainingAmt: 1000 - 90, 1016 remainingFees: 0, 1017 terminate: false, 1018 }, 1019 }, 1020 { 1021 // Test when the payment is settled, the state should 1022 // be marked as terminated. 1023 name: "payment settled", 1024 payment: paymentSettled, 1025 totalAmt: 1000, 1026 feeLimit: 100, 1027 expectedState: &paymentState{ 1028 numShardsInFlight: 0, 1029 remainingAmt: 1000 - 90, 1030 remainingFees: 100 - 10, 1031 terminate: true, 1032 }, 1033 }, 1034 { 1035 // Test when the payment is failed, the state should be 1036 // marked as terminated. 1037 name: "payment failed", 1038 payment: paymentFailed, 1039 totalAmt: 1000, 1040 feeLimit: 100, 1041 expectedState: &paymentState{ 1042 numShardsInFlight: 0, 1043 remainingAmt: 1000, 1044 remainingFees: 100, 1045 terminate: true, 1046 }, 1047 }, 1048 } 1049 1050 for _, tc := range testCases { 1051 tc := tc 1052 t.Run(tc.name, func(t *testing.T) { 1053 t.Parallel() 1054 1055 // Create mock control tower and assign it to router. 1056 // We will then use the router and the paymentHash 1057 // above to create our paymentLifecycle for this test. 1058 ct := &mockControlTower{} 1059 rt := &ChannelRouter{cfg: &Config{Control: ct}} 1060 pl := &paymentLifecycle{ 1061 router: rt, 1062 identifier: paymentHash, 1063 totalAmount: lnwire.MilliAtom(tc.totalAmt), 1064 feeLimit: lnwire.MilliAtom(tc.feeLimit), 1065 } 1066 1067 if tc.payment == nil { 1068 // A nil payment indicates we want to test an 1069 // error returned from FetchPayment. 1070 dummyErr := errors.New("dummy") 1071 ct.On("FetchPayment", paymentHash).Return( 1072 nil, dummyErr, 1073 ) 1074 1075 } else { 1076 // Otherwise we will return the payment. 1077 ct.On("FetchPayment", paymentHash).Return( 1078 tc.payment, nil, 1079 ) 1080 } 1081 1082 // Call the method that updates the payment state. 1083 _, state, err := pl.fetchPaymentState() 1084 1085 // Assert that the mock method is called as 1086 // intended. 1087 ct.AssertExpectations(t) 1088 1089 if tc.shouldReturnError { 1090 require.Error(t, err, "expect an error") 1091 return 1092 } 1093 1094 require.NoError(t, err, "unexpected error") 1095 require.Equal( 1096 t, tc.expectedState, state, 1097 "state not updated as expected", 1098 ) 1099 1100 }) 1101 } 1102 1103 } 1104 1105 func makeActiveAttempt(total, fee int) channeldb.HTLCAttempt { 1106 return channeldb.HTLCAttempt{ 1107 HTLCAttemptInfo: makeAttemptInfo(total, total-fee), 1108 } 1109 } 1110 1111 func makeSettledAttempt(total, fee int, 1112 preimage lntypes.Preimage) channeldb.HTLCAttempt { 1113 1114 return channeldb.HTLCAttempt{ 1115 HTLCAttemptInfo: makeAttemptInfo(total, total-fee), 1116 Settle: &channeldb.HTLCSettleInfo{Preimage: preimage}, 1117 } 1118 } 1119 1120 func makeFailedAttempt(total, fee int) channeldb.HTLCAttempt { 1121 return channeldb.HTLCAttempt{ 1122 HTLCAttemptInfo: makeAttemptInfo(total, total-fee), 1123 Failure: &channeldb.HTLCFailInfo{ 1124 Reason: channeldb.HTLCFailInternal, 1125 }, 1126 } 1127 } 1128 1129 func makeAttemptInfo(total, amtForwarded int) channeldb.HTLCAttemptInfo { 1130 hop := &route.Hop{AmtToForward: lnwire.MilliAtom(amtForwarded)} 1131 return channeldb.HTLCAttemptInfo{ 1132 Route: route.Route{ 1133 TotalAmount: lnwire.MilliAtom(total), 1134 Hops: []*route.Hop{hop}, 1135 }, 1136 } 1137 }