github.com/decred/dcrlnd@v0.7.6/channeldb/payment_control_test.go (about) 1 package channeldb 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "fmt" 7 "io" 8 "reflect" 9 "testing" 10 "time" 11 12 "github.com/btcsuite/btcwallet/walletdb" 13 "github.com/davecgh/go-spew/spew" 14 "github.com/decred/dcrlnd/kvdb" 15 "github.com/decred/dcrlnd/lntypes" 16 "github.com/decred/dcrlnd/record" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func genPreimage() (lntypes.Preimage, error) { 22 var preimage [32]byte 23 if _, err := io.ReadFull(rand.Reader, preimage[:]); err != nil { 24 return preimage, err 25 } 26 return preimage, nil 27 } 28 29 func genInfo() (*PaymentCreationInfo, *HTLCAttemptInfo, 30 lntypes.Preimage, error) { 31 32 preimage, err := genPreimage() 33 if err != nil { 34 return nil, nil, preimage, fmt.Errorf("unable to "+ 35 "generate preimage: %v", err) 36 } 37 38 rhash := preimage.Hash() 39 attempt := NewHtlcAttemptInfo( 40 0, priv, *testRoute.Copy(), time.Time{}, nil, 41 ) 42 return &PaymentCreationInfo{ 43 PaymentIdentifier: rhash, 44 Value: testRoute.ReceiverAmt(), 45 CreationTime: time.Unix(time.Now().Unix(), 0), 46 PaymentRequest: []byte("hola"), 47 }, attempt, preimage, nil 48 } 49 50 // TestPaymentControlSwitchFail checks that payment status returns to Failed 51 // status after failing, and that InitPayment allows another HTLC for the 52 // same payment hash. 53 func TestPaymentControlSwitchFail(t *testing.T) { 54 t.Parallel() 55 56 db, cleanup, err := MakeTestDB() 57 defer cleanup() 58 if err != nil { 59 t.Fatalf("unable to init db: %v", err) 60 } 61 62 pControl := NewPaymentControl(db) 63 64 info, attempt, preimg, err := genInfo() 65 if err != nil { 66 t.Fatalf("unable to generate htlc message: %v", err) 67 } 68 69 // Sends base htlc message which initiate StatusInFlight. 70 err = pControl.InitPayment(info.PaymentIdentifier, info) 71 if err != nil { 72 t.Fatalf("unable to send htlc message: %v", err) 73 } 74 75 assertPaymentIndex(t, pControl, info.PaymentIdentifier) 76 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 77 assertPaymentInfo( 78 t, pControl, info.PaymentIdentifier, info, nil, nil, 79 ) 80 81 // Fail the payment, which should moved it to Failed. 82 failReason := FailureReasonNoRoute 83 _, err = pControl.Fail(info.PaymentIdentifier, failReason) 84 if err != nil { 85 t.Fatalf("unable to fail payment hash: %v", err) 86 } 87 88 // Verify the status is indeed Failed. 89 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusFailed) 90 assertPaymentInfo( 91 t, pControl, info.PaymentIdentifier, info, &failReason, nil, 92 ) 93 94 // Lookup the payment so we can get its old sequence number before it is 95 // overwritten. 96 payment, err := pControl.FetchPayment(info.PaymentIdentifier) 97 assert.NoError(t, err) 98 99 // Sends the htlc again, which should succeed since the prior payment 100 // failed. 101 err = pControl.InitPayment(info.PaymentIdentifier, info) 102 if err != nil { 103 t.Fatalf("unable to send htlc message: %v", err) 104 } 105 106 // Check that our index has been updated, and the old index has been 107 // removed. 108 assertPaymentIndex(t, pControl, info.PaymentIdentifier) 109 assertNoIndex(t, pControl, payment.SequenceNum) 110 111 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 112 assertPaymentInfo( 113 t, pControl, info.PaymentIdentifier, info, nil, nil, 114 ) 115 116 // Record a new attempt. In this test scenario, the attempt fails. 117 // However, this is not communicated to control tower in the current 118 // implementation. It only registers the initiation of the attempt. 119 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) 120 if err != nil { 121 t.Fatalf("unable to register attempt: %v", err) 122 } 123 124 htlcReason := HTLCFailUnreadable 125 _, err = pControl.FailAttempt( 126 info.PaymentIdentifier, attempt.AttemptID, 127 &HTLCFailInfo{ 128 Reason: htlcReason, 129 }, 130 ) 131 if err != nil { 132 t.Fatal(err) 133 } 134 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 135 136 htlc := &htlcStatus{ 137 HTLCAttemptInfo: attempt, 138 failure: &htlcReason, 139 } 140 141 assertPaymentInfo(t, pControl, info.PaymentIdentifier, info, nil, htlc) 142 143 // Record another attempt. 144 attempt.AttemptID = 1 145 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) 146 if err != nil { 147 t.Fatalf("unable to send htlc message: %v", err) 148 } 149 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 150 151 htlc = &htlcStatus{ 152 HTLCAttemptInfo: attempt, 153 } 154 155 assertPaymentInfo( 156 t, pControl, info.PaymentIdentifier, info, nil, htlc, 157 ) 158 159 // Settle the attempt and verify that status was changed to 160 // StatusSucceeded. 161 payment, err = pControl.SettleAttempt( 162 info.PaymentIdentifier, attempt.AttemptID, 163 &HTLCSettleInfo{ 164 Preimage: preimg, 165 }, 166 ) 167 if err != nil { 168 t.Fatalf("error shouldn't have been received, got: %v", err) 169 } 170 171 if len(payment.HTLCs) != 2 { 172 t.Fatalf("payment should have two htlcs, got: %d", 173 len(payment.HTLCs)) 174 } 175 176 err = assertRouteEqual(&payment.HTLCs[0].Route, &attempt.Route) 177 if err != nil { 178 t.Fatalf("unexpected route returned: %v vs %v: %v", 179 spew.Sdump(attempt.Route), 180 spew.Sdump(payment.HTLCs[0].Route), err) 181 } 182 183 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded) 184 185 htlc.settle = &preimg 186 assertPaymentInfo( 187 t, pControl, info.PaymentIdentifier, info, nil, htlc, 188 ) 189 190 // Attempt a final payment, which should now fail since the prior 191 // payment succeed. 192 err = pControl.InitPayment(info.PaymentIdentifier, info) 193 if err != ErrAlreadyPaid { 194 t.Fatalf("unable to send htlc message: %v", err) 195 } 196 } 197 198 // TestPaymentControlSwitchDoubleSend checks the ability of payment control to 199 // prevent double sending of htlc message, when message is in StatusInFlight. 200 func TestPaymentControlSwitchDoubleSend(t *testing.T) { 201 t.Parallel() 202 203 db, cleanup, err := MakeTestDB() 204 defer cleanup() 205 206 if err != nil { 207 t.Fatalf("unable to init db: %v", err) 208 } 209 210 pControl := NewPaymentControl(db) 211 212 info, attempt, preimg, err := genInfo() 213 if err != nil { 214 t.Fatalf("unable to generate htlc message: %v", err) 215 } 216 217 // Sends base htlc message which initiate base status and move it to 218 // StatusInFlight and verifies that it was changed. 219 err = pControl.InitPayment(info.PaymentIdentifier, info) 220 if err != nil { 221 t.Fatalf("unable to send htlc message: %v", err) 222 } 223 224 assertPaymentIndex(t, pControl, info.PaymentIdentifier) 225 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 226 assertPaymentInfo( 227 t, pControl, info.PaymentIdentifier, info, nil, nil, 228 ) 229 230 // Try to initiate double sending of htlc message with the same 231 // payment hash, should result in error indicating that payment has 232 // already been sent. 233 err = pControl.InitPayment(info.PaymentIdentifier, info) 234 if err != ErrPaymentInFlight { 235 t.Fatalf("payment control wrong behaviour: " + 236 "double sending must trigger ErrPaymentInFlight error") 237 } 238 239 // Record an attempt. 240 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) 241 if err != nil { 242 t.Fatalf("unable to send htlc message: %v", err) 243 } 244 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 245 246 htlc := &htlcStatus{ 247 HTLCAttemptInfo: attempt, 248 } 249 assertPaymentInfo( 250 t, pControl, info.PaymentIdentifier, info, nil, htlc, 251 ) 252 253 // Sends base htlc message which initiate StatusInFlight. 254 err = pControl.InitPayment(info.PaymentIdentifier, info) 255 if err != ErrPaymentInFlight { 256 t.Fatalf("payment control wrong behaviour: " + 257 "double sending must trigger ErrPaymentInFlight error") 258 } 259 260 // After settling, the error should be ErrAlreadyPaid. 261 _, err = pControl.SettleAttempt( 262 info.PaymentIdentifier, attempt.AttemptID, 263 &HTLCSettleInfo{ 264 Preimage: preimg, 265 }, 266 ) 267 if err != nil { 268 t.Fatalf("error shouldn't have been received, got: %v", err) 269 } 270 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded) 271 272 htlc.settle = &preimg 273 assertPaymentInfo(t, pControl, info.PaymentIdentifier, info, nil, htlc) 274 275 err = pControl.InitPayment(info.PaymentIdentifier, info) 276 if err != ErrAlreadyPaid { 277 t.Fatalf("unable to send htlc message: %v", err) 278 } 279 } 280 281 // TestPaymentControlSuccessesWithoutInFlight checks that the payment 282 // control will disallow calls to Success when no payment is in flight. 283 func TestPaymentControlSuccessesWithoutInFlight(t *testing.T) { 284 t.Parallel() 285 286 db, cleanup, err := MakeTestDB() 287 defer cleanup() 288 289 if err != nil { 290 t.Fatalf("unable to init db: %v", err) 291 } 292 293 pControl := NewPaymentControl(db) 294 295 info, _, preimg, err := genInfo() 296 if err != nil { 297 t.Fatalf("unable to generate htlc message: %v", err) 298 } 299 300 // Attempt to complete the payment should fail. 301 _, err = pControl.SettleAttempt( 302 info.PaymentIdentifier, 0, 303 &HTLCSettleInfo{ 304 Preimage: preimg, 305 }, 306 ) 307 if err != ErrPaymentNotInitiated { 308 t.Fatalf("expected ErrPaymentNotInitiated, got %v", err) 309 } 310 311 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown) 312 } 313 314 // TestPaymentControlFailsWithoutInFlight checks that a strict payment 315 // control will disallow calls to Fail when no payment is in flight. 316 func TestPaymentControlFailsWithoutInFlight(t *testing.T) { 317 t.Parallel() 318 319 db, cleanup, err := MakeTestDB() 320 defer cleanup() 321 322 if err != nil { 323 t.Fatalf("unable to init db: %v", err) 324 } 325 326 pControl := NewPaymentControl(db) 327 328 info, _, _, err := genInfo() 329 if err != nil { 330 t.Fatalf("unable to generate htlc message: %v", err) 331 } 332 333 // Calling Fail should return an error. 334 _, err = pControl.Fail(info.PaymentIdentifier, FailureReasonNoRoute) 335 if err != ErrPaymentNotInitiated { 336 t.Fatalf("expected ErrPaymentNotInitiated, got %v", err) 337 } 338 339 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown) 340 } 341 342 // TestPaymentControlDeleteNonInFlight checks that calling DeletePayments only 343 // deletes payments from the database that are not in-flight. 344 func TestPaymentControlDeleteNonInFligt(t *testing.T) { 345 t.Parallel() 346 347 db, cleanup, err := MakeTestDB() 348 defer cleanup() 349 350 if err != nil { 351 t.Fatalf("unable to init db: %v", err) 352 } 353 354 // Create a sequence number for duplicate payments that will not collide 355 // with the sequence numbers for the payments we create. These values 356 // start at 1, so 9999 is a safe bet for this test. 357 var duplicateSeqNr = 9999 358 359 pControl := NewPaymentControl(db) 360 361 payments := []struct { 362 failed bool 363 success bool 364 hasDuplicate bool 365 }{ 366 { 367 failed: true, 368 success: false, 369 hasDuplicate: false, 370 }, 371 { 372 failed: false, 373 success: true, 374 hasDuplicate: false, 375 }, 376 { 377 failed: false, 378 success: false, 379 hasDuplicate: false, 380 }, 381 { 382 failed: false, 383 success: true, 384 hasDuplicate: true, 385 }, 386 } 387 388 var numSuccess, numInflight int 389 390 for _, p := range payments { 391 info, attempt, preimg, err := genInfo() 392 if err != nil { 393 t.Fatalf("unable to generate htlc message: %v", err) 394 } 395 396 // Sends base htlc message which initiate StatusInFlight. 397 err = pControl.InitPayment(info.PaymentIdentifier, info) 398 if err != nil { 399 t.Fatalf("unable to send htlc message: %v", err) 400 } 401 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) 402 if err != nil { 403 t.Fatalf("unable to send htlc message: %v", err) 404 } 405 406 htlc := &htlcStatus{ 407 HTLCAttemptInfo: attempt, 408 } 409 410 if p.failed { 411 // Fail the payment attempt. 412 htlcFailure := HTLCFailUnreadable 413 _, err := pControl.FailAttempt( 414 info.PaymentIdentifier, attempt.AttemptID, 415 &HTLCFailInfo{ 416 Reason: htlcFailure, 417 }, 418 ) 419 if err != nil { 420 t.Fatalf("unable to fail htlc: %v", err) 421 } 422 423 // Fail the payment, which should moved it to Failed. 424 failReason := FailureReasonNoRoute 425 _, err = pControl.Fail(info.PaymentIdentifier, failReason) 426 if err != nil { 427 t.Fatalf("unable to fail payment hash: %v", err) 428 } 429 430 // Verify the status is indeed Failed. 431 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusFailed) 432 433 htlc.failure = &htlcFailure 434 assertPaymentInfo( 435 t, pControl, info.PaymentIdentifier, info, 436 &failReason, htlc, 437 ) 438 } else if p.success { 439 // Verifies that status was changed to StatusSucceeded. 440 _, err := pControl.SettleAttempt( 441 info.PaymentIdentifier, attempt.AttemptID, 442 &HTLCSettleInfo{ 443 Preimage: preimg, 444 }, 445 ) 446 if err != nil { 447 t.Fatalf("error shouldn't have been received, got: %v", err) 448 } 449 450 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded) 451 452 htlc.settle = &preimg 453 assertPaymentInfo( 454 t, pControl, info.PaymentIdentifier, info, nil, htlc, 455 ) 456 457 numSuccess++ 458 } else { 459 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 460 assertPaymentInfo( 461 t, pControl, info.PaymentIdentifier, info, nil, htlc, 462 ) 463 464 numInflight++ 465 } 466 467 // If the payment is intended to have a duplicate payment, we 468 // add one. 469 if p.hasDuplicate { 470 appendDuplicatePayment( 471 t, pControl.db, info.PaymentIdentifier, 472 uint64(duplicateSeqNr), preimg, 473 ) 474 duplicateSeqNr++ 475 numSuccess++ 476 } 477 } 478 479 // Delete all failed payments. 480 if err := db.DeletePayments(true, false); err != nil { 481 t.Fatal(err) 482 } 483 484 // This should leave the succeeded and in-flight payments. 485 dbPayments, err := db.FetchPayments() 486 if err != nil { 487 t.Fatal(err) 488 } 489 490 if len(dbPayments) != numSuccess+numInflight { 491 t.Fatalf("expected %d payments, got %d", 492 numSuccess+numInflight, len(dbPayments)) 493 } 494 495 var s, i int 496 for _, p := range dbPayments { 497 fmt.Println("fetch payment has status", p.Status) 498 switch p.Status { 499 case StatusSucceeded: 500 s++ 501 case StatusInFlight: 502 i++ 503 } 504 } 505 506 if s != numSuccess { 507 t.Fatalf("expected %d succeeded payments , got %d", 508 numSuccess, s) 509 } 510 if i != numInflight { 511 t.Fatalf("expected %d in-flight payments, got %d", 512 numInflight, i) 513 } 514 515 // Now delete all payments except in-flight. 516 if err := db.DeletePayments(false, false); err != nil { 517 t.Fatal(err) 518 } 519 520 // This should leave the in-flight payment. 521 dbPayments, err = db.FetchPayments() 522 if err != nil { 523 t.Fatal(err) 524 } 525 526 if len(dbPayments) != numInflight { 527 t.Fatalf("expected %d payments, got %d", numInflight, 528 len(dbPayments)) 529 } 530 531 for _, p := range dbPayments { 532 if p.Status != StatusInFlight { 533 t.Fatalf("expected in-fligth status, got %v", p.Status) 534 } 535 } 536 537 // Finally, check that we only have a single index left in the payment 538 // index bucket. 539 var indexCount int 540 err = kvdb.View(db, func(tx walletdb.ReadTx) error { 541 index := tx.ReadBucket(paymentsIndexBucket) 542 543 return index.ForEach(func(k, v []byte) error { 544 indexCount++ 545 return nil 546 }) 547 }, func() { indexCount = 0 }) 548 require.NoError(t, err) 549 550 require.Equal(t, 1, indexCount) 551 } 552 553 // TestPaymentControlDeletePayments tests that DeletePayments correcly deletes 554 // information about completed payments from the database. 555 func TestPaymentControlDeletePayments(t *testing.T) { 556 t.Parallel() 557 558 db, cleanup, err := MakeTestDB() 559 defer cleanup() 560 require.NoError(t, err, "unable to init db") 561 562 pControl := NewPaymentControl(db) 563 564 // Register three payments: 565 // 1. A payment with two failed attempts. 566 // 2. A Payment with one failed and one settled attempt. 567 // 3. A payment with one failed and one in-flight attempt. 568 payments := []*payment{ 569 {status: StatusFailed}, 570 {status: StatusSucceeded}, 571 {status: StatusInFlight}, 572 } 573 574 // Use helper function to register the test payments in the data and 575 // populate the data to the payments slice. 576 createTestPayments(t, pControl, payments) 577 578 // Check that all payments are there as we added them. 579 assertPayments(t, db, payments) 580 581 // Delete HTLC attempts for failed payments only. 582 require.NoError(t, db.DeletePayments(true, true)) 583 584 // The failed payment is the only altered one. 585 payments[0].htlcs = 0 586 assertPayments(t, db, payments) 587 588 // Delete failed attempts for all payments. 589 require.NoError(t, db.DeletePayments(false, true)) 590 591 // The failed attempts should be deleted, except for the in-flight 592 // payment, that shouldn't be altered until it has completed. 593 payments[1].htlcs = 1 594 assertPayments(t, db, payments) 595 596 // Now delete all failed payments. 597 require.NoError(t, db.DeletePayments(true, false)) 598 599 assertPayments(t, db, payments[1:]) 600 601 // Finally delete all completed payments. 602 require.NoError(t, db.DeletePayments(false, false)) 603 604 assertPayments(t, db, payments[2:]) 605 } 606 607 // TestPaymentControlDeleteSinglePayment tests that DeletePayment correcly 608 // deletes information about a completed payment from the database. 609 func TestPaymentControlDeleteSinglePayment(t *testing.T) { 610 t.Parallel() 611 612 db, cleanup, err := MakeTestDB() 613 defer cleanup() 614 require.NoError(t, err, "unable to init db") 615 616 pControl := NewPaymentControl(db) 617 618 // Register four payments: 619 // All payments will have one failed HTLC attempt and one HTLC attempt 620 // according to its final status. 621 // 1. A payment with two failed attempts. 622 // 2. Another payment with two failed attempts. 623 // 3. A Payment with one failed and one settled attempt. 624 // 4. A payment with one failed and one in-flight attempt. 625 626 // Initiate payments, which is a slice of payment that is used as 627 // template to create the corresponding test payments in the database. 628 // 629 // Note: The payment id and number of htlc attempts of each payment will 630 // be added to this slice when creating the payments below. 631 // This allows the slice to be used directly for testing purposes. 632 payments := []*payment{ 633 {status: StatusFailed}, 634 {status: StatusFailed}, 635 {status: StatusSucceeded}, 636 {status: StatusInFlight}, 637 } 638 639 // Use helper function to register the test payments in the data and 640 // populate the data to the payments slice. 641 createTestPayments(t, pControl, payments) 642 643 // Check that all payments are there as we added them. 644 assertPayments(t, db, payments) 645 646 // Delete HTLC attempts for first payment only. 647 require.NoError(t, db.DeletePayment(payments[0].id, true)) 648 649 // The first payment is the only altered one as its failed HTLC should 650 // have been removed but is still present as payment. 651 payments[0].htlcs = 0 652 assertPayments(t, db, payments) 653 654 // Delete the first payment completely. 655 require.NoError(t, db.DeletePayment(payments[0].id, false)) 656 657 // The first payment should have been deleted. 658 assertPayments(t, db, payments[1:]) 659 660 // Now delete the second payment completely. 661 require.NoError(t, db.DeletePayment(payments[1].id, false)) 662 663 // The Second payment should have been deleted. 664 assertPayments(t, db, payments[2:]) 665 666 // Delete failed HTLC attempts for the third payment. 667 require.NoError(t, db.DeletePayment(payments[2].id, true)) 668 669 // Only the successful HTLC attempt should be left for the third payment. 670 payments[2].htlcs = 1 671 assertPayments(t, db, payments[2:]) 672 673 // Now delete the third payment completely. 674 require.NoError(t, db.DeletePayment(payments[2].id, false)) 675 676 // Only the last payment should be left. 677 assertPayments(t, db, payments[3:]) 678 679 // Deleting HTLC attempts from InFlight payments should not work and an 680 // error returned. 681 require.Error(t, db.DeletePayment(payments[3].id, true)) 682 683 // The payment is InFlight and therefore should not have been altered. 684 assertPayments(t, db, payments[3:]) 685 686 // Finally deleting the InFlight payment should also not work and an 687 // error returned. 688 require.Error(t, db.DeletePayment(payments[3].id, false)) 689 690 // The payment is InFlight and therefore should not have been altered. 691 assertPayments(t, db, payments[3:]) 692 } 693 694 // TestPaymentControlMultiShard checks the ability of payment control to 695 // have multiple in-flight HTLCs for a single payment. 696 func TestPaymentControlMultiShard(t *testing.T) { 697 t.Parallel() 698 699 // We will register three HTLC attempts, and always fail the second 700 // one. We'll generate all combinations of settling/failing the first 701 // and third HTLC, and assert that the payment status end up as we 702 // expect. 703 type testCase struct { 704 settleFirst bool 705 settleLast bool 706 } 707 708 var tests []testCase 709 for _, f := range []bool{true, false} { 710 for _, l := range []bool{true, false} { 711 tests = append(tests, testCase{f, l}) 712 } 713 } 714 715 runSubTest := func(t *testing.T, test testCase) { 716 db, cleanup, err := MakeTestDB() 717 defer cleanup() 718 719 if err != nil { 720 t.Fatalf("unable to init db: %v", err) 721 } 722 723 pControl := NewPaymentControl(db) 724 725 info, attempt, preimg, err := genInfo() 726 if err != nil { 727 t.Fatalf("unable to generate htlc message: %v", err) 728 } 729 730 // Init the payment, moving it to the StatusInFlight state. 731 err = pControl.InitPayment(info.PaymentIdentifier, info) 732 if err != nil { 733 t.Fatalf("unable to send htlc message: %v", err) 734 } 735 736 assertPaymentIndex(t, pControl, info.PaymentIdentifier) 737 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 738 assertPaymentInfo( 739 t, pControl, info.PaymentIdentifier, info, nil, nil, 740 ) 741 742 // Create three unique attempts we'll use for the test, and 743 // register them with the payment control. We set each 744 // attempts's value to one third of the payment amount, and 745 // populate the MPP options. 746 shardAmt := info.Value / 3 747 attempt.Route.FinalHop().AmtToForward = shardAmt 748 attempt.Route.FinalHop().MPP = record.NewMPP( 749 info.Value, [32]byte{1}, 750 ) 751 752 var attempts []*HTLCAttemptInfo 753 for i := uint64(0); i < 3; i++ { 754 a := *attempt 755 a.AttemptID = i 756 attempts = append(attempts, &a) 757 758 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &a) 759 if err != nil { 760 t.Fatalf("unable to send htlc message: %v", err) 761 } 762 assertPaymentStatus( 763 t, pControl, info.PaymentIdentifier, StatusInFlight, 764 ) 765 766 htlc := &htlcStatus{ 767 HTLCAttemptInfo: &a, 768 } 769 assertPaymentInfo( 770 t, pControl, info.PaymentIdentifier, info, nil, htlc, 771 ) 772 } 773 774 // For a fourth attempt, check that attempting to 775 // register it will fail since the total sent amount 776 // will be too large. 777 b := *attempt 778 b.AttemptID = 3 779 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 780 if err != ErrValueExceedsAmt { 781 t.Fatalf("expected ErrValueExceedsAmt, got: %v", 782 err) 783 } 784 785 // Fail the second attempt. 786 a := attempts[1] 787 htlcFail := HTLCFailUnreadable 788 _, err = pControl.FailAttempt( 789 info.PaymentIdentifier, a.AttemptID, 790 &HTLCFailInfo{ 791 Reason: htlcFail, 792 }, 793 ) 794 if err != nil { 795 t.Fatal(err) 796 } 797 798 htlc := &htlcStatus{ 799 HTLCAttemptInfo: a, 800 failure: &htlcFail, 801 } 802 assertPaymentInfo( 803 t, pControl, info.PaymentIdentifier, info, nil, htlc, 804 ) 805 806 // Payment should still be in-flight. 807 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 808 809 // Depending on the test case, settle or fail the first attempt. 810 a = attempts[0] 811 htlc = &htlcStatus{ 812 HTLCAttemptInfo: a, 813 } 814 815 var firstFailReason *FailureReason 816 if test.settleFirst { 817 _, err := pControl.SettleAttempt( 818 info.PaymentIdentifier, a.AttemptID, 819 &HTLCSettleInfo{ 820 Preimage: preimg, 821 }, 822 ) 823 if err != nil { 824 t.Fatalf("error shouldn't have been "+ 825 "received, got: %v", err) 826 } 827 828 // Assert that the HTLC has had the preimage recorded. 829 htlc.settle = &preimg 830 assertPaymentInfo( 831 t, pControl, info.PaymentIdentifier, info, nil, htlc, 832 ) 833 } else { 834 _, err := pControl.FailAttempt( 835 info.PaymentIdentifier, a.AttemptID, 836 &HTLCFailInfo{ 837 Reason: htlcFail, 838 }, 839 ) 840 if err != nil { 841 t.Fatalf("error shouldn't have been "+ 842 "received, got: %v", err) 843 } 844 845 // Assert the failure was recorded. 846 htlc.failure = &htlcFail 847 assertPaymentInfo( 848 t, pControl, info.PaymentIdentifier, info, nil, htlc, 849 ) 850 851 // We also record a payment level fail, to move it into 852 // a terminal state. 853 failReason := FailureReasonNoRoute 854 _, err = pControl.Fail(info.PaymentIdentifier, failReason) 855 if err != nil { 856 t.Fatalf("unable to fail payment hash: %v", err) 857 } 858 859 // Record the reason we failed the payment, such that 860 // we can assert this later in the test. 861 firstFailReason = &failReason 862 } 863 864 // The payment should still be considered in-flight, since there 865 // is still an active HTLC. 866 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 867 868 // Try to register yet another attempt. This should fail now 869 // that the payment has reached a terminal condition. 870 b = *attempt 871 b.AttemptID = 3 872 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 873 if err != ErrPaymentTerminal { 874 t.Fatalf("expected ErrPaymentTerminal, got: %v", err) 875 } 876 877 assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight) 878 879 // Settle or fail the remaining attempt based on the testcase. 880 a = attempts[2] 881 htlc = &htlcStatus{ 882 HTLCAttemptInfo: a, 883 } 884 if test.settleLast { 885 // Settle the last outstanding attempt. 886 _, err = pControl.SettleAttempt( 887 info.PaymentIdentifier, a.AttemptID, 888 &HTLCSettleInfo{ 889 Preimage: preimg, 890 }, 891 ) 892 if err != nil { 893 t.Fatalf("error shouldn't have been "+ 894 "received, got: %v", err) 895 } 896 897 htlc.settle = &preimg 898 assertPaymentInfo( 899 t, pControl, info.PaymentIdentifier, info, 900 firstFailReason, htlc, 901 ) 902 } else { 903 // Fail the attempt. 904 _, err := pControl.FailAttempt( 905 info.PaymentIdentifier, a.AttemptID, 906 &HTLCFailInfo{ 907 Reason: htlcFail, 908 }, 909 ) 910 if err != nil { 911 t.Fatalf("error shouldn't have been "+ 912 "received, got: %v", err) 913 } 914 915 // Assert the failure was recorded. 916 htlc.failure = &htlcFail 917 assertPaymentInfo( 918 t, pControl, info.PaymentIdentifier, info, 919 firstFailReason, htlc, 920 ) 921 922 // Check that we can override any perevious terminal 923 // failure. This is to allow multiple concurrent shard 924 // write a terminal failure to the database without 925 // syncing. 926 failReason := FailureReasonPaymentDetails 927 _, err = pControl.Fail(info.PaymentIdentifier, failReason) 928 if err != nil { 929 t.Fatalf("unable to fail payment hash: %v", err) 930 } 931 } 932 933 // If any of the two attempts settled, the payment should end 934 // up in the Succeeded state. If both failed the payment should 935 // also be Failed at this poinnt. 936 finalStatus := StatusFailed 937 if test.settleFirst || test.settleLast { 938 finalStatus = StatusSucceeded 939 } 940 941 assertPaymentStatus(t, pControl, info.PaymentIdentifier, finalStatus) 942 943 // Finally assert we cannot register more attempts. 944 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 945 require.Equal(t, ErrPaymentTerminal, err) 946 } 947 948 for _, test := range tests { 949 test := test 950 subTest := fmt.Sprintf("first=%v, second=%v", 951 test.settleFirst, test.settleLast) 952 953 t.Run(subTest, func(t *testing.T) { 954 runSubTest(t, test) 955 }) 956 } 957 } 958 959 func TestPaymentControlMPPRecordValidation(t *testing.T) { 960 t.Parallel() 961 962 db, cleanup, err := MakeTestDB() 963 defer cleanup() 964 965 if err != nil { 966 t.Fatalf("unable to init db: %v", err) 967 } 968 969 pControl := NewPaymentControl(db) 970 971 info, attempt, _, err := genInfo() 972 if err != nil { 973 t.Fatalf("unable to generate htlc message: %v", err) 974 } 975 976 // Init the payment. 977 err = pControl.InitPayment(info.PaymentIdentifier, info) 978 if err != nil { 979 t.Fatalf("unable to send htlc message: %v", err) 980 } 981 982 // Create three unique attempts we'll use for the test, and 983 // register them with the payment control. We set each 984 // attempts's value to one third of the payment amount, and 985 // populate the MPP options. 986 shardAmt := info.Value / 3 987 attempt.Route.FinalHop().AmtToForward = shardAmt 988 attempt.Route.FinalHop().MPP = record.NewMPP( 989 info.Value, [32]byte{1}, 990 ) 991 992 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) 993 if err != nil { 994 t.Fatalf("unable to send htlc message: %v", err) 995 } 996 997 // Now try to register a non-MPP attempt, which should fail. 998 b := *attempt 999 b.AttemptID = 1 1000 b.Route.FinalHop().MPP = nil 1001 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 1002 if err != ErrMPPayment { 1003 t.Fatalf("expected ErrMPPayment, got: %v", err) 1004 } 1005 1006 // Try to register attempt one with a different payment address. 1007 b.Route.FinalHop().MPP = record.NewMPP( 1008 info.Value, [32]byte{2}, 1009 ) 1010 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 1011 if err != ErrMPPPaymentAddrMismatch { 1012 t.Fatalf("expected ErrMPPPaymentAddrMismatch, got: %v", err) 1013 } 1014 1015 // Try registering one with a different total amount. 1016 b.Route.FinalHop().MPP = record.NewMPP( 1017 info.Value/2, [32]byte{1}, 1018 ) 1019 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 1020 if err != ErrMPPTotalAmountMismatch { 1021 t.Fatalf("expected ErrMPPTotalAmountMismatch, got: %v", err) 1022 } 1023 1024 // Create and init a new payment. This time we'll check that we cannot 1025 // register an MPP attempt if we already registered a non-MPP one. 1026 info, attempt, _, err = genInfo() 1027 if err != nil { 1028 t.Fatalf("unable to generate htlc message: %v", err) 1029 } 1030 1031 err = pControl.InitPayment(info.PaymentIdentifier, info) 1032 if err != nil { 1033 t.Fatalf("unable to send htlc message: %v", err) 1034 } 1035 1036 attempt.Route.FinalHop().MPP = nil 1037 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt) 1038 if err != nil { 1039 t.Fatalf("unable to send htlc message: %v", err) 1040 } 1041 1042 // Attempt to register an MPP attempt, which should fail. 1043 b = *attempt 1044 b.AttemptID = 1 1045 b.Route.FinalHop().MPP = record.NewMPP( 1046 info.Value, [32]byte{1}, 1047 ) 1048 1049 _, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b) 1050 if err != ErrNonMPPayment { 1051 t.Fatalf("expected ErrNonMPPayment, got: %v", err) 1052 } 1053 } 1054 1055 // assertPaymentStatus retrieves the status of the payment referred to by hash 1056 // and compares it with the expected state. 1057 func assertPaymentStatus(t *testing.T, p *PaymentControl, 1058 hash lntypes.Hash, expStatus PaymentStatus) { 1059 1060 t.Helper() 1061 1062 payment, err := p.FetchPayment(hash) 1063 if expStatus == StatusUnknown && err == ErrPaymentNotInitiated { 1064 return 1065 } 1066 if err != nil { 1067 t.Fatal(err) 1068 } 1069 1070 if payment.Status != expStatus { 1071 t.Fatalf("payment status mismatch: expected %v, got %v", 1072 expStatus, payment.Status) 1073 } 1074 } 1075 1076 type htlcStatus struct { 1077 *HTLCAttemptInfo 1078 settle *lntypes.Preimage 1079 failure *HTLCFailReason 1080 } 1081 1082 // assertPaymentInfo retrieves the payment referred to by hash and verifies the 1083 // expected values. 1084 func assertPaymentInfo(t *testing.T, p *PaymentControl, hash lntypes.Hash, 1085 c *PaymentCreationInfo, f *FailureReason, a *htlcStatus) { 1086 1087 t.Helper() 1088 1089 payment, err := p.FetchPayment(hash) 1090 if err != nil { 1091 t.Fatal(err) 1092 } 1093 1094 if !reflect.DeepEqual(payment.Info, c) { 1095 t.Fatalf("PaymentCreationInfos don't match: %v vs %v", 1096 spew.Sdump(payment.Info), spew.Sdump(c)) 1097 } 1098 1099 if f != nil { 1100 if *payment.FailureReason != *f { 1101 t.Fatal("unexpected failure reason") 1102 } 1103 } else { 1104 if payment.FailureReason != nil { 1105 t.Fatal("unexpected failure reason") 1106 } 1107 } 1108 1109 if a == nil { 1110 if len(payment.HTLCs) > 0 { 1111 t.Fatal("expected no htlcs") 1112 } 1113 return 1114 } 1115 1116 htlc := payment.HTLCs[a.AttemptID] 1117 if err := assertRouteEqual(&htlc.Route, &a.Route); err != nil { 1118 t.Fatal("routes do not match") 1119 } 1120 1121 if htlc.AttemptID != a.AttemptID { 1122 t.Fatalf("unnexpected attempt ID %v, expected %v", 1123 htlc.AttemptID, a.AttemptID) 1124 } 1125 1126 if a.failure != nil { 1127 if htlc.Failure == nil { 1128 t.Fatalf("expected HTLC to be failed") 1129 } 1130 1131 if htlc.Failure.Reason != *a.failure { 1132 t.Fatalf("expected HTLC failure %v, had %v", 1133 *a.failure, htlc.Failure.Reason) 1134 } 1135 } else if htlc.Failure != nil { 1136 t.Fatalf("expected no HTLC failure") 1137 } 1138 1139 if a.settle != nil { 1140 if htlc.Settle.Preimage != *a.settle { 1141 t.Fatalf("Preimages don't match: %x vs %x", 1142 htlc.Settle.Preimage, a.settle) 1143 } 1144 } else if htlc.Settle != nil { 1145 t.Fatal("expected no settle info") 1146 } 1147 } 1148 1149 // fetchPaymentIndexEntry gets the payment hash for the sequence number provided 1150 // from our payment indexes bucket. 1151 func fetchPaymentIndexEntry(_ *testing.T, p *PaymentControl, 1152 sequenceNumber uint64) (*lntypes.Hash, error) { 1153 1154 var hash lntypes.Hash 1155 1156 if err := kvdb.View(p.db, func(tx walletdb.ReadTx) error { 1157 indexBucket := tx.ReadBucket(paymentsIndexBucket) 1158 key := make([]byte, 8) 1159 byteOrder.PutUint64(key, sequenceNumber) 1160 1161 indexValue := indexBucket.Get(key) 1162 if indexValue == nil { 1163 return errNoSequenceNrIndex 1164 } 1165 1166 r := bytes.NewReader(indexValue) 1167 1168 var err error 1169 hash, err = deserializePaymentIndex(r) 1170 return err 1171 }, func() { 1172 hash = lntypes.Hash{} 1173 }); err != nil { 1174 return nil, err 1175 } 1176 1177 return &hash, nil 1178 } 1179 1180 // assertPaymentIndex looks up the index for a payment in the db and checks 1181 // that its payment hash matches the expected hash passed in. 1182 func assertPaymentIndex(t *testing.T, p *PaymentControl, 1183 expectedHash lntypes.Hash) { 1184 1185 // Lookup the payment so that we have its sequence number and check 1186 // that is has correctly been indexed in the payment indexes bucket. 1187 pmt, err := p.FetchPayment(expectedHash) 1188 require.NoError(t, err) 1189 1190 hash, err := fetchPaymentIndexEntry(t, p, pmt.SequenceNum) 1191 require.NoError(t, err) 1192 assert.Equal(t, expectedHash, *hash) 1193 } 1194 1195 // assertNoIndex checks that an index for the sequence number provided does not 1196 // exist. 1197 func assertNoIndex(t *testing.T, p *PaymentControl, seqNr uint64) { 1198 _, err := fetchPaymentIndexEntry(t, p, seqNr) 1199 require.Equal(t, errNoSequenceNrIndex, err) 1200 } 1201 1202 // payment is a helper structure that holds basic information on a test payment, 1203 // such as the payment id, the status and the total number of HTLCs attempted. 1204 type payment struct { 1205 id lntypes.Hash 1206 status PaymentStatus 1207 htlcs int 1208 } 1209 1210 // createTestPayments registers payments depending on the provided statuses in 1211 // the payments slice. Each payment will receive one failed HTLC and another 1212 // HTLC depending on the final status of the payment provided. 1213 func createTestPayments(t *testing.T, p *PaymentControl, payments []*payment) { 1214 attemptID := uint64(0) 1215 1216 for i := 0; i < len(payments); i++ { 1217 info, attempt, preimg, err := genInfo() 1218 require.NoError(t, err, "unable to generate htlc message") 1219 1220 // Set the payment id accordingly in the payments slice. 1221 payments[i].id = info.PaymentIdentifier 1222 1223 attempt.AttemptID = attemptID 1224 attemptID++ 1225 1226 // Init the payment. 1227 err = p.InitPayment(info.PaymentIdentifier, info) 1228 require.NoError(t, err, "unable to send htlc message") 1229 1230 // Register and fail the first attempt for all payments. 1231 _, err = p.RegisterAttempt(info.PaymentIdentifier, attempt) 1232 require.NoError(t, err, "unable to send htlc message") 1233 1234 htlcFailure := HTLCFailUnreadable 1235 _, err = p.FailAttempt( 1236 info.PaymentIdentifier, attempt.AttemptID, 1237 &HTLCFailInfo{ 1238 Reason: htlcFailure, 1239 }, 1240 ) 1241 require.NoError(t, err, "unable to fail htlc") 1242 1243 // Increase the HTLC counter in the payments slice for the 1244 // failed attempt. 1245 payments[i].htlcs++ 1246 1247 // Depending on the test case, fail or succeed the next 1248 // attempt. 1249 attempt.AttemptID = attemptID 1250 attemptID++ 1251 1252 _, err = p.RegisterAttempt(info.PaymentIdentifier, attempt) 1253 require.NoError(t, err, "unable to send htlc message") 1254 1255 switch payments[i].status { 1256 1257 // Fail the attempt and the payment overall. 1258 case StatusFailed: 1259 htlcFailure := HTLCFailUnreadable 1260 _, err = p.FailAttempt( 1261 info.PaymentIdentifier, attempt.AttemptID, 1262 &HTLCFailInfo{ 1263 Reason: htlcFailure, 1264 }, 1265 ) 1266 require.NoError(t, err, "unable to fail htlc") 1267 1268 failReason := FailureReasonNoRoute 1269 _, err = p.Fail(info.PaymentIdentifier, 1270 failReason) 1271 require.NoError(t, err, "unable to fail payment hash") 1272 1273 // Settle the attempt 1274 case StatusSucceeded: 1275 _, err := p.SettleAttempt( 1276 info.PaymentIdentifier, attempt.AttemptID, 1277 &HTLCSettleInfo{ 1278 Preimage: preimg, 1279 }, 1280 ) 1281 require.NoError(t, err, "no error should have been "+ 1282 "received from settling a htlc attempt") 1283 1284 // We leave the attempt in-flight by doing nothing. 1285 case StatusInFlight: 1286 } 1287 1288 // Increase the HTLC counter in the payments slice for any 1289 // attempt above. 1290 payments[i].htlcs++ 1291 } 1292 } 1293 1294 // assertPayments is a helper function that given a slice of payment and 1295 // indices for the slice asserts that exactly the same payments in the 1296 // slice for the provided indices exist when fetching payments from the 1297 // database. 1298 func assertPayments(t *testing.T, db *DB, payments []*payment) { 1299 t.Helper() 1300 1301 dbPayments, err := db.FetchPayments() 1302 require.NoError(t, err, "could not fetch payments from db") 1303 1304 // Make sure that the number of fetched payments is the same 1305 // as expected. 1306 require.Len(t, dbPayments, len(payments), "unexpected number of payments") 1307 1308 // Convert fetched payments of type MPPayment to our helper structure. 1309 p := make([]*payment, len(dbPayments)) 1310 for i, dbPayment := range dbPayments { 1311 p[i] = &payment{ 1312 id: dbPayment.Info.PaymentIdentifier, 1313 status: dbPayment.Status, 1314 htlcs: len(dbPayment.HTLCs), 1315 } 1316 } 1317 1318 // Check that each payment we want to assert exists in the database. 1319 require.Equal(t, payments, p) 1320 }