github.com/decred/dcrlnd@v0.7.6/channeldb/invoice_test.go (about) 1 package channeldb 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "fmt" 7 "math" 8 "testing" 9 "time" 10 11 "github.com/decred/dcrlnd/clock" 12 "github.com/decred/dcrlnd/feature" 13 "github.com/decred/dcrlnd/lntypes" 14 "github.com/decred/dcrlnd/lnwire" 15 "github.com/decred/dcrlnd/record" 16 "github.com/decred/dcrlnd/tlv" 17 "github.com/stretchr/testify/require" 18 ) 19 20 var ( 21 emptyFeatures = lnwire.NewFeatureVector(nil, lnwire.Features) 22 ampFeatures = lnwire.NewFeatureVector( 23 lnwire.NewRawFeatureVector( 24 lnwire.TLVOnionPayloadOptional, 25 lnwire.PaymentAddrOptional, 26 lnwire.AMPRequired, 27 ), 28 lnwire.Features, 29 ) 30 testNow = time.Unix(1, 0) 31 ) 32 33 func randInvoice(value lnwire.MilliAtom) (*Invoice, error) { 34 var ( 35 pre lntypes.Preimage 36 payAddr [32]byte 37 ) 38 if _, err := rand.Read(pre[:]); err != nil { 39 return nil, err 40 } 41 if _, err := rand.Read(payAddr[:]); err != nil { 42 return nil, err 43 } 44 45 i := &Invoice{ 46 CreationDate: testNow, 47 Terms: ContractTerm{ 48 Expiry: 4000, 49 PaymentPreimage: &pre, 50 PaymentAddr: payAddr, 51 Value: value, 52 Features: emptyFeatures, 53 }, 54 Htlcs: map[CircuitKey]*InvoiceHTLC{}, 55 AMPState: map[SetID]InvoiceStateAMP{}, 56 } 57 i.Memo = []byte("memo") 58 59 // Create a random byte slice of MaxPaymentRequestSize bytes to be used 60 // as a dummy paymentrequest, and determine if it should be set based 61 // on one of the random bytes. 62 var r [MaxPaymentRequestSize]byte 63 if _, err := rand.Read(r[:]); err != nil { 64 return nil, err 65 } 66 if r[0]&1 == 0 { 67 i.PaymentRequest = r[:] 68 } else { 69 i.PaymentRequest = []byte("") 70 } 71 72 return i, nil 73 } 74 75 // settleTestInvoice settles a test invoice. 76 func settleTestInvoice(invoice *Invoice, settleIndex uint64) { 77 invoice.SettleDate = testNow 78 invoice.AmtPaid = invoice.Terms.Value 79 invoice.State = ContractSettled 80 invoice.Htlcs[CircuitKey{}] = &InvoiceHTLC{ 81 Amt: invoice.Terms.Value, 82 AcceptTime: testNow, 83 ResolveTime: testNow, 84 State: HtlcStateSettled, 85 CustomRecords: make(record.CustomSet), 86 } 87 invoice.SettleIndex = settleIndex 88 } 89 90 // Tests that pending invoices are those which are either in ContractOpen or 91 // in ContractAccepted state. 92 func TestInvoiceIsPending(t *testing.T) { 93 contractStates := []ContractState{ 94 ContractOpen, ContractSettled, ContractCanceled, ContractAccepted, 95 } 96 97 for _, state := range contractStates { 98 invoice := Invoice{ 99 State: state, 100 } 101 102 // We expect that an invoice is pending if it's either in ContractOpen 103 // or ContractAccepted state. 104 pending := (state == ContractOpen || state == ContractAccepted) 105 106 if invoice.IsPending() != pending { 107 t.Fatalf("expected pending: %v, got: %v, invoice: %v", 108 pending, invoice.IsPending(), invoice) 109 } 110 } 111 } 112 113 type invWorkflowTest struct { 114 name string 115 queryPayHash bool 116 queryPayAddr bool 117 } 118 119 var invWorkflowTests = []invWorkflowTest{ 120 { 121 name: "unknown", 122 queryPayHash: false, 123 queryPayAddr: false, 124 }, 125 { 126 name: "only payhash known", 127 queryPayHash: true, 128 queryPayAddr: false, 129 }, 130 { 131 name: "payaddr and payhash known", 132 queryPayHash: true, 133 queryPayAddr: true, 134 }, 135 } 136 137 // TestInvoiceWorkflow asserts the basic process of inserting, fetching, and 138 // updating an invoice. We assert that the flow is successful using when 139 // querying with various combinations of payment hash and payment address. 140 func TestInvoiceWorkflow(t *testing.T) { 141 t.Parallel() 142 143 for _, test := range invWorkflowTests { 144 test := test 145 t.Run(test.name, func(t *testing.T) { 146 testInvoiceWorkflow(t, test) 147 }) 148 } 149 } 150 151 func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { 152 db, cleanUp, err := MakeTestDB() 153 defer cleanUp() 154 if err != nil { 155 t.Fatalf("unable to make test db: %v", err) 156 } 157 158 // Create a fake invoice which we'll use several times in the tests 159 // below. 160 fakeInvoice, err := randInvoice(10000) 161 if err != nil { 162 t.Fatalf("unable to create invoice: %v", err) 163 } 164 invPayHash := fakeInvoice.Terms.PaymentPreimage.Hash() 165 166 // Select the payment hash and payment address we will use to lookup or 167 // update the invoice for the remainder of the test. 168 var ( 169 payHash lntypes.Hash 170 payAddr *[32]byte 171 ref InvoiceRef 172 ) 173 switch { 174 case test.queryPayHash && test.queryPayAddr: 175 payHash = invPayHash 176 payAddr = &fakeInvoice.Terms.PaymentAddr 177 ref = InvoiceRefByHashAndAddr(payHash, *payAddr) 178 case test.queryPayHash: 179 payHash = invPayHash 180 ref = InvoiceRefByHash(payHash) 181 } 182 183 // Add the invoice to the database, this should succeed as there aren't 184 // any existing invoices within the database with the same payment 185 // hash. 186 if _, err := db.AddInvoice(fakeInvoice, invPayHash); err != nil { 187 t.Fatalf("unable to find invoice: %v", err) 188 } 189 190 // Attempt to retrieve the invoice which was just added to the 191 // database. It should be found, and the invoice returned should be 192 // identical to the one created above. 193 dbInvoice, err := db.LookupInvoice(ref) 194 if !test.queryPayAddr && !test.queryPayHash { 195 if err != ErrInvoiceNotFound { 196 t.Fatalf("invoice should not exist: %v", err) 197 } 198 return 199 } 200 201 require.Equal(t, 202 *fakeInvoice, dbInvoice, 203 "invoice fetched from db doesn't match original", 204 ) 205 206 // The add index of the invoice retrieved from the database should now 207 // be fully populated. As this is the first index written to the DB, 208 // the addIndex should be 1. 209 if dbInvoice.AddIndex != 1 { 210 t.Fatalf("wrong add index: expected %v, got %v", 1, 211 dbInvoice.AddIndex) 212 } 213 214 // Settle the invoice, the version retrieved from the database should 215 // now have the settled bit toggle to true and a non-default 216 // SettledDate 217 payAmt := fakeInvoice.Terms.Value * 2 218 _, err = db.UpdateInvoice(ref, nil, getUpdateInvoice(payAmt)) 219 if err != nil { 220 t.Fatalf("unable to settle invoice: %v", err) 221 } 222 dbInvoice2, err := db.LookupInvoice(ref) 223 if err != nil { 224 t.Fatalf("unable to fetch invoice: %v", err) 225 } 226 if dbInvoice2.State != ContractSettled { 227 t.Fatalf("invoice should now be settled but isn't") 228 } 229 if dbInvoice2.SettleDate.IsZero() { 230 t.Fatalf("invoice should have non-zero SettledDate but isn't") 231 } 232 233 // Our 2x payment should be reflected, and also the settle index of 1 234 // should also have been committed for this index. 235 if dbInvoice2.AmtPaid != payAmt { 236 t.Fatalf("wrong amt paid: expected %v, got %v", payAmt, 237 dbInvoice2.AmtPaid) 238 } 239 if dbInvoice2.SettleIndex != 1 { 240 t.Fatalf("wrong settle index: expected %v, got %v", 1, 241 dbInvoice2.SettleIndex) 242 } 243 244 // Attempt to insert generated above again, this should fail as 245 // duplicates are rejected by the processing logic. 246 if _, err := db.AddInvoice(fakeInvoice, payHash); err != ErrDuplicateInvoice { 247 t.Fatalf("invoice insertion should fail due to duplication, "+ 248 "instead %v", err) 249 } 250 251 // Attempt to look up a non-existent invoice, this should also fail but 252 // with a "not found" error. 253 var fakeHash [32]byte 254 fakeRef := InvoiceRefByHash(fakeHash) 255 _, err = db.LookupInvoice(fakeRef) 256 if err != ErrInvoiceNotFound { 257 t.Fatalf("lookup should have failed, instead %v", err) 258 } 259 260 // Add 10 random invoices. 261 const numInvoices = 10 262 amt := lnwire.NewMAtomsFromAtoms(1000) 263 invoices := make([]*Invoice, numInvoices+1) 264 invoices[0] = &dbInvoice2 265 for i := 1; i < len(invoices); i++ { 266 invoice, err := randInvoice(amt) 267 if err != nil { 268 t.Fatalf("unable to create invoice: %v", err) 269 } 270 271 hash := invoice.Terms.PaymentPreimage.Hash() 272 if _, err := db.AddInvoice(invoice, hash); err != nil { 273 t.Fatalf("unable to add invoice %v", err) 274 } 275 276 invoices[i] = invoice 277 } 278 279 // Perform a scan to collect all the active invoices. 280 query := InvoiceQuery{ 281 IndexOffset: 0, 282 NumMaxInvoices: math.MaxUint64, 283 PendingOnly: false, 284 } 285 286 response, err := db.QueryInvoices(query) 287 if err != nil { 288 t.Fatalf("invoice query failed: %v", err) 289 } 290 291 // The retrieve list of invoices should be identical as since we're 292 // using big endian, the invoices should be retrieved in ascending 293 // order (and the primary key should be incremented with each 294 // insertion). 295 for i := 0; i < len(invoices); i++ { 296 require.Equal(t, 297 *invoices[i], response.Invoices[i], 298 "retrieved invoice doesn't match", 299 ) 300 } 301 } 302 303 // TestAddDuplicatePayAddr asserts that the payment addresses of inserted 304 // invoices are unique. 305 func TestAddDuplicatePayAddr(t *testing.T) { 306 db, cleanUp, err := MakeTestDB() 307 defer cleanUp() 308 require.NoError(t, err) 309 310 // Create two invoices with the same payment addr. 311 invoice1, err := randInvoice(1000) 312 require.NoError(t, err) 313 314 invoice2, err := randInvoice(20000) 315 require.NoError(t, err) 316 invoice2.Terms.PaymentAddr = invoice1.Terms.PaymentAddr 317 318 // First insert should succeed. 319 inv1Hash := invoice1.Terms.PaymentPreimage.Hash() 320 _, err = db.AddInvoice(invoice1, inv1Hash) 321 require.NoError(t, err) 322 323 // Second insert should fail with duplicate payment addr. 324 inv2Hash := invoice2.Terms.PaymentPreimage.Hash() 325 _, err = db.AddInvoice(invoice2, inv2Hash) 326 require.Error(t, err, ErrDuplicatePayAddr) 327 } 328 329 // TestAddDuplicateKeysendPayAddr asserts that we permit duplicate payment 330 // addresses to be inserted if they are blank to support JIT legacy keysend 331 // invoices. 332 func TestAddDuplicateKeysendPayAddr(t *testing.T) { 333 db, cleanUp, err := MakeTestDB() 334 defer cleanUp() 335 require.NoError(t, err) 336 337 // Create two invoices with the same _blank_ payment addr. 338 invoice1, err := randInvoice(1000) 339 require.NoError(t, err) 340 invoice1.Terms.PaymentAddr = BlankPayAddr 341 342 invoice2, err := randInvoice(20000) 343 require.NoError(t, err) 344 invoice2.Terms.PaymentAddr = BlankPayAddr 345 346 // Inserting both should succeed without a duplicate payment address 347 // failure. 348 inv1Hash := invoice1.Terms.PaymentPreimage.Hash() 349 _, err = db.AddInvoice(invoice1, inv1Hash) 350 require.NoError(t, err) 351 352 inv2Hash := invoice2.Terms.PaymentPreimage.Hash() 353 _, err = db.AddInvoice(invoice2, inv2Hash) 354 require.NoError(t, err) 355 356 // Querying for each should succeed. Here we use hash+addr refs since 357 // the lookup will fail if the hash and addr point to different 358 // invoices, so if both succeed we can be assured they aren't included 359 // in the payment address index. 360 ref1 := InvoiceRefByHashAndAddr(inv1Hash, BlankPayAddr) 361 dbInv1, err := db.LookupInvoice(ref1) 362 require.NoError(t, err) 363 require.Equal(t, invoice1, &dbInv1) 364 365 ref2 := InvoiceRefByHashAndAddr(inv2Hash, BlankPayAddr) 366 dbInv2, err := db.LookupInvoice(ref2) 367 require.NoError(t, err) 368 require.Equal(t, invoice2, &dbInv2) 369 } 370 371 // TestFailInvoiceLookupMPPPayAddrOnly asserts that looking up a MPP invoice 372 // that matches _only_ by payment address fails with ErrInvoiceNotFound. This 373 // ensures that the HTLC's payment hash always matches the payment hash in the 374 // returned invoice. 375 func TestFailInvoiceLookupMPPPayAddrOnly(t *testing.T) { 376 db, cleanUp, err := MakeTestDB() 377 defer cleanUp() 378 require.NoError(t, err) 379 380 // Create and insert a random invoice. 381 invoice, err := randInvoice(1000) 382 require.NoError(t, err) 383 384 payHash := invoice.Terms.PaymentPreimage.Hash() 385 payAddr := invoice.Terms.PaymentAddr 386 _, err = db.AddInvoice(invoice, payHash) 387 require.NoError(t, err) 388 389 // Modify the queried payment hash to be invalid. 390 payHash[0] ^= 0x01 391 392 // Lookup the invoice by (invalid) payment hash and payment address. The 393 // lookup should fail since we require the payment hash to match for 394 // legacy/MPP invoices, as this guarantees that the preimage is valid 395 // for the given HTLC. 396 ref := InvoiceRefByHashAndAddr(payHash, payAddr) 397 _, err = db.LookupInvoice(ref) 398 require.Equal(t, ErrInvoiceNotFound, err) 399 } 400 401 // TestInvRefEquivocation asserts that retrieving or updating an invoice using 402 // an equivocating InvoiceRef results in ErrInvRefEquivocation. 403 func TestInvRefEquivocation(t *testing.T) { 404 db, cleanUp, err := MakeTestDB() 405 defer cleanUp() 406 require.NoError(t, err) 407 408 // Add two random invoices. 409 invoice1, err := randInvoice(1000) 410 require.NoError(t, err) 411 412 inv1Hash := invoice1.Terms.PaymentPreimage.Hash() 413 _, err = db.AddInvoice(invoice1, inv1Hash) 414 require.NoError(t, err) 415 416 invoice2, err := randInvoice(2000) 417 require.NoError(t, err) 418 419 inv2Hash := invoice2.Terms.PaymentPreimage.Hash() 420 _, err = db.AddInvoice(invoice2, inv2Hash) 421 require.NoError(t, err) 422 423 // Now, query using invoice 1's payment address, but invoice 2's payment 424 // hash. We expect an error since the invref points to multiple 425 // invoices. 426 ref := InvoiceRefByHashAndAddr(inv2Hash, invoice1.Terms.PaymentAddr) 427 _, err = db.LookupInvoice(ref) 428 require.Error(t, err, ErrInvRefEquivocation) 429 430 // The same error should be returned when updating an equivocating 431 // reference. 432 nop := func(_ *Invoice) (*InvoiceUpdateDesc, error) { 433 return nil, nil 434 } 435 _, err = db.UpdateInvoice(ref, nil, nop) 436 require.Error(t, err, ErrInvRefEquivocation) 437 } 438 439 // TestInvoiceCancelSingleHtlc tests that a single htlc can be canceled on the 440 // invoice. 441 func TestInvoiceCancelSingleHtlc(t *testing.T) { 442 t.Parallel() 443 444 db, cleanUp, err := MakeTestDB() 445 defer cleanUp() 446 if err != nil { 447 t.Fatalf("unable to make test db: %v", err) 448 } 449 450 preimage := lntypes.Preimage{1} 451 paymentHash := preimage.Hash() 452 453 testInvoice := &Invoice{ 454 Htlcs: map[CircuitKey]*InvoiceHTLC{}, 455 Terms: ContractTerm{ 456 Value: lnwire.NewMAtomsFromAtoms(10000), 457 Features: emptyFeatures, 458 PaymentPreimage: &preimage, 459 }, 460 } 461 462 if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil { 463 t.Fatalf("unable to find invoice: %v", err) 464 } 465 466 // Accept an htlc on this invoice. 467 key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4} 468 htlc := HtlcAcceptDesc{ 469 Amt: 500, 470 CustomRecords: make(record.CustomSet), 471 } 472 473 ref := InvoiceRefByHash(paymentHash) 474 invoice, err := db.UpdateInvoice(ref, nil, 475 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 476 return &InvoiceUpdateDesc{ 477 AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ 478 key: &htlc, 479 }, 480 }, nil 481 }) 482 if err != nil { 483 t.Fatalf("unable to add invoice htlc: %v", err) 484 } 485 if len(invoice.Htlcs) != 1 { 486 t.Fatalf("expected the htlc to be added") 487 } 488 if invoice.Htlcs[key].State != HtlcStateAccepted { 489 t.Fatalf("expected htlc in state accepted") 490 } 491 492 // Cancel the htlc again. 493 invoice, err = db.UpdateInvoice(ref, nil, 494 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 495 return &InvoiceUpdateDesc{ 496 CancelHtlcs: map[CircuitKey]struct{}{ 497 key: {}, 498 }, 499 }, nil 500 }) 501 if err != nil { 502 t.Fatalf("unable to cancel htlc: %v", err) 503 } 504 if len(invoice.Htlcs) != 1 { 505 t.Fatalf("expected the htlc to be present") 506 } 507 if invoice.Htlcs[key].State != HtlcStateCanceled { 508 t.Fatalf("expected htlc in state canceled") 509 } 510 } 511 512 // TestInvoiceCancelSingleHtlcAMP tests that it's possible to cancel a single 513 // invoice of an AMP HTLC across multiple set IDs, and also have that update 514 // the amount paid and other related fields as well. 515 func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { 516 t.Parallel() 517 518 db, cleanUp, err := MakeTestDB(OptionClock(testClock)) 519 defer cleanUp() 520 require.NoError(t, err, "unable to make test db: %v", err) 521 522 // We'll start out by creating an invoice and writing it to the DB. 523 amt := lnwire.NewMAtomsFromAtoms(1000) 524 invoice, err := randInvoice(amt) 525 require.Nil(t, err) 526 527 // Set AMP-specific features so that we can settle with HTLC-level 528 // preimages. 529 invoice.Terms.Features = ampFeatures 530 531 preimage := *invoice.Terms.PaymentPreimage 532 payHash := preimage.Hash() 533 _, err = db.AddInvoice(invoice, payHash) 534 require.Nil(t, err) 535 536 // Add two HTLC sets, one with one HTLC and the other with two. 537 setID1 := &[32]byte{1} 538 setID2 := &[32]byte{2} 539 540 ref := InvoiceRefByHashAndAddr(payHash, invoice.Terms.PaymentAddr) 541 542 // The first set ID with a single HTLC added. 543 _, err = db.UpdateInvoice( 544 ref, (*SetID)(setID1), updateAcceptAMPHtlc(0, amt, setID1, true), 545 ) 546 require.Nil(t, err) 547 548 // The second set ID with two HTLCs added. 549 _, err = db.UpdateInvoice( 550 ref, (*SetID)(setID2), updateAcceptAMPHtlc(1, amt, setID2, true), 551 ) 552 require.Nil(t, err) 553 dbInvoice, err := db.UpdateInvoice( 554 ref, (*SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, true), 555 ) 556 require.Nil(t, err) 557 558 // At this point, we should detect that 3k satoshis total has been 559 // paid. 560 require.Equal(t, dbInvoice.AmtPaid, amt*3) 561 562 // Now we'll cancel a single invoice, and assert that the amount paid 563 // is decremented, and the state for that HTLC set reflects that is 564 // been cancelled. 565 _, err = db.UpdateInvoice(ref, (*SetID)(setID1), 566 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 567 return &InvoiceUpdateDesc{ 568 CancelHtlcs: map[CircuitKey]struct{}{ 569 {HtlcID: 0}: {}, 570 }, 571 SetID: (*SetID)(setID1), 572 }, nil 573 }) 574 if err != nil { 575 t.Fatalf("unable to cancel htlc: %v", err) 576 } 577 578 freshInvoice, err := db.LookupInvoice(ref) 579 require.Nil(t, err) 580 dbInvoice = &freshInvoice 581 582 // The amount paid should reflect that an invoice was cancelled. 583 require.Equal(t, dbInvoice.AmtPaid, amt*2) 584 585 // The HTLC and AMP state should also show that only one HTLC set is 586 // left. 587 invoice.State = ContractOpen 588 invoice.AmtPaid = 2 * amt 589 invoice.SettleDate = dbInvoice.SettleDate 590 invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ 591 {HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID1, payHash, &preimage), 592 {HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, payHash, &preimage), 593 {HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, payHash, &preimage), 594 } 595 invoice.AMPState[*setID1] = InvoiceStateAMP{ 596 State: HtlcStateCanceled, 597 InvoiceKeys: map[CircuitKey]struct{}{ 598 {HtlcID: 0}: {}, 599 }, 600 } 601 invoice.AMPState[*setID2] = InvoiceStateAMP{ 602 State: HtlcStateAccepted, 603 AmtPaid: amt * 2, 604 InvoiceKeys: map[CircuitKey]struct{}{ 605 {HtlcID: 1}: {}, 606 {HtlcID: 2}: {}, 607 }, 608 } 609 610 invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateCanceled 611 invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0) 612 613 require.Equal(t, invoice, dbInvoice) 614 615 // Next, we'll cancel the _other_ HTLCs active, but we'll do them one 616 // by one. 617 _, err = db.UpdateInvoice(ref, (*SetID)(setID2), 618 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 619 return &InvoiceUpdateDesc{ 620 CancelHtlcs: map[CircuitKey]struct{}{ 621 {HtlcID: 1}: {}, 622 }, 623 SetID: (*SetID)(setID2), 624 }, nil 625 }) 626 if err != nil { 627 t.Fatalf("unable to cancel htlc: %v", err) 628 } 629 630 freshInvoice, err = db.LookupInvoice(ref) 631 require.Nil(t, err) 632 dbInvoice = &freshInvoice 633 634 invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateCanceled 635 invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0) 636 invoice.AmtPaid = amt 637 638 ampState := invoice.AMPState[*setID2] 639 ampState.State = HtlcStateCanceled 640 ampState.AmtPaid = amt 641 invoice.AMPState[*setID2] = ampState 642 643 require.Equal(t, invoice, dbInvoice) 644 645 // Now we'll cancel the final HTLC, which should cause all the active 646 // HTLCs to transition to the cancelled state. 647 _, err = db.UpdateInvoice(ref, (*SetID)(setID2), 648 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 649 return &InvoiceUpdateDesc{ 650 CancelHtlcs: map[CircuitKey]struct{}{ 651 {HtlcID: 2}: {}, 652 }, 653 SetID: (*SetID)(setID2), 654 }, nil 655 }) 656 if err != nil { 657 t.Fatalf("unable to cancel htlc: %v", err) 658 } 659 660 freshInvoice, err = db.LookupInvoice(ref) 661 require.Nil(t, err) 662 dbInvoice = &freshInvoice 663 664 ampState = invoice.AMPState[*setID2] 665 ampState.AmtPaid = 0 666 invoice.AMPState[*setID2] = ampState 667 668 invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateCanceled 669 invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0) 670 invoice.AmtPaid = 0 671 672 require.Equal(t, invoice, dbInvoice) 673 } 674 675 // TestInvoiceTimeSeries tests that newly added invoices invoices, as well as 676 // settled invoices are added to the database are properly placed in the add 677 // add or settle index which serves as an event time series. 678 func TestInvoiceAddTimeSeries(t *testing.T) { 679 t.Parallel() 680 681 db, cleanUp, err := MakeTestDB(OptionClock(testClock)) 682 defer cleanUp() 683 if err != nil { 684 t.Fatalf("unable to make test db: %v", err) 685 } 686 687 _, err = db.InvoicesAddedSince(0) 688 require.NoError(t, err) 689 690 // We'll start off by creating 20 random invoices, and inserting them 691 // into the database. 692 const numInvoices = 20 693 amt := lnwire.NewMAtomsFromAtoms(1000) 694 invoices := make([]Invoice, numInvoices) 695 for i := 0; i < len(invoices); i++ { 696 invoice, err := randInvoice(amt) 697 if err != nil { 698 t.Fatalf("unable to create invoice: %v", err) 699 } 700 701 paymentHash := invoice.Terms.PaymentPreimage.Hash() 702 703 if _, err := db.AddInvoice(invoice, paymentHash); err != nil { 704 t.Fatalf("unable to add invoice %v", err) 705 } 706 707 invoices[i] = *invoice 708 } 709 710 // With the invoices constructed, we'll now create a series of queries 711 // that we'll use to assert expected return values of 712 // InvoicesAddedSince. 713 addQueries := []struct { 714 sinceAddIndex uint64 715 716 resp []Invoice 717 }{ 718 // If we specify a value of zero, we shouldn't get any invoices 719 // back. 720 { 721 sinceAddIndex: 0, 722 }, 723 724 // If we specify a value well beyond the number of inserted 725 // invoices, we shouldn't get any invoices back. 726 { 727 sinceAddIndex: 99999999, 728 }, 729 730 // Using an index of 1 should result in all values, but the 731 // first one being returned. 732 { 733 sinceAddIndex: 1, 734 resp: invoices[1:], 735 }, 736 737 // If we use an index of 10, then we should retrieve the 738 // reaming 10 invoices. 739 { 740 sinceAddIndex: 10, 741 resp: invoices[10:], 742 }, 743 } 744 745 for i, query := range addQueries { 746 resp, err := db.InvoicesAddedSince(query.sinceAddIndex) 747 if err != nil { 748 t.Fatalf("unable to query: %v", err) 749 } 750 751 require.Equal(t, len(query.resp), len(resp)) 752 753 for j := 0; j < len(query.resp); j++ { 754 require.Equal(t, 755 query.resp[j], resp[j], 756 fmt.Sprintf("test: #%v, item: #%v", i, j), 757 ) 758 } 759 } 760 761 _, err = db.InvoicesSettledSince(0) 762 require.NoError(t, err) 763 764 var settledInvoices []Invoice 765 var settleIndex uint64 = 1 766 // We'll now only settle the latter half of each of those invoices. 767 for i := 10; i < len(invoices); i++ { 768 invoice := &invoices[i] 769 770 paymentHash := invoice.Terms.PaymentPreimage.Hash() 771 772 ref := InvoiceRefByHash(paymentHash) 773 _, err := db.UpdateInvoice( 774 ref, nil, getUpdateInvoice(invoice.Terms.Value), 775 ) 776 if err != nil { 777 t.Fatalf("unable to settle invoice: %v", err) 778 } 779 780 // Create the settled invoice for the expectation set. 781 settleTestInvoice(invoice, settleIndex) 782 settleIndex++ 783 784 settledInvoices = append(settledInvoices, *invoice) 785 } 786 787 // We'll now prepare an additional set of queries to ensure the settle 788 // time series has properly been maintained in the database. 789 settleQueries := []struct { 790 sinceSettleIndex uint64 791 792 resp []Invoice 793 }{ 794 // If we specify a value of zero, we shouldn't get any settled 795 // invoices back. 796 { 797 sinceSettleIndex: 0, 798 }, 799 800 // If we specify a value well beyond the number of settled 801 // invoices, we shouldn't get any invoices back. 802 { 803 sinceSettleIndex: 99999999, 804 }, 805 806 // Using an index of 1 should result in the final 10 invoices 807 // being returned, as we only settled those. 808 { 809 sinceSettleIndex: 1, 810 resp: settledInvoices[1:], 811 }, 812 } 813 814 for i, query := range settleQueries { 815 resp, err := db.InvoicesSettledSince(query.sinceSettleIndex) 816 if err != nil { 817 t.Fatalf("unable to query: %v", err) 818 } 819 820 require.Equal(t, len(query.resp), len(resp)) 821 822 for j := 0; j < len(query.resp); j++ { 823 require.Equal(t, 824 query.resp[j], resp[j], 825 fmt.Sprintf("test: #%v, item: #%v", i, j), 826 ) 827 } 828 } 829 } 830 831 // TestSettleIndexAmpPayments tests that repeated settles of the same invoice 832 // end up properly adding entries to the settle index, and the 833 // InvoicesSettledSince will emit a "projected" version of the invoice w/ 834 // _just_ that HTLC information. 835 func TestSettleIndexAmpPayments(t *testing.T) { 836 t.Parallel() 837 838 testClock := clock.NewTestClock(testNow) 839 db, cleanUp, err := MakeTestDB(OptionClock(testClock)) 840 defer cleanUp() 841 require.Nil(t, err) 842 843 // First, we'll make a sample invoice that'll be paid to several times 844 // below. 845 amt := lnwire.NewMAtomsFromAtoms(1000) 846 testInvoice, err := randInvoice(amt) 847 require.Nil(t, err) 848 testInvoice.Terms.Features = ampFeatures 849 850 // Add the invoice to the DB, we use a dummy payment hash here but the 851 // invoice will have a valid payment address set. 852 preimage := *testInvoice.Terms.PaymentPreimage 853 payHash := preimage.Hash() 854 _, err = db.AddInvoice(testInvoice, payHash) 855 require.Nil(t, err) 856 857 // Now that we have the invoice, we'll simulate 3 different HTLC sets 858 // being attached to the invoice. These represent 3 different 859 // concurrent payments. 860 setID1 := &[32]byte{1} 861 setID2 := &[32]byte{2} 862 setID3 := &[32]byte{3} 863 864 ref := InvoiceRefByHashAndAddr(payHash, testInvoice.Terms.PaymentAddr) 865 _, err = db.UpdateInvoice( 866 ref, (*SetID)(setID1), updateAcceptAMPHtlc(1, amt, setID1, true), 867 ) 868 require.Nil(t, err) 869 _, err = db.UpdateInvoice( 870 ref, (*SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, true), 871 ) 872 require.Nil(t, err) 873 _, err = db.UpdateInvoice( 874 ref, (*SetID)(setID3), updateAcceptAMPHtlc(3, amt, setID3, true), 875 ) 876 require.Nil(t, err) 877 878 // Now that the invoices have been accepted, we'll exercise the 879 // behavior of the LookupInvoice call that allows us to modify exactly 880 // how we query for invoices. 881 // 882 // First, we'll query for the invoice with just the payment addr, but 883 // specify no HTLcs are to be included. 884 refNoHtlcs := InvoiceRefByAddrBlankHtlc(testInvoice.Terms.PaymentAddr) 885 invoiceNoHTLCs, err := db.LookupInvoice(refNoHtlcs) 886 require.Nil(t, err) 887 888 require.Equal(t, 0, len(invoiceNoHTLCs.Htlcs)) 889 890 // We'll now look up the HTLCs based on the individual setIDs added 891 // above. 892 for i, setID := range []*[32]byte{setID1, setID2, setID3} { 893 refFiltered := InvoiceRefBySetIDFiltered(*setID) 894 invoiceFiltered, err := db.LookupInvoice(refFiltered) 895 require.Nil(t, err) 896 897 // Only a single HTLC should be present. 898 require.Equal(t, 1, len(invoiceFiltered.Htlcs)) 899 900 // The set ID for the HTLC should match the queried set ID. 901 key := CircuitKey{HtlcID: uint64(i + 1)} 902 htlc := invoiceFiltered.Htlcs[key] 903 require.Equal(t, *setID, htlc.AMP.Record.SetID()) 904 905 // The HTLC should show that it's in the accepted state. 906 require.Equal(t, htlc.State, HtlcStateAccepted) 907 } 908 909 // Now that we know the invoices are in the proper state, we'll settle 910 // them on by one in distinct updates. 911 _, err = db.UpdateInvoice( 912 ref, (*SetID)(setID1), 913 getUpdateInvoiceAMPSettle( 914 setID1, preimage, CircuitKey{HtlcID: 1}, 915 ), 916 ) 917 require.Nil(t, err) 918 _, err = db.UpdateInvoice( 919 ref, (*SetID)(setID2), 920 getUpdateInvoiceAMPSettle( 921 setID2, preimage, CircuitKey{HtlcID: 2}, 922 ), 923 ) 924 require.Nil(t, err) 925 _, err = db.UpdateInvoice( 926 ref, (*SetID)(setID3), 927 getUpdateInvoiceAMPSettle( 928 setID3, preimage, CircuitKey{HtlcID: 3}, 929 ), 930 ) 931 require.Nil(t, err) 932 933 // Now that all the invoices have been settled, we'll ensure that the 934 // settle index was updated properly by obtaining all the currently 935 // settled invoices in the time series. We use a value of 1 here to 936 // ensure we get _all_ the invoices back. 937 settledInvoices, err := db.InvoicesSettledSince(1) 938 require.Nil(t, err) 939 940 // To get around the settle index quirk, we'll fetch the very first 941 // invoice in the HTLC filtered mode and append it to the set of 942 // invoices. 943 firstInvoice, err := db.LookupInvoice(InvoiceRefBySetIDFiltered(*setID1)) 944 require.Nil(t, err) 945 settledInvoices = append([]Invoice{firstInvoice}, settledInvoices...) 946 947 // There should be 3 invoices settled, as we created 3 "sub-invoices" 948 // above. 949 numInvoices := 3 950 require.Equal(t, numInvoices, len(settledInvoices)) 951 952 // Each invoice should match the set of invoices we settled above, and 953 // the AMPState should be set accordingly. 954 for i, settledInvoice := range settledInvoices { 955 // Only one HTLC should be projected for this settled index. 956 require.Equal(t, 1, len(settledInvoice.Htlcs)) 957 958 // The invoice should show up as settled, and match the settle 959 // index increment. 960 invSetID := &[32]byte{byte(i + 1)} 961 subInvoiceState, ok := settledInvoice.AMPState[*invSetID] 962 require.True(t, ok) 963 964 require.Equal(t, subInvoiceState.State, HtlcStateSettled) 965 require.Equal(t, int(subInvoiceState.SettleIndex), i+1) 966 967 invoiceKey := CircuitKey{HtlcID: uint64(i + 1)} 968 _, keyFound := subInvoiceState.InvoiceKeys[invoiceKey] 969 require.True(t, keyFound) 970 } 971 972 // If we attempt to look up the invoice by the payment addr, with all 973 // the HTLCs, the main invoice should have 3 HTLCs present. 974 refWithHtlcs := InvoiceRefByAddr(testInvoice.Terms.PaymentAddr) 975 invoiceWithHTLCs, err := db.LookupInvoice(refWithHtlcs) 976 require.Nil(t, err) 977 require.Equal(t, numInvoices, len(invoiceWithHTLCs.Htlcs)) 978 979 // Finally, delete the invoice. If we query again, then nothing should 980 // be found. 981 err = db.DeleteInvoice([]InvoiceDeleteRef{ 982 { 983 PayHash: payHash, 984 PayAddr: &testInvoice.Terms.PaymentAddr, 985 AddIndex: testInvoice.AddIndex, 986 }, 987 }) 988 require.Nil(t, err) 989 } 990 991 // TestScanInvoices tests that ScanInvoices scans through all stored invoices 992 // correctly. 993 func TestScanInvoices(t *testing.T) { 994 t.Parallel() 995 996 db, cleanup, err := MakeTestDB() 997 defer cleanup() 998 if err != nil { 999 t.Fatalf("unable to make test db: %v", err) 1000 } 1001 1002 var invoices map[lntypes.Hash]*Invoice 1003 callCount := 0 1004 resetCount := 0 1005 1006 // reset is used to reset/initialize results and is called once 1007 // upon calling ScanInvoices and when the underlying transaction is 1008 // retried. 1009 reset := func() { 1010 invoices = make(map[lntypes.Hash]*Invoice) 1011 callCount = 0 1012 resetCount++ 1013 1014 } 1015 1016 scanFunc := func(paymentHash lntypes.Hash, invoice *Invoice) error { 1017 invoices[paymentHash] = invoice 1018 callCount++ 1019 1020 return nil 1021 } 1022 1023 // With an empty DB we expect to not scan any invoices. 1024 require.NoError(t, db.ScanInvoices(scanFunc, reset)) 1025 require.Equal(t, 0, len(invoices)) 1026 require.Equal(t, 0, callCount) 1027 require.Equal(t, 1, resetCount) 1028 1029 numInvoices := 5 1030 testInvoices := make(map[lntypes.Hash]*Invoice) 1031 1032 // Now populate the DB and check if we can get all invoices with their 1033 // payment hashes as expected. 1034 for i := 1; i <= numInvoices; i++ { 1035 invoice, err := randInvoice(lnwire.MilliAtom(i)) 1036 require.NoError(t, err) 1037 1038 paymentHash := invoice.Terms.PaymentPreimage.Hash() 1039 testInvoices[paymentHash] = invoice 1040 1041 _, err = db.AddInvoice(invoice, paymentHash) 1042 require.NoError(t, err) 1043 } 1044 1045 resetCount = 0 1046 require.NoError(t, db.ScanInvoices(scanFunc, reset)) 1047 require.Equal(t, numInvoices, callCount) 1048 require.Equal(t, testInvoices, invoices) 1049 require.Equal(t, 1, resetCount) 1050 } 1051 1052 // TestDuplicateSettleInvoice tests that if we add a new invoice and settle it 1053 // twice, then the second time we also receive the invoice that we settled as a 1054 // return argument. 1055 func TestDuplicateSettleInvoice(t *testing.T) { 1056 t.Parallel() 1057 1058 db, cleanUp, err := MakeTestDB(OptionClock(testClock)) 1059 defer cleanUp() 1060 if err != nil { 1061 t.Fatalf("unable to make test db: %v", err) 1062 } 1063 1064 // We'll start out by creating an invoice and writing it to the DB. 1065 amt := lnwire.NewMAtomsFromAtoms(1000) 1066 invoice, err := randInvoice(amt) 1067 if err != nil { 1068 t.Fatalf("unable to create invoice: %v", err) 1069 } 1070 1071 payHash := invoice.Terms.PaymentPreimage.Hash() 1072 1073 if _, err := db.AddInvoice(invoice, payHash); err != nil { 1074 t.Fatalf("unable to add invoice %v", err) 1075 } 1076 1077 // With the invoice in the DB, we'll now attempt to settle the invoice. 1078 ref := InvoiceRefByHash(payHash) 1079 dbInvoice, err := db.UpdateInvoice(ref, nil, getUpdateInvoice(amt)) 1080 if err != nil { 1081 t.Fatalf("unable to settle invoice: %v", err) 1082 } 1083 1084 // We'll update what we expect the settle invoice to be so that our 1085 // comparison below has the correct assumption. 1086 invoice.SettleIndex = 1 1087 invoice.State = ContractSettled 1088 invoice.AmtPaid = amt 1089 invoice.SettleDate = dbInvoice.SettleDate 1090 invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ 1091 {}: { 1092 Amt: amt, 1093 AcceptTime: time.Unix(1, 0), 1094 ResolveTime: time.Unix(1, 0), 1095 State: HtlcStateSettled, 1096 CustomRecords: make(record.CustomSet), 1097 }, 1098 } 1099 1100 // We should get back the exact same invoice that we just inserted. 1101 require.Equal(t, invoice, dbInvoice, "wrong invoice after settle") 1102 1103 // If we try to settle the invoice again, then we should get the very 1104 // same invoice back, but with an error this time. 1105 dbInvoice, err = db.UpdateInvoice(ref, nil, getUpdateInvoice(amt)) 1106 if err != ErrInvoiceAlreadySettled { 1107 t.Fatalf("expected ErrInvoiceAlreadySettled") 1108 } 1109 1110 if dbInvoice == nil { 1111 t.Fatalf("invoice from db is nil after settle!") 1112 } 1113 1114 invoice.SettleDate = dbInvoice.SettleDate 1115 require.Equal(t, invoice, dbInvoice, "wrong invoice after second settle") 1116 } 1117 1118 // TestQueryInvoices ensures that we can properly query the invoice database 1119 // for invoices using different types of queries. 1120 func TestQueryInvoices(t *testing.T) { 1121 t.Parallel() 1122 1123 db, cleanUp, err := MakeTestDB(OptionClock(testClock)) 1124 defer cleanUp() 1125 if err != nil { 1126 t.Fatalf("unable to make test db: %v", err) 1127 } 1128 1129 // To begin the test, we'll add 50 invoices to the database. We'll 1130 // assume that the index of the invoice within the database is the same 1131 // as the amount of the invoice itself. 1132 const numInvoices = 50 1133 var settleIndex uint64 = 1 1134 var invoices []Invoice 1135 var pendingInvoices []Invoice 1136 1137 for i := 1; i <= numInvoices; i++ { 1138 amt := lnwire.MilliAtom(i) 1139 invoice, err := randInvoice(amt) 1140 if err != nil { 1141 t.Fatalf("unable to create invoice: %v", err) 1142 } 1143 1144 paymentHash := invoice.Terms.PaymentPreimage.Hash() 1145 1146 if _, err := db.AddInvoice(invoice, paymentHash); err != nil { 1147 t.Fatalf("unable to add invoice: %v", err) 1148 } 1149 1150 // We'll only settle half of all invoices created. 1151 if i%2 == 0 { 1152 ref := InvoiceRefByHash(paymentHash) 1153 _, err := db.UpdateInvoice(ref, nil, getUpdateInvoice(amt)) 1154 if err != nil { 1155 t.Fatalf("unable to settle invoice: %v", err) 1156 } 1157 1158 // Create the settled invoice for the expectation set. 1159 settleTestInvoice(invoice, settleIndex) 1160 settleIndex++ 1161 } else { 1162 pendingInvoices = append(pendingInvoices, *invoice) 1163 } 1164 1165 invoices = append(invoices, *invoice) 1166 } 1167 1168 // The test will consist of several queries along with their respective 1169 // expected response. Each query response should match its expected one. 1170 testCases := []struct { 1171 query InvoiceQuery 1172 expected []Invoice 1173 }{ 1174 // Fetch all invoices with a single query. 1175 { 1176 query: InvoiceQuery{ 1177 NumMaxInvoices: numInvoices, 1178 }, 1179 expected: invoices, 1180 }, 1181 // Fetch all invoices with a single query, reversed. 1182 { 1183 query: InvoiceQuery{ 1184 Reversed: true, 1185 NumMaxInvoices: numInvoices, 1186 }, 1187 expected: invoices, 1188 }, 1189 // Fetch the first 25 invoices. 1190 { 1191 query: InvoiceQuery{ 1192 NumMaxInvoices: numInvoices / 2, 1193 }, 1194 expected: invoices[:numInvoices/2], 1195 }, 1196 // Fetch the first 10 invoices, but this time iterating 1197 // backwards. 1198 { 1199 query: InvoiceQuery{ 1200 IndexOffset: 11, 1201 Reversed: true, 1202 NumMaxInvoices: numInvoices, 1203 }, 1204 expected: invoices[:10], 1205 }, 1206 // Fetch the last 40 invoices. 1207 { 1208 query: InvoiceQuery{ 1209 IndexOffset: 10, 1210 NumMaxInvoices: numInvoices, 1211 }, 1212 expected: invoices[10:], 1213 }, 1214 // Fetch all but the first invoice. 1215 { 1216 query: InvoiceQuery{ 1217 IndexOffset: 1, 1218 NumMaxInvoices: numInvoices, 1219 }, 1220 expected: invoices[1:], 1221 }, 1222 // Fetch one invoice, reversed, with index offset 3. This 1223 // should give us the second invoice in the array. 1224 { 1225 query: InvoiceQuery{ 1226 IndexOffset: 3, 1227 Reversed: true, 1228 NumMaxInvoices: 1, 1229 }, 1230 expected: invoices[1:2], 1231 }, 1232 // Same as above, at index 2. 1233 { 1234 query: InvoiceQuery{ 1235 IndexOffset: 2, 1236 Reversed: true, 1237 NumMaxInvoices: 1, 1238 }, 1239 expected: invoices[0:1], 1240 }, 1241 // Fetch one invoice, at index 1, reversed. Since invoice#1 is 1242 // the very first, there won't be any left in a reverse search, 1243 // so we expect no invoices to be returned. 1244 { 1245 query: InvoiceQuery{ 1246 IndexOffset: 1, 1247 Reversed: true, 1248 NumMaxInvoices: 1, 1249 }, 1250 expected: nil, 1251 }, 1252 // Same as above, but don't restrict the number of invoices to 1253 // 1. 1254 { 1255 query: InvoiceQuery{ 1256 IndexOffset: 1, 1257 Reversed: true, 1258 NumMaxInvoices: numInvoices, 1259 }, 1260 expected: nil, 1261 }, 1262 // Fetch one invoice, reversed, with no offset set. We expect 1263 // the last invoice in the response. 1264 { 1265 query: InvoiceQuery{ 1266 Reversed: true, 1267 NumMaxInvoices: 1, 1268 }, 1269 expected: invoices[numInvoices-1:], 1270 }, 1271 // Fetch one invoice, reversed, the offset set at numInvoices+1. 1272 // We expect this to return the last invoice. 1273 { 1274 query: InvoiceQuery{ 1275 IndexOffset: numInvoices + 1, 1276 Reversed: true, 1277 NumMaxInvoices: 1, 1278 }, 1279 expected: invoices[numInvoices-1:], 1280 }, 1281 // Same as above, at offset numInvoices. 1282 { 1283 query: InvoiceQuery{ 1284 IndexOffset: numInvoices, 1285 Reversed: true, 1286 NumMaxInvoices: 1, 1287 }, 1288 expected: invoices[numInvoices-2 : numInvoices-1], 1289 }, 1290 // Fetch one invoice, at no offset (same as offset 0). We 1291 // expect the first invoice only in the response. 1292 { 1293 query: InvoiceQuery{ 1294 NumMaxInvoices: 1, 1295 }, 1296 expected: invoices[:1], 1297 }, 1298 // Same as above, at offset 1. 1299 { 1300 query: InvoiceQuery{ 1301 IndexOffset: 1, 1302 NumMaxInvoices: 1, 1303 }, 1304 expected: invoices[1:2], 1305 }, 1306 // Same as above, at offset 2. 1307 { 1308 query: InvoiceQuery{ 1309 IndexOffset: 2, 1310 NumMaxInvoices: 1, 1311 }, 1312 expected: invoices[2:3], 1313 }, 1314 // Same as above, at offset numInvoices-1. Expect the last 1315 // invoice to be returned. 1316 { 1317 query: InvoiceQuery{ 1318 IndexOffset: numInvoices - 1, 1319 NumMaxInvoices: 1, 1320 }, 1321 expected: invoices[numInvoices-1:], 1322 }, 1323 // Same as above, at offset numInvoices. No invoices should be 1324 // returned, as there are no invoices after this offset. 1325 { 1326 query: InvoiceQuery{ 1327 IndexOffset: numInvoices, 1328 NumMaxInvoices: 1, 1329 }, 1330 expected: nil, 1331 }, 1332 // Fetch all pending invoices with a single query. 1333 { 1334 query: InvoiceQuery{ 1335 PendingOnly: true, 1336 NumMaxInvoices: numInvoices, 1337 }, 1338 expected: pendingInvoices, 1339 }, 1340 // Fetch the first 12 pending invoices. 1341 { 1342 query: InvoiceQuery{ 1343 PendingOnly: true, 1344 NumMaxInvoices: numInvoices / 4, 1345 }, 1346 expected: pendingInvoices[:len(pendingInvoices)/2], 1347 }, 1348 // Fetch the first 5 pending invoices, but this time iterating 1349 // backwards. 1350 { 1351 query: InvoiceQuery{ 1352 IndexOffset: 10, 1353 PendingOnly: true, 1354 Reversed: true, 1355 NumMaxInvoices: numInvoices, 1356 }, 1357 // Since we seek to the invoice with index 10 and 1358 // iterate backwards, there should only be 5 pending 1359 // invoices before it as every other invoice within the 1360 // index is settled. 1361 expected: pendingInvoices[:5], 1362 }, 1363 // Fetch the last 15 invoices. 1364 { 1365 query: InvoiceQuery{ 1366 IndexOffset: 20, 1367 PendingOnly: true, 1368 NumMaxInvoices: numInvoices, 1369 }, 1370 // Since we seek to the invoice with index 20, there are 1371 // 30 invoices left. From these 30, only 15 of them are 1372 // still pending. 1373 expected: pendingInvoices[len(pendingInvoices)-15:], 1374 }, 1375 // Fetch all invoices paginating backwards, with an index offset 1376 // that is beyond our last offset. We expect all invoices to be 1377 // returned. 1378 { 1379 query: InvoiceQuery{ 1380 IndexOffset: numInvoices * 2, 1381 PendingOnly: false, 1382 Reversed: true, 1383 NumMaxInvoices: numInvoices, 1384 }, 1385 expected: invoices, 1386 }, 1387 } 1388 1389 for i, testCase := range testCases { 1390 response, err := db.QueryInvoices(testCase.query) 1391 if err != nil { 1392 t.Fatalf("unable to query invoice database: %v", err) 1393 } 1394 1395 require.Equal(t, len(testCase.expected), len(response.Invoices)) 1396 1397 for j, expected := range testCase.expected { 1398 require.Equal(t, 1399 expected, response.Invoices[j], 1400 fmt.Sprintf("test: #%v, item: #%v", i, j), 1401 ) 1402 } 1403 } 1404 } 1405 1406 // getUpdateInvoice returns an invoice update callback that, when called, 1407 // settles the invoice with the given amount. 1408 func getUpdateInvoice(amt lnwire.MilliAtom) InvoiceUpdateCallback { 1409 return func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 1410 if invoice.State == ContractSettled { 1411 return nil, ErrInvoiceAlreadySettled 1412 } 1413 1414 noRecords := make(record.CustomSet) 1415 1416 update := &InvoiceUpdateDesc{ 1417 State: &InvoiceStateUpdateDesc{ 1418 Preimage: invoice.Terms.PaymentPreimage, 1419 NewState: ContractSettled, 1420 }, 1421 AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ 1422 {}: { 1423 Amt: amt, 1424 CustomRecords: noRecords, 1425 }, 1426 }, 1427 } 1428 1429 return update, nil 1430 } 1431 } 1432 1433 // TestCustomRecords tests that custom records are properly recorded in the 1434 // invoice database. 1435 func TestCustomRecords(t *testing.T) { 1436 t.Parallel() 1437 1438 db, cleanUp, err := MakeTestDB() 1439 defer cleanUp() 1440 if err != nil { 1441 t.Fatalf("unable to make test db: %v", err) 1442 } 1443 1444 preimage := lntypes.Preimage{1} 1445 paymentHash := preimage.Hash() 1446 1447 testInvoice := &Invoice{ 1448 Htlcs: map[CircuitKey]*InvoiceHTLC{}, 1449 Terms: ContractTerm{ 1450 Value: lnwire.NewMAtomsFromAtoms(10000), 1451 Features: emptyFeatures, 1452 PaymentPreimage: &preimage, 1453 }, 1454 } 1455 1456 if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil { 1457 t.Fatalf("unable to add invoice: %v", err) 1458 } 1459 1460 // Accept an htlc with custom records on this invoice. 1461 key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4} 1462 1463 records := record.CustomSet{ 1464 100000: []byte{}, 1465 100001: []byte{1, 2}, 1466 } 1467 1468 ref := InvoiceRefByHash(paymentHash) 1469 _, err = db.UpdateInvoice(ref, nil, 1470 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 1471 return &InvoiceUpdateDesc{ 1472 AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ 1473 key: { 1474 Amt: 500, 1475 CustomRecords: records, 1476 }, 1477 }, 1478 }, nil 1479 }, 1480 ) 1481 if err != nil { 1482 t.Fatalf("unable to add invoice htlc: %v", err) 1483 } 1484 1485 // Retrieve the invoice from that database and verify that the custom 1486 // records are present. 1487 dbInvoice, err := db.LookupInvoice(ref) 1488 if err != nil { 1489 t.Fatalf("unable to lookup invoice: %v", err) 1490 } 1491 1492 if len(dbInvoice.Htlcs) != 1 { 1493 t.Fatalf("expected the htlc to be added") 1494 } 1495 1496 require.Equal(t, 1497 records, dbInvoice.Htlcs[key].CustomRecords, 1498 "invalid custom records", 1499 ) 1500 } 1501 1502 // TestInvoiceHtlcAMPFields asserts that the set id and preimage fields are 1503 // properly recorded when updating an invoice. 1504 func TestInvoiceHtlcAMPFields(t *testing.T) { 1505 t.Run("amp", func(t *testing.T) { 1506 testInvoiceHtlcAMPFields(t, true) 1507 }) 1508 t.Run("no amp", func(t *testing.T) { 1509 testInvoiceHtlcAMPFields(t, false) 1510 }) 1511 } 1512 1513 func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) { 1514 db, cleanUp, err := MakeTestDB() 1515 defer cleanUp() 1516 require.Nil(t, err) 1517 1518 testInvoice, err := randInvoice(1000) 1519 require.Nil(t, err) 1520 1521 if isAMP { 1522 testInvoice.Terms.Features = ampFeatures 1523 } 1524 1525 payHash := testInvoice.Terms.PaymentPreimage.Hash() 1526 _, err = db.AddInvoice(testInvoice, payHash) 1527 require.Nil(t, err) 1528 1529 // Accept an htlc with custom records on this invoice. 1530 key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4} 1531 records := make(map[uint64][]byte) 1532 1533 var ampData *InvoiceHtlcAMPData 1534 if isAMP { 1535 amp := record.NewAMP([32]byte{1}, [32]byte{2}, 3) 1536 preimage := &lntypes.Preimage{4} 1537 1538 ampData = &InvoiceHtlcAMPData{ 1539 Record: *amp, 1540 Hash: preimage.Hash(), 1541 Preimage: preimage, 1542 } 1543 } 1544 1545 ref := InvoiceRefByHash(payHash) 1546 _, err = db.UpdateInvoice(ref, nil, 1547 func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 1548 return &InvoiceUpdateDesc{ 1549 AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ 1550 key: { 1551 Amt: 500, 1552 AMP: ampData, 1553 CustomRecords: records, 1554 }, 1555 }, 1556 }, nil 1557 }, 1558 ) 1559 require.Nil(t, err) 1560 1561 // Retrieve the invoice from that database and verify that the AMP 1562 // fields are as expected. 1563 dbInvoice, err := db.LookupInvoice(ref) 1564 require.Nil(t, err) 1565 1566 require.Equal(t, 1, len(dbInvoice.Htlcs)) 1567 require.Equal(t, ampData, dbInvoice.Htlcs[key].AMP) 1568 } 1569 1570 // TestInvoiceRef asserts that the proper identifiers are returned from an 1571 // InvoiceRef depending on the constructor used. 1572 func TestInvoiceRef(t *testing.T) { 1573 payHash := lntypes.Hash{0x01} 1574 payAddr := [32]byte{0x02} 1575 setID := [32]byte{0x03} 1576 1577 // An InvoiceRef by hash should return the provided hash and a nil 1578 // payment addr. 1579 refByHash := InvoiceRefByHash(payHash) 1580 require.Equal(t, &payHash, refByHash.PayHash()) 1581 require.Equal(t, (*[32]byte)(nil), refByHash.PayAddr()) 1582 require.Equal(t, (*[32]byte)(nil), refByHash.SetID()) 1583 1584 // An InvoiceRef by hash and addr should return the payment hash and 1585 // payment addr passed to the constructor. 1586 refByHashAndAddr := InvoiceRefByHashAndAddr(payHash, payAddr) 1587 require.Equal(t, &payHash, refByHashAndAddr.PayHash()) 1588 require.Equal(t, &payAddr, refByHashAndAddr.PayAddr()) 1589 require.Equal(t, (*[32]byte)(nil), refByHashAndAddr.SetID()) 1590 1591 // An InvoiceRef by set id should return an empty pay hash, a nil pay 1592 // addr, and a reference to the given set id. 1593 refBySetID := InvoiceRefBySetID(setID) 1594 require.Equal(t, (*lntypes.Hash)(nil), refBySetID.PayHash()) 1595 require.Equal(t, (*[32]byte)(nil), refBySetID.PayAddr()) 1596 require.Equal(t, &setID, refBySetID.SetID()) 1597 1598 // An InvoiceRef by pay addr should only return a pay addr, but nil for 1599 // pay hash and set id. 1600 refByAddr := InvoiceRefByAddr(payAddr) 1601 require.Equal(t, (*lntypes.Hash)(nil), refByAddr.PayHash()) 1602 require.Equal(t, &payAddr, refByAddr.PayAddr()) 1603 require.Equal(t, (*[32]byte)(nil), refByAddr.SetID()) 1604 } 1605 1606 // TestHTLCSet asserts that HTLCSet returns the proper set of accepted HTLCs 1607 // that can be considered for settlement. It asserts that MPP and AMP HTLCs do 1608 // not comingle, and also that HTLCs with disjoint set ids appear in different 1609 // sets. 1610 func TestHTLCSet(t *testing.T) { 1611 inv := &Invoice{ 1612 Htlcs: make(map[CircuitKey]*InvoiceHTLC), 1613 } 1614 1615 // Construct two distinct set id's, in this test we'll also track the 1616 // nil set id as a third group. 1617 setID1 := &[32]byte{1} 1618 setID2 := &[32]byte{2} 1619 1620 // Create the expected htlc sets for each group, these will be updated 1621 // as the invoice is modified. 1622 expSetNil := make(map[CircuitKey]*InvoiceHTLC) 1623 expSet1 := make(map[CircuitKey]*InvoiceHTLC) 1624 expSet2 := make(map[CircuitKey]*InvoiceHTLC) 1625 1626 checkHTLCSets := func() { 1627 require.Equal(t, expSetNil, inv.HTLCSet(nil, HtlcStateAccepted)) 1628 require.Equal(t, expSet1, inv.HTLCSet(setID1, HtlcStateAccepted)) 1629 require.Equal(t, expSet2, inv.HTLCSet(setID2, HtlcStateAccepted)) 1630 } 1631 1632 // All HTLC sets should be empty initially. 1633 checkHTLCSets() 1634 1635 // Add the following sequence of HTLCs to the invoice, sanity checking 1636 // all three HTLC sets after each transition. This sequence asserts: 1637 // - both nil and non-nil set ids can have multiple htlcs. 1638 // - there may be distinct htlc sets with non-nil set ids. 1639 // - only accepted htlcs are returned as part of the set. 1640 htlcs := []struct { 1641 setID *[32]byte 1642 state HtlcState 1643 }{ 1644 {nil, HtlcStateAccepted}, 1645 {nil, HtlcStateAccepted}, 1646 {setID1, HtlcStateAccepted}, 1647 {setID1, HtlcStateAccepted}, 1648 {setID2, HtlcStateAccepted}, 1649 {setID2, HtlcStateAccepted}, 1650 {nil, HtlcStateCanceled}, 1651 {setID1, HtlcStateCanceled}, 1652 {setID2, HtlcStateCanceled}, 1653 {nil, HtlcStateSettled}, 1654 {setID1, HtlcStateSettled}, 1655 {setID2, HtlcStateSettled}, 1656 } 1657 1658 for i, h := range htlcs { 1659 var ampData *InvoiceHtlcAMPData 1660 if h.setID != nil { 1661 ampData = &InvoiceHtlcAMPData{ 1662 Record: *record.NewAMP([32]byte{0}, *h.setID, 0), 1663 } 1664 1665 } 1666 1667 // Add the HTLC to the invoice's set of HTLCs. 1668 key := CircuitKey{HtlcID: uint64(i)} 1669 htlc := &InvoiceHTLC{ 1670 AMP: ampData, 1671 State: h.state, 1672 } 1673 inv.Htlcs[key] = htlc 1674 1675 // Update our expected htlc set if the htlc is accepted, 1676 // otherwise it shouldn't be reflected. 1677 if h.state == HtlcStateAccepted { 1678 switch h.setID { 1679 case nil: 1680 expSetNil[key] = htlc 1681 case setID1: 1682 expSet1[key] = htlc 1683 case setID2: 1684 expSet2[key] = htlc 1685 default: 1686 t.Fatalf("unexpected set id") 1687 } 1688 } 1689 1690 checkHTLCSets() 1691 } 1692 } 1693 1694 // TestAddInvoiceWithHTLCs asserts that you can't insert an invoice that already 1695 // has HTLCs. 1696 func TestAddInvoiceWithHTLCs(t *testing.T) { 1697 db, cleanUp, err := MakeTestDB() 1698 defer cleanUp() 1699 require.Nil(t, err) 1700 1701 testInvoice, err := randInvoice(1000) 1702 require.Nil(t, err) 1703 1704 key := CircuitKey{HtlcID: 1} 1705 testInvoice.Htlcs[key] = &InvoiceHTLC{} 1706 1707 payHash := testInvoice.Terms.PaymentPreimage.Hash() 1708 _, err = db.AddInvoice(testInvoice, payHash) 1709 require.Equal(t, ErrInvoiceHasHtlcs, err) 1710 } 1711 1712 // TestSetIDIndex asserts that the set id index properly adds new invoices as we 1713 // accept HTLCs, that they can be queried by their set id after accepting, and 1714 // that invoices with duplicate set ids are disallowed. 1715 func TestSetIDIndex(t *testing.T) { 1716 testClock := clock.NewTestClock(testNow) 1717 db, cleanUp, err := MakeTestDB(OptionClock(testClock)) 1718 defer cleanUp() 1719 require.Nil(t, err) 1720 1721 // We'll start out by creating an invoice and writing it to the DB. 1722 amt := lnwire.NewMAtomsFromAtoms(1000) 1723 invoice, err := randInvoice(amt) 1724 require.Nil(t, err) 1725 1726 // Set AMP-specific features so that we can settle with HTLC-level 1727 // preimages. 1728 invoice.Terms.Features = ampFeatures 1729 1730 preimage := *invoice.Terms.PaymentPreimage 1731 payHash := preimage.Hash() 1732 _, err = db.AddInvoice(invoice, payHash) 1733 require.Nil(t, err) 1734 1735 setID := &[32]byte{1} 1736 1737 // Update the invoice with an accepted HTLC that also accepts the 1738 // invoice. 1739 ref := InvoiceRefByHashAndAddr(payHash, invoice.Terms.PaymentAddr) 1740 dbInvoice, err := db.UpdateInvoice( 1741 ref, (*SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true), 1742 ) 1743 require.Nil(t, err) 1744 1745 // We'll update what we expect the accepted invoice to be so that our 1746 // comparison below has the correct assumption. 1747 invoice.State = ContractOpen 1748 invoice.AmtPaid = amt 1749 invoice.SettleDate = dbInvoice.SettleDate 1750 invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ 1751 {HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, payHash, &preimage), 1752 } 1753 invoice.AMPState = map[SetID]InvoiceStateAMP{} 1754 invoice.AMPState[*setID] = InvoiceStateAMP{ 1755 State: HtlcStateAccepted, 1756 AmtPaid: amt, 1757 InvoiceKeys: map[CircuitKey]struct{}{ 1758 {HtlcID: 0}: {}, 1759 }, 1760 } 1761 1762 // We should get back the exact same invoice that we just inserted. 1763 require.Equal(t, invoice, dbInvoice) 1764 1765 // Now lookup the invoice by set id and see that we get the same one. 1766 refBySetID := InvoiceRefBySetID(*setID) 1767 dbInvoiceBySetID, err := db.LookupInvoice(refBySetID) 1768 require.Nil(t, err) 1769 require.Equal(t, invoice, &dbInvoiceBySetID) 1770 1771 // Trying to accept an HTLC to a different invoice, but using the same 1772 // set id should fail. 1773 invoice2, err := randInvoice(amt) 1774 require.Nil(t, err) 1775 1776 // Set AMP-specific features so that we can settle with HTLC-level 1777 // preimages. 1778 invoice2.Terms.Features = ampFeatures 1779 1780 payHash2 := invoice2.Terms.PaymentPreimage.Hash() 1781 _, err = db.AddInvoice(invoice2, payHash2) 1782 require.Nil(t, err) 1783 1784 ref2 := InvoiceRefByHashAndAddr(payHash2, invoice2.Terms.PaymentAddr) 1785 _, err = db.UpdateInvoice( 1786 ref2, (*SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true), 1787 ) 1788 require.Equal(t, ErrDuplicateSetID{setID: *setID}, err) 1789 1790 // Now, begin constructing a second htlc set under a different set id. 1791 // This set will contain two distinct HTLCs. 1792 setID2 := &[32]byte{2} 1793 1794 _, err = db.UpdateInvoice( 1795 ref, (*SetID)(setID2), updateAcceptAMPHtlc(1, amt, setID2, false), 1796 ) 1797 require.Nil(t, err) 1798 dbInvoice, err = db.UpdateInvoice( 1799 ref, (*SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, false), 1800 ) 1801 require.Nil(t, err) 1802 1803 // We'll update what we expect the settle invoice to be so that our 1804 // comparison below has the correct assumption. 1805 invoice.State = ContractOpen 1806 invoice.AmtPaid += 2 * amt 1807 invoice.SettleDate = dbInvoice.SettleDate 1808 invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ 1809 {HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, payHash, &preimage), 1810 {HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, payHash, nil), 1811 {HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, payHash, nil), 1812 } 1813 invoice.AMPState[*setID] = InvoiceStateAMP{ 1814 State: HtlcStateAccepted, 1815 AmtPaid: amt, 1816 InvoiceKeys: map[CircuitKey]struct{}{ 1817 {HtlcID: 0}: {}, 1818 }, 1819 } 1820 invoice.AMPState[*setID2] = InvoiceStateAMP{ 1821 State: HtlcStateAccepted, 1822 AmtPaid: amt * 2, 1823 InvoiceKeys: map[CircuitKey]struct{}{ 1824 {HtlcID: 1}: {}, 1825 {HtlcID: 2}: {}, 1826 }, 1827 } 1828 1829 // Since UpdateInvoice will only return the sub-set of updated HTLcs, 1830 // we'll query again to ensure we get the full set of HTLCs returned. 1831 freshInvoice, err := db.LookupInvoice(ref) 1832 require.Nil(t, err) 1833 dbInvoice = &freshInvoice 1834 1835 // We should get back the exact same invoice that we just inserted. 1836 require.Equal(t, invoice, dbInvoice) 1837 1838 // Now lookup the invoice by second set id and see that we get the same 1839 // index, including the htlcs under the first set id. 1840 refBySetID = InvoiceRefBySetID(*setID2) 1841 dbInvoiceBySetID, err = db.LookupInvoice(refBySetID) 1842 require.Nil(t, err) 1843 require.Equal(t, invoice, &dbInvoiceBySetID) 1844 1845 // Now attempt to settle a non-existent HTLC set, this set ID is the 1846 // zero setID so it isn't used for anything internally. 1847 _, err = db.UpdateInvoice( 1848 ref, nil, 1849 getUpdateInvoiceAMPSettle(&[32]byte{}, [32]byte{}, CircuitKey{HtlcID: 99}), 1850 ) 1851 require.Equal(t, ErrEmptyHTLCSet, err) 1852 1853 // Now settle the first htlc set. The existing HTLCs should remain in 1854 // the accepted state and shouldn't be canceled, since we permit an 1855 // invoice to be settled multiple times. 1856 _, err = db.UpdateInvoice( 1857 ref, (*SetID)(setID), 1858 getUpdateInvoiceAMPSettle(setID, preimage, CircuitKey{HtlcID: 0}), 1859 ) 1860 require.Nil(t, err) 1861 1862 freshInvoice, err = db.LookupInvoice(ref) 1863 require.Nil(t, err) 1864 dbInvoice = &freshInvoice 1865 1866 invoice.State = ContractOpen 1867 1868 // The amount paid should reflect that we have 3 present HTLCs, each 1869 // with an amount of the original invoice. 1870 invoice.AmtPaid = amt * 3 1871 1872 ampState := invoice.AMPState[*setID] 1873 ampState.State = HtlcStateSettled 1874 ampState.SettleDate = testNow 1875 ampState.SettleIndex = 1 1876 1877 invoice.AMPState[*setID] = ampState 1878 1879 invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateSettled 1880 invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0) 1881 1882 require.Equal(t, invoice, dbInvoice) 1883 1884 // If we try to settle the same set ID again, then we should get an 1885 // error, as it's already been settled. 1886 _, err = db.UpdateInvoice( 1887 ref, (*SetID)(setID), 1888 getUpdateInvoiceAMPSettle(setID, preimage, CircuitKey{HtlcID: 0}), 1889 ) 1890 require.Equal(t, ErrEmptyHTLCSet, err) 1891 1892 // Next, let's attempt to settle the other active set ID for this 1893 // invoice. This will allow us to exercise the case where we go to 1894 // settle an invoice with a new setID after one has already been fully 1895 // settled. 1896 _, err = db.UpdateInvoice( 1897 ref, (*SetID)(setID2), 1898 getUpdateInvoiceAMPSettle( 1899 setID2, preimage, CircuitKey{HtlcID: 1}, CircuitKey{HtlcID: 2}, 1900 ), 1901 ) 1902 require.Nil(t, err) 1903 1904 freshInvoice, err = db.LookupInvoice(ref) 1905 require.Nil(t, err) 1906 dbInvoice = &freshInvoice 1907 1908 // Now the rest of the HTLCs should show as fully settled. 1909 ampState = invoice.AMPState[*setID2] 1910 ampState.State = HtlcStateSettled 1911 ampState.SettleDate = testNow 1912 ampState.SettleIndex = 2 1913 1914 invoice.AMPState[*setID2] = ampState 1915 1916 invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateSettled 1917 invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0) 1918 invoice.Htlcs[CircuitKey{HtlcID: 1}].AMP.Preimage = &preimage 1919 1920 invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateSettled 1921 invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0) 1922 invoice.Htlcs[CircuitKey{HtlcID: 2}].AMP.Preimage = &preimage 1923 1924 require.Equal(t, invoice, dbInvoice) 1925 1926 // Lastly, querying for an unknown set id should fail. 1927 refUnknownSetID := InvoiceRefBySetID([32]byte{}) 1928 _, err = db.LookupInvoice(refUnknownSetID) 1929 require.Equal(t, ErrInvoiceNotFound, err) 1930 } 1931 1932 func makeAMPInvoiceHTLC(amt lnwire.MilliAtom, setID [32]byte, 1933 hash lntypes.Hash, preimage *lntypes.Preimage) *InvoiceHTLC { 1934 1935 return &InvoiceHTLC{ 1936 Amt: amt, 1937 AcceptTime: testNow, 1938 ResolveTime: time.Time{}, 1939 State: HtlcStateAccepted, 1940 CustomRecords: make(record.CustomSet), 1941 AMP: &InvoiceHtlcAMPData{ 1942 Record: *record.NewAMP([32]byte{}, setID, 0), 1943 Hash: hash, 1944 Preimage: preimage, 1945 }, 1946 } 1947 } 1948 1949 // updateAcceptAMPHtlc returns an invoice update callback that, when called, 1950 // settles the invoice with the given amount. 1951 func updateAcceptAMPHtlc(id uint64, amt lnwire.MilliAtom, 1952 setID *[32]byte, accept bool) InvoiceUpdateCallback { 1953 1954 return func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 1955 if invoice.State == ContractSettled { 1956 return nil, ErrInvoiceAlreadySettled 1957 } 1958 1959 noRecords := make(record.CustomSet) 1960 1961 var ( 1962 state *InvoiceStateUpdateDesc 1963 preimage *lntypes.Preimage 1964 ) 1965 if accept { 1966 state = &InvoiceStateUpdateDesc{ 1967 NewState: ContractAccepted, 1968 SetID: setID, 1969 } 1970 pre := *invoice.Terms.PaymentPreimage 1971 preimage = &pre 1972 } 1973 1974 ampData := &InvoiceHtlcAMPData{ 1975 Record: *record.NewAMP([32]byte{}, *setID, 0), 1976 Hash: invoice.Terms.PaymentPreimage.Hash(), 1977 Preimage: preimage, 1978 } 1979 update := &InvoiceUpdateDesc{ 1980 State: state, 1981 AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ 1982 {HtlcID: id}: { 1983 Amt: amt, 1984 CustomRecords: noRecords, 1985 AMP: ampData, 1986 }, 1987 }, 1988 } 1989 1990 return update, nil 1991 } 1992 } 1993 1994 func getUpdateInvoiceAMPSettle(setID *[32]byte, 1995 preimage [32]byte, circuitKeys ...CircuitKey) InvoiceUpdateCallback { 1996 1997 return func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 1998 if invoice.State == ContractSettled { 1999 return nil, ErrInvoiceAlreadySettled 2000 } 2001 2002 preImageSet := make(map[CircuitKey]lntypes.Preimage) 2003 for _, key := range circuitKeys { 2004 preImageSet[key] = preimage 2005 } 2006 2007 update := &InvoiceUpdateDesc{ 2008 State: &InvoiceStateUpdateDesc{ 2009 Preimage: nil, 2010 NewState: ContractSettled, 2011 SetID: setID, 2012 HTLCPreimages: preImageSet, 2013 }, 2014 } 2015 2016 return update, nil 2017 } 2018 } 2019 2020 // TestUnexpectedInvoicePreimage asserts that legacy or MPP invoices cannot be 2021 // settled when referenced by payment address only. Since regular or MPP 2022 // payments do not store the payment hash explicitly (it is stored in the 2023 // index), this enforces that they can only be updated using a InvoiceRefByHash 2024 // or InvoiceRefByHashOrAddr. 2025 func TestUnexpectedInvoicePreimage(t *testing.T) { 2026 t.Parallel() 2027 2028 db, cleanup, err := MakeTestDB() 2029 defer cleanup() 2030 require.NoError(t, err, "unable to make test db") 2031 2032 invoice, err := randInvoice(lnwire.MilliAtom(100)) 2033 require.NoError(t, err) 2034 2035 // Add a random invoice indexed by payment hash and payment addr. 2036 paymentHash := invoice.Terms.PaymentPreimage.Hash() 2037 _, err = db.AddInvoice(invoice, paymentHash) 2038 require.NoError(t, err) 2039 2040 // Attempt to update the invoice by pay addr only. This will fail since, 2041 // in order to settle an MPP invoice, the InvoiceRef must present a 2042 // payment hash against which to validate the preimage. 2043 _, err = db.UpdateInvoice( 2044 InvoiceRefByAddr(invoice.Terms.PaymentAddr), nil, 2045 getUpdateInvoice(invoice.Terms.Value), 2046 ) 2047 2048 //Assert that we get ErrUnexpectedInvoicePreimage. 2049 require.Error(t, ErrUnexpectedInvoicePreimage, err) 2050 } 2051 2052 type updateHTLCPreimageTestCase struct { 2053 name string 2054 settleSamePreimage bool 2055 expError error 2056 } 2057 2058 // TestUpdateHTLCPreimages asserts various properties of setting HTLC-level 2059 // preimages on invoice state transitions. 2060 func TestUpdateHTLCPreimages(t *testing.T) { 2061 t.Parallel() 2062 2063 tests := []updateHTLCPreimageTestCase{ 2064 { 2065 name: "same preimage on settle", 2066 settleSamePreimage: true, 2067 expError: nil, 2068 }, 2069 { 2070 name: "diff preimage on settle", 2071 settleSamePreimage: false, 2072 expError: ErrHTLCPreimageAlreadyExists, 2073 }, 2074 } 2075 2076 for _, test := range tests { 2077 test := test 2078 t.Run(test.name, func(t *testing.T) { 2079 testUpdateHTLCPreimages(t, test) 2080 }) 2081 } 2082 } 2083 2084 func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) { 2085 db, cleanup, err := MakeTestDB() 2086 defer cleanup() 2087 require.NoError(t, err, "unable to make test db") 2088 2089 // We'll start out by creating an invoice and writing it to the DB. 2090 amt := lnwire.NewMAtomsFromAtoms(1000) 2091 invoice, err := randInvoice(amt) 2092 require.Nil(t, err) 2093 2094 preimage := *invoice.Terms.PaymentPreimage 2095 payHash := preimage.Hash() 2096 2097 // Set AMP-specific features so that we can settle with HTLC-level 2098 // preimages. 2099 invoice.Terms.Features = ampFeatures 2100 2101 _, err = db.AddInvoice(invoice, payHash) 2102 require.Nil(t, err) 2103 2104 setID := &[32]byte{1} 2105 2106 // Update the invoice with an accepted HTLC that also accepts the 2107 // invoice. 2108 ref := InvoiceRefByAddr(invoice.Terms.PaymentAddr) 2109 dbInvoice, err := db.UpdateInvoice( 2110 ref, (*SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true), 2111 ) 2112 require.Nil(t, err) 2113 2114 htlcPreimages := make(map[CircuitKey]lntypes.Preimage) 2115 for key := range dbInvoice.Htlcs { 2116 // Set the either the same preimage used to accept above, or a 2117 // blank preimage depending on the test case. 2118 var pre lntypes.Preimage 2119 if test.settleSamePreimage { 2120 pre = preimage 2121 } 2122 htlcPreimages[key] = pre 2123 } 2124 2125 updateInvoice := func(invoice *Invoice) (*InvoiceUpdateDesc, error) { 2126 update := &InvoiceUpdateDesc{ 2127 State: &InvoiceStateUpdateDesc{ 2128 Preimage: nil, 2129 NewState: ContractSettled, 2130 HTLCPreimages: htlcPreimages, 2131 SetID: setID, 2132 }, 2133 } 2134 2135 return update, nil 2136 } 2137 2138 // Now settle the HTLC set and assert the resulting error. 2139 _, err = db.UpdateInvoice(ref, (*SetID)(setID), updateInvoice) 2140 require.Equal(t, test.expError, err) 2141 } 2142 2143 type updateHTLCTest struct { 2144 name string 2145 input InvoiceHTLC 2146 invState ContractState 2147 setID *[32]byte 2148 output InvoiceHTLC 2149 expErr error 2150 } 2151 2152 // TestUpdateHTLC asserts the behavior of the updateHTLC method in various 2153 // scenarios for MPP and AMP. 2154 func TestUpdateHTLC(t *testing.T) { 2155 t.Parallel() 2156 2157 setID := [32]byte{0x01} 2158 ampRecord := record.NewAMP([32]byte{0x02}, setID, 3) 2159 preimage := lntypes.Preimage{0x04} 2160 hash := preimage.Hash() 2161 2162 diffSetID := [32]byte{0x05} 2163 fakePreimage := lntypes.Preimage{0x06} 2164 testAlreadyNow := time.Now() 2165 2166 tests := []updateHTLCTest{ 2167 { 2168 name: "MPP accept", 2169 input: InvoiceHTLC{ 2170 Amt: 5000, 2171 MppTotalAmt: 5000, 2172 AcceptHeight: 100, 2173 AcceptTime: testNow, 2174 ResolveTime: time.Time{}, 2175 Expiry: 40, 2176 State: HtlcStateAccepted, 2177 CustomRecords: make(record.CustomSet), 2178 AMP: nil, 2179 }, 2180 invState: ContractAccepted, 2181 setID: nil, 2182 output: InvoiceHTLC{ 2183 Amt: 5000, 2184 MppTotalAmt: 5000, 2185 AcceptHeight: 100, 2186 AcceptTime: testNow, 2187 ResolveTime: time.Time{}, 2188 Expiry: 40, 2189 State: HtlcStateAccepted, 2190 CustomRecords: make(record.CustomSet), 2191 AMP: nil, 2192 }, 2193 expErr: nil, 2194 }, 2195 { 2196 name: "MPP settle", 2197 input: InvoiceHTLC{ 2198 Amt: 5000, 2199 MppTotalAmt: 5000, 2200 AcceptHeight: 100, 2201 AcceptTime: testNow, 2202 ResolveTime: time.Time{}, 2203 Expiry: 40, 2204 State: HtlcStateAccepted, 2205 CustomRecords: make(record.CustomSet), 2206 AMP: nil, 2207 }, 2208 invState: ContractSettled, 2209 setID: nil, 2210 output: InvoiceHTLC{ 2211 Amt: 5000, 2212 MppTotalAmt: 5000, 2213 AcceptHeight: 100, 2214 AcceptTime: testNow, 2215 ResolveTime: testNow, 2216 Expiry: 40, 2217 State: HtlcStateSettled, 2218 CustomRecords: make(record.CustomSet), 2219 AMP: nil, 2220 }, 2221 expErr: nil, 2222 }, 2223 { 2224 name: "MPP cancel", 2225 input: InvoiceHTLC{ 2226 Amt: 5000, 2227 MppTotalAmt: 5000, 2228 AcceptHeight: 100, 2229 AcceptTime: testNow, 2230 ResolveTime: time.Time{}, 2231 Expiry: 40, 2232 State: HtlcStateAccepted, 2233 CustomRecords: make(record.CustomSet), 2234 AMP: nil, 2235 }, 2236 invState: ContractCanceled, 2237 setID: nil, 2238 output: InvoiceHTLC{ 2239 Amt: 5000, 2240 MppTotalAmt: 5000, 2241 AcceptHeight: 100, 2242 AcceptTime: testNow, 2243 ResolveTime: testNow, 2244 Expiry: 40, 2245 State: HtlcStateCanceled, 2246 CustomRecords: make(record.CustomSet), 2247 AMP: nil, 2248 }, 2249 expErr: nil, 2250 }, 2251 { 2252 name: "AMP accept missing preimage", 2253 input: InvoiceHTLC{ 2254 Amt: 5000, 2255 MppTotalAmt: 5000, 2256 AcceptHeight: 100, 2257 AcceptTime: testNow, 2258 ResolveTime: time.Time{}, 2259 Expiry: 40, 2260 State: HtlcStateAccepted, 2261 CustomRecords: make(record.CustomSet), 2262 AMP: &InvoiceHtlcAMPData{ 2263 Record: *ampRecord, 2264 Hash: hash, 2265 Preimage: nil, 2266 }, 2267 }, 2268 invState: ContractAccepted, 2269 setID: &setID, 2270 output: InvoiceHTLC{ 2271 Amt: 5000, 2272 MppTotalAmt: 5000, 2273 AcceptHeight: 100, 2274 AcceptTime: testNow, 2275 ResolveTime: time.Time{}, 2276 Expiry: 40, 2277 State: HtlcStateAccepted, 2278 CustomRecords: make(record.CustomSet), 2279 AMP: &InvoiceHtlcAMPData{ 2280 Record: *ampRecord, 2281 Hash: hash, 2282 Preimage: nil, 2283 }, 2284 }, 2285 expErr: ErrHTLCPreimageMissing, 2286 }, 2287 { 2288 name: "AMP accept invalid preimage", 2289 input: InvoiceHTLC{ 2290 Amt: 5000, 2291 MppTotalAmt: 5000, 2292 AcceptHeight: 100, 2293 AcceptTime: testNow, 2294 ResolveTime: time.Time{}, 2295 Expiry: 40, 2296 State: HtlcStateAccepted, 2297 CustomRecords: make(record.CustomSet), 2298 AMP: &InvoiceHtlcAMPData{ 2299 Record: *ampRecord, 2300 Hash: hash, 2301 Preimage: &fakePreimage, 2302 }, 2303 }, 2304 invState: ContractAccepted, 2305 setID: &setID, 2306 output: InvoiceHTLC{ 2307 Amt: 5000, 2308 MppTotalAmt: 5000, 2309 AcceptHeight: 100, 2310 AcceptTime: testNow, 2311 ResolveTime: time.Time{}, 2312 Expiry: 40, 2313 State: HtlcStateAccepted, 2314 CustomRecords: make(record.CustomSet), 2315 AMP: &InvoiceHtlcAMPData{ 2316 Record: *ampRecord, 2317 Hash: hash, 2318 Preimage: &fakePreimage, 2319 }, 2320 }, 2321 expErr: ErrHTLCPreimageMismatch, 2322 }, 2323 { 2324 name: "AMP accept valid preimage", 2325 input: InvoiceHTLC{ 2326 Amt: 5000, 2327 MppTotalAmt: 5000, 2328 AcceptHeight: 100, 2329 AcceptTime: testNow, 2330 ResolveTime: time.Time{}, 2331 Expiry: 40, 2332 State: HtlcStateAccepted, 2333 CustomRecords: make(record.CustomSet), 2334 AMP: &InvoiceHtlcAMPData{ 2335 Record: *ampRecord, 2336 Hash: hash, 2337 Preimage: &preimage, 2338 }, 2339 }, 2340 invState: ContractAccepted, 2341 setID: &setID, 2342 output: InvoiceHTLC{ 2343 Amt: 5000, 2344 MppTotalAmt: 5000, 2345 AcceptHeight: 100, 2346 AcceptTime: testNow, 2347 ResolveTime: time.Time{}, 2348 Expiry: 40, 2349 State: HtlcStateAccepted, 2350 CustomRecords: make(record.CustomSet), 2351 AMP: &InvoiceHtlcAMPData{ 2352 Record: *ampRecord, 2353 Hash: hash, 2354 Preimage: &preimage, 2355 }, 2356 }, 2357 expErr: nil, 2358 }, 2359 { 2360 name: "AMP accept valid preimage different htlc set", 2361 input: InvoiceHTLC{ 2362 Amt: 5000, 2363 MppTotalAmt: 5000, 2364 AcceptHeight: 100, 2365 AcceptTime: testNow, 2366 ResolveTime: time.Time{}, 2367 Expiry: 40, 2368 State: HtlcStateAccepted, 2369 CustomRecords: make(record.CustomSet), 2370 AMP: &InvoiceHtlcAMPData{ 2371 Record: *ampRecord, 2372 Hash: hash, 2373 Preimage: &preimage, 2374 }, 2375 }, 2376 invState: ContractAccepted, 2377 setID: &diffSetID, 2378 output: InvoiceHTLC{ 2379 Amt: 5000, 2380 MppTotalAmt: 5000, 2381 AcceptHeight: 100, 2382 AcceptTime: testNow, 2383 ResolveTime: time.Time{}, 2384 Expiry: 40, 2385 State: HtlcStateAccepted, 2386 CustomRecords: make(record.CustomSet), 2387 AMP: &InvoiceHtlcAMPData{ 2388 Record: *ampRecord, 2389 Hash: hash, 2390 Preimage: &preimage, 2391 }, 2392 }, 2393 expErr: nil, 2394 }, 2395 { 2396 name: "AMP settle missing preimage", 2397 input: InvoiceHTLC{ 2398 Amt: 5000, 2399 MppTotalAmt: 5000, 2400 AcceptHeight: 100, 2401 AcceptTime: testNow, 2402 ResolveTime: time.Time{}, 2403 Expiry: 40, 2404 State: HtlcStateAccepted, 2405 CustomRecords: make(record.CustomSet), 2406 AMP: &InvoiceHtlcAMPData{ 2407 Record: *ampRecord, 2408 Hash: hash, 2409 Preimage: nil, 2410 }, 2411 }, 2412 invState: ContractSettled, 2413 setID: &setID, 2414 output: InvoiceHTLC{ 2415 Amt: 5000, 2416 MppTotalAmt: 5000, 2417 AcceptHeight: 100, 2418 AcceptTime: testNow, 2419 ResolveTime: time.Time{}, 2420 Expiry: 40, 2421 State: HtlcStateAccepted, 2422 CustomRecords: make(record.CustomSet), 2423 AMP: &InvoiceHtlcAMPData{ 2424 Record: *ampRecord, 2425 Hash: hash, 2426 Preimage: nil, 2427 }, 2428 }, 2429 expErr: ErrHTLCPreimageMissing, 2430 }, 2431 { 2432 name: "AMP settle invalid preimage", 2433 input: InvoiceHTLC{ 2434 Amt: 5000, 2435 MppTotalAmt: 5000, 2436 AcceptHeight: 100, 2437 AcceptTime: testNow, 2438 ResolveTime: time.Time{}, 2439 Expiry: 40, 2440 State: HtlcStateAccepted, 2441 CustomRecords: make(record.CustomSet), 2442 AMP: &InvoiceHtlcAMPData{ 2443 Record: *ampRecord, 2444 Hash: hash, 2445 Preimage: &fakePreimage, 2446 }, 2447 }, 2448 invState: ContractSettled, 2449 setID: &setID, 2450 output: InvoiceHTLC{ 2451 Amt: 5000, 2452 MppTotalAmt: 5000, 2453 AcceptHeight: 100, 2454 AcceptTime: testNow, 2455 ResolveTime: time.Time{}, 2456 Expiry: 40, 2457 State: HtlcStateAccepted, 2458 CustomRecords: make(record.CustomSet), 2459 AMP: &InvoiceHtlcAMPData{ 2460 Record: *ampRecord, 2461 Hash: hash, 2462 Preimage: &fakePreimage, 2463 }, 2464 }, 2465 expErr: ErrHTLCPreimageMismatch, 2466 }, 2467 { 2468 name: "AMP settle valid preimage", 2469 input: InvoiceHTLC{ 2470 Amt: 5000, 2471 MppTotalAmt: 5000, 2472 AcceptHeight: 100, 2473 AcceptTime: testNow, 2474 ResolveTime: time.Time{}, 2475 Expiry: 40, 2476 State: HtlcStateAccepted, 2477 CustomRecords: make(record.CustomSet), 2478 AMP: &InvoiceHtlcAMPData{ 2479 Record: *ampRecord, 2480 Hash: hash, 2481 Preimage: &preimage, 2482 }, 2483 }, 2484 invState: ContractSettled, 2485 setID: &setID, 2486 output: InvoiceHTLC{ 2487 Amt: 5000, 2488 MppTotalAmt: 5000, 2489 AcceptHeight: 100, 2490 AcceptTime: testNow, 2491 ResolveTime: testNow, 2492 Expiry: 40, 2493 State: HtlcStateSettled, 2494 CustomRecords: make(record.CustomSet), 2495 AMP: &InvoiceHtlcAMPData{ 2496 Record: *ampRecord, 2497 Hash: hash, 2498 Preimage: &preimage, 2499 }, 2500 }, 2501 expErr: nil, 2502 }, 2503 { 2504 // With the newer AMP logic, this is now valid, as we 2505 // want to be able to accept multiple settle attempts 2506 // to a given pay_addr. In this case, the HTLC should 2507 // remain in the accepted state. 2508 name: "AMP settle valid preimage different htlc set", 2509 input: InvoiceHTLC{ 2510 Amt: 5000, 2511 MppTotalAmt: 5000, 2512 AcceptHeight: 100, 2513 AcceptTime: testNow, 2514 ResolveTime: time.Time{}, 2515 Expiry: 40, 2516 State: HtlcStateAccepted, 2517 CustomRecords: make(record.CustomSet), 2518 AMP: &InvoiceHtlcAMPData{ 2519 Record: *ampRecord, 2520 Hash: hash, 2521 Preimage: &preimage, 2522 }, 2523 }, 2524 invState: ContractSettled, 2525 setID: &diffSetID, 2526 output: InvoiceHTLC{ 2527 Amt: 5000, 2528 MppTotalAmt: 5000, 2529 AcceptHeight: 100, 2530 AcceptTime: testNow, 2531 ResolveTime: time.Time{}, 2532 Expiry: 40, 2533 State: HtlcStateAccepted, 2534 CustomRecords: make(record.CustomSet), 2535 AMP: &InvoiceHtlcAMPData{ 2536 Record: *ampRecord, 2537 Hash: hash, 2538 Preimage: &preimage, 2539 }, 2540 }, 2541 expErr: nil, 2542 }, 2543 { 2544 name: "accept invoice htlc already settled", 2545 input: InvoiceHTLC{ 2546 Amt: 5000, 2547 MppTotalAmt: 5000, 2548 AcceptHeight: 100, 2549 AcceptTime: testNow, 2550 ResolveTime: testAlreadyNow, 2551 Expiry: 40, 2552 State: HtlcStateSettled, 2553 CustomRecords: make(record.CustomSet), 2554 AMP: &InvoiceHtlcAMPData{ 2555 Record: *ampRecord, 2556 Hash: hash, 2557 Preimage: &preimage, 2558 }, 2559 }, 2560 invState: ContractAccepted, 2561 setID: &setID, 2562 output: InvoiceHTLC{ 2563 Amt: 5000, 2564 MppTotalAmt: 5000, 2565 AcceptHeight: 100, 2566 AcceptTime: testNow, 2567 ResolveTime: testAlreadyNow, 2568 Expiry: 40, 2569 State: HtlcStateSettled, 2570 CustomRecords: make(record.CustomSet), 2571 AMP: &InvoiceHtlcAMPData{ 2572 Record: *ampRecord, 2573 Hash: hash, 2574 Preimage: &preimage, 2575 }, 2576 }, 2577 expErr: ErrHTLCAlreadySettled, 2578 }, 2579 { 2580 name: "cancel invoice htlc already settled", 2581 input: InvoiceHTLC{ 2582 Amt: 5000, 2583 MppTotalAmt: 5000, 2584 AcceptHeight: 100, 2585 AcceptTime: testNow, 2586 ResolveTime: testAlreadyNow, 2587 Expiry: 40, 2588 State: HtlcStateSettled, 2589 CustomRecords: make(record.CustomSet), 2590 AMP: &InvoiceHtlcAMPData{ 2591 Record: *ampRecord, 2592 Hash: hash, 2593 Preimage: &preimage, 2594 }, 2595 }, 2596 invState: ContractCanceled, 2597 setID: &setID, 2598 output: InvoiceHTLC{ 2599 Amt: 5000, 2600 MppTotalAmt: 5000, 2601 AcceptHeight: 100, 2602 AcceptTime: testNow, 2603 ResolveTime: testAlreadyNow, 2604 Expiry: 40, 2605 State: HtlcStateSettled, 2606 CustomRecords: make(record.CustomSet), 2607 AMP: &InvoiceHtlcAMPData{ 2608 Record: *ampRecord, 2609 Hash: hash, 2610 Preimage: &preimage, 2611 }, 2612 }, 2613 expErr: ErrHTLCAlreadySettled, 2614 }, 2615 { 2616 name: "settle invoice htlc already settled", 2617 input: InvoiceHTLC{ 2618 Amt: 5000, 2619 MppTotalAmt: 5000, 2620 AcceptHeight: 100, 2621 AcceptTime: testNow, 2622 ResolveTime: testAlreadyNow, 2623 Expiry: 40, 2624 State: HtlcStateSettled, 2625 CustomRecords: make(record.CustomSet), 2626 AMP: &InvoiceHtlcAMPData{ 2627 Record: *ampRecord, 2628 Hash: hash, 2629 Preimage: &preimage, 2630 }, 2631 }, 2632 invState: ContractSettled, 2633 setID: &setID, 2634 output: InvoiceHTLC{ 2635 Amt: 5000, 2636 MppTotalAmt: 5000, 2637 AcceptHeight: 100, 2638 AcceptTime: testNow, 2639 ResolveTime: testAlreadyNow, 2640 Expiry: 40, 2641 State: HtlcStateSettled, 2642 CustomRecords: make(record.CustomSet), 2643 AMP: &InvoiceHtlcAMPData{ 2644 Record: *ampRecord, 2645 Hash: hash, 2646 Preimage: &preimage, 2647 }, 2648 }, 2649 expErr: nil, 2650 }, 2651 { 2652 name: "cancel invoice", 2653 input: InvoiceHTLC{ 2654 Amt: 5000, 2655 MppTotalAmt: 5000, 2656 AcceptHeight: 100, 2657 AcceptTime: testNow, 2658 ResolveTime: time.Time{}, 2659 Expiry: 40, 2660 State: HtlcStateAccepted, 2661 CustomRecords: make(record.CustomSet), 2662 AMP: &InvoiceHtlcAMPData{ 2663 Record: *ampRecord, 2664 Hash: hash, 2665 Preimage: &preimage, 2666 }, 2667 }, 2668 invState: ContractCanceled, 2669 setID: &setID, 2670 output: InvoiceHTLC{ 2671 Amt: 5000, 2672 MppTotalAmt: 5000, 2673 AcceptHeight: 100, 2674 AcceptTime: testNow, 2675 ResolveTime: testNow, 2676 Expiry: 40, 2677 State: HtlcStateCanceled, 2678 CustomRecords: make(record.CustomSet), 2679 AMP: &InvoiceHtlcAMPData{ 2680 Record: *ampRecord, 2681 Hash: hash, 2682 Preimage: &preimage, 2683 }, 2684 }, 2685 expErr: nil, 2686 }, 2687 { 2688 name: "accept invoice htlc already canceled", 2689 input: InvoiceHTLC{ 2690 Amt: 5000, 2691 MppTotalAmt: 5000, 2692 AcceptHeight: 100, 2693 AcceptTime: testNow, 2694 ResolveTime: testAlreadyNow, 2695 Expiry: 40, 2696 State: HtlcStateCanceled, 2697 CustomRecords: make(record.CustomSet), 2698 AMP: &InvoiceHtlcAMPData{ 2699 Record: *ampRecord, 2700 Hash: hash, 2701 Preimage: &preimage, 2702 }, 2703 }, 2704 invState: ContractAccepted, 2705 setID: &setID, 2706 output: InvoiceHTLC{ 2707 Amt: 5000, 2708 MppTotalAmt: 5000, 2709 AcceptHeight: 100, 2710 AcceptTime: testNow, 2711 ResolveTime: testAlreadyNow, 2712 Expiry: 40, 2713 State: HtlcStateCanceled, 2714 CustomRecords: make(record.CustomSet), 2715 AMP: &InvoiceHtlcAMPData{ 2716 Record: *ampRecord, 2717 Hash: hash, 2718 Preimage: &preimage, 2719 }, 2720 }, 2721 expErr: nil, 2722 }, 2723 { 2724 name: "cancel invoice htlc already canceled", 2725 input: InvoiceHTLC{ 2726 Amt: 5000, 2727 MppTotalAmt: 5000, 2728 AcceptHeight: 100, 2729 AcceptTime: testNow, 2730 ResolveTime: testAlreadyNow, 2731 Expiry: 40, 2732 State: HtlcStateCanceled, 2733 CustomRecords: make(record.CustomSet), 2734 AMP: &InvoiceHtlcAMPData{ 2735 Record: *ampRecord, 2736 Hash: hash, 2737 Preimage: &preimage, 2738 }, 2739 }, 2740 invState: ContractCanceled, 2741 setID: &setID, 2742 output: InvoiceHTLC{ 2743 Amt: 5000, 2744 MppTotalAmt: 5000, 2745 AcceptHeight: 100, 2746 AcceptTime: testNow, 2747 ResolveTime: testAlreadyNow, 2748 Expiry: 40, 2749 State: HtlcStateCanceled, 2750 CustomRecords: make(record.CustomSet), 2751 AMP: &InvoiceHtlcAMPData{ 2752 Record: *ampRecord, 2753 Hash: hash, 2754 Preimage: &preimage, 2755 }, 2756 }, 2757 expErr: nil, 2758 }, 2759 { 2760 name: "settle invoice htlc already canceled", 2761 input: InvoiceHTLC{ 2762 Amt: 5000, 2763 MppTotalAmt: 5000, 2764 AcceptHeight: 100, 2765 AcceptTime: testNow, 2766 ResolveTime: testAlreadyNow, 2767 Expiry: 40, 2768 State: HtlcStateCanceled, 2769 CustomRecords: make(record.CustomSet), 2770 AMP: &InvoiceHtlcAMPData{ 2771 Record: *ampRecord, 2772 Hash: hash, 2773 Preimage: &preimage, 2774 }, 2775 }, 2776 invState: ContractSettled, 2777 setID: &setID, 2778 output: InvoiceHTLC{ 2779 Amt: 5000, 2780 MppTotalAmt: 5000, 2781 AcceptHeight: 100, 2782 AcceptTime: testNow, 2783 ResolveTime: testAlreadyNow, 2784 Expiry: 40, 2785 State: HtlcStateCanceled, 2786 CustomRecords: make(record.CustomSet), 2787 AMP: &InvoiceHtlcAMPData{ 2788 Record: *ampRecord, 2789 Hash: hash, 2790 Preimage: &preimage, 2791 }, 2792 }, 2793 expErr: nil, 2794 }, 2795 } 2796 2797 for _, test := range tests { 2798 test := test 2799 t.Run(test.name, func(t *testing.T) { 2800 testUpdateHTLC(t, test) 2801 }) 2802 } 2803 } 2804 2805 func testUpdateHTLC(t *testing.T, test updateHTLCTest) { 2806 htlc := test.input.Copy() 2807 _, err := updateHtlc(testNow, htlc, test.invState, test.setID) 2808 require.Equal(t, test.expErr, err) 2809 require.Equal(t, test.output, *htlc) 2810 } 2811 2812 // TestDeleteInvoices tests that deleting a list of invoices will succeed 2813 // if all delete references are valid, or will fail otherwise. 2814 func TestDeleteInvoices(t *testing.T) { 2815 t.Parallel() 2816 2817 db, cleanup, err := MakeTestDB() 2818 defer cleanup() 2819 require.NoError(t, err, "unable to make test db") 2820 2821 // Add some invoices to the test db. 2822 numInvoices := 3 2823 invoicesToDelete := make([]InvoiceDeleteRef, numInvoices) 2824 2825 for i := 0; i < numInvoices; i++ { 2826 invoice, err := randInvoice(lnwire.MilliAtom(i + 1)) 2827 require.NoError(t, err) 2828 2829 paymentHash := invoice.Terms.PaymentPreimage.Hash() 2830 addIndex, err := db.AddInvoice(invoice, paymentHash) 2831 require.NoError(t, err) 2832 2833 // Settle the second invoice. 2834 if i == 1 { 2835 invoice, err = db.UpdateInvoice( 2836 InvoiceRefByHash(paymentHash), nil, 2837 getUpdateInvoice(invoice.Terms.Value), 2838 ) 2839 require.NoError(t, err, "unable to settle invoice") 2840 } 2841 2842 // store the delete ref for later. 2843 invoicesToDelete[i] = InvoiceDeleteRef{ 2844 PayHash: paymentHash, 2845 PayAddr: &invoice.Terms.PaymentAddr, 2846 AddIndex: addIndex, 2847 SettleIndex: invoice.SettleIndex, 2848 } 2849 } 2850 2851 // assertInvoiceCount asserts that the number of invoices equals 2852 // to the passed count. 2853 assertInvoiceCount := func(count int) { 2854 // Query to collect all invoices. 2855 query := InvoiceQuery{ 2856 IndexOffset: 0, 2857 NumMaxInvoices: math.MaxUint64, 2858 } 2859 2860 // Check that we really have 3 invoices. 2861 response, err := db.QueryInvoices(query) 2862 require.NoError(t, err) 2863 require.Equal(t, count, len(response.Invoices)) 2864 } 2865 2866 // XOR one byte of one of the references' hash and attempt to delete. 2867 invoicesToDelete[0].PayHash[2] ^= 3 2868 require.Error(t, db.DeleteInvoice(invoicesToDelete)) 2869 assertInvoiceCount(3) 2870 2871 // Restore the hash. 2872 invoicesToDelete[0].PayHash[2] ^= 3 2873 2874 // XOR the second invoice's payment settle index as it is settled, and 2875 // attempt to delete. 2876 invoicesToDelete[1].SettleIndex ^= 11 2877 require.Error(t, db.DeleteInvoice(invoicesToDelete)) 2878 assertInvoiceCount(3) 2879 2880 // Restore the settle index. 2881 invoicesToDelete[1].SettleIndex ^= 11 2882 2883 // XOR the add index for one of the references and attempt to delete. 2884 invoicesToDelete[2].AddIndex ^= 13 2885 require.Error(t, db.DeleteInvoice(invoicesToDelete)) 2886 assertInvoiceCount(3) 2887 2888 // Restore the add index. 2889 invoicesToDelete[2].AddIndex ^= 13 2890 2891 // Delete should succeed with all the valid references. 2892 require.NoError(t, db.DeleteInvoice(invoicesToDelete)) 2893 assertInvoiceCount(0) 2894 } 2895 2896 // TestAddInvoiceInvalidFeatureDeps asserts that inserting an invoice with 2897 // invalid transitive feature dependencies fails with the appropriate error. 2898 func TestAddInvoiceInvalidFeatureDeps(t *testing.T) { 2899 t.Parallel() 2900 2901 db, cleanup, err := MakeTestDB() 2902 require.NoError(t, err, "unable to make test db") 2903 defer cleanup() 2904 2905 invoice, err := randInvoice(500) 2906 require.NoError(t, err) 2907 2908 invoice.Terms.Features = lnwire.NewFeatureVector( 2909 lnwire.NewRawFeatureVector( 2910 lnwire.TLVOnionPayloadOptional, 2911 lnwire.MPPOptional, 2912 ), 2913 lnwire.Features, 2914 ) 2915 2916 hash := invoice.Terms.PaymentPreimage.Hash() 2917 _, err = db.AddInvoice(invoice, hash) 2918 require.Error(t, err, feature.NewErrMissingFeatureDep( 2919 lnwire.PaymentAddrOptional, 2920 )) 2921 } 2922 2923 // TestEncodeDecodeAmpInvoiceState asserts that the nested TLV 2924 // encoding+decoding for the AMPInvoiceState struct works as expected. 2925 func TestEncodeDecodeAmpInvoiceState(t *testing.T) { 2926 t.Parallel() 2927 2928 setID1 := [32]byte{1} 2929 setID2 := [32]byte{2} 2930 setID3 := [32]byte{3} 2931 2932 circuitKey1 := CircuitKey{ 2933 ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 1, 2934 } 2935 circuitKey2 := CircuitKey{ 2936 ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 2, 2937 } 2938 circuitKey3 := CircuitKey{ 2939 ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 3, 2940 } 2941 2942 // Make a sample invoice state map that we'll encode then decode to 2943 // assert equality of. 2944 ampState := AMPInvoiceState{ 2945 setID1: InvoiceStateAMP{ 2946 State: HtlcStateSettled, 2947 SettleDate: testNow, 2948 SettleIndex: 1, 2949 InvoiceKeys: map[CircuitKey]struct{}{ 2950 circuitKey1: {}, 2951 circuitKey2: {}, 2952 }, 2953 AmtPaid: 5, 2954 }, 2955 setID2: InvoiceStateAMP{ 2956 State: HtlcStateCanceled, 2957 SettleDate: testNow, 2958 SettleIndex: 2, 2959 InvoiceKeys: map[CircuitKey]struct{}{ 2960 circuitKey1: {}, 2961 }, 2962 AmtPaid: 6, 2963 }, 2964 setID3: InvoiceStateAMP{ 2965 State: HtlcStateAccepted, 2966 SettleDate: testNow, 2967 SettleIndex: 3, 2968 InvoiceKeys: map[CircuitKey]struct{}{ 2969 circuitKey1: {}, 2970 circuitKey2: {}, 2971 circuitKey3: {}, 2972 }, 2973 AmtPaid: 7, 2974 }, 2975 } 2976 2977 // We'll now make a sample invoice stream, and use that to encode the 2978 // amp state we created above. 2979 tlvStream, err := tlv.NewStream( 2980 tlv.MakeDynamicRecord( 2981 invoiceAmpStateType, &State, ampState.recordSize, 2982 ampStateEncoder, ampStateDecoder, 2983 ), 2984 ) 2985 require.Nil(t, err) 2986 2987 // Next encode the stream into a set of raw bytes. 2988 var b bytes.Buffer 2989 err = tlvStream.Encode(&b) 2990 require.Nil(t, err) 2991 2992 // Now create a new blank ampState map, which we'll use to decode the 2993 // bytes into. 2994 ampState2 := make(AMPInvoiceState) 2995 2996 // Decode from the raw stream into this blank mpa. 2997 tlvStream, err = tlv.NewStream( 2998 tlv.MakeDynamicRecord( 2999 invoiceAmpStateType, &State2, nil, 3000 ampStateEncoder, ampStateDecoder, 3001 ), 3002 ) 3003 require.Nil(t, err) 3004 3005 err = tlvStream.Decode(&b) 3006 require.Nil(t, err) 3007 3008 // The two states should match. 3009 require.Equal(t, ampState, ampState2) 3010 }