github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_amp_test.go (about) 1 package itest 2 3 import ( 4 "context" 5 "crypto/rand" 6 "encoding/hex" 7 "sort" 8 "testing" 9 "time" 10 11 "github.com/decred/dcrd/dcrutil/v4" 12 "github.com/decred/dcrlnd/amp" 13 "github.com/decred/dcrlnd/chainreg" 14 "github.com/decred/dcrlnd/lnrpc" 15 "github.com/decred/dcrlnd/lnrpc/invoicesrpc" 16 "github.com/decred/dcrlnd/lnrpc/routerrpc" 17 "github.com/decred/dcrlnd/lntest" 18 "github.com/decred/dcrlnd/lntypes" 19 "github.com/stretchr/testify/require" 20 ) 21 22 // testSendPaymentAMPInvoice tests that we can send an AMP payment to a 23 // specified AMP invoice using SendPaymentV2. 24 func testSendPaymentAMPInvoice(net *lntest.NetworkHarness, t *harnessTest) { 25 t.t.Run("native payaddr", func(t *testing.T) { 26 tt := newHarnessTest(t, net) 27 testSendPaymentAMPInvoiceCase(net, tt, false) 28 }) 29 t.t.Run("external payaddr", func(t *testing.T) { 30 tt := newHarnessTest(t, net) 31 testSendPaymentAMPInvoiceCase(net, tt, true) 32 }) 33 } 34 35 func testSendPaymentAMPInvoiceCase(net *lntest.NetworkHarness, t *harnessTest, 36 useExternalPayAddr bool) { 37 38 ctxb := context.Background() 39 40 ctx := newMppTestContext(t, net) 41 defer ctx.shutdownNodes() 42 43 // Subscribe to bob's invoices. Do this early in the test to make sure 44 // that the subscription has actually been completed when we add an 45 // invoice. Otherwise the notification will be missed. 46 req := &lnrpc.InvoiceSubscription{} 47 ctxc, cancelSubscription := context.WithCancel(ctxb) 48 bobInvoiceSubscription, err := ctx.bob.SubscribeInvoices(ctxc, req) 49 require.NoError(t.t, err) 50 defer cancelSubscription() 51 52 const paymentAmt = dcrutil.Amount(300000) 53 54 // Set up a network with three different paths Alice <-> Bob. Channel 55 // capacities are set such that the payment can only succeed if (at 56 // least) three paths are used. 57 // 58 // _ Eve _ 59 // / \ 60 // Alice -- Carol ---- Bob 61 // \ / 62 // \__ Dave ____/ 63 // 64 ctx.openChannel(ctx.carol, ctx.bob, 135000) 65 ctx.openChannel(ctx.alice, ctx.carol, 235000) 66 ctx.openChannel(ctx.dave, ctx.bob, 135000) 67 ctx.openChannel(ctx.alice, ctx.dave, 135000) 68 ctx.openChannel(ctx.eve, ctx.bob, 135000) 69 ctx.openChannel(ctx.carol, ctx.eve, 135000) 70 71 defer ctx.closeChannels() 72 73 ctx.waitForChannels() 74 75 addInvoiceResp, err := ctx.bob.AddInvoice(context.Background(), &lnrpc.Invoice{ 76 Value: int64(paymentAmt), 77 IsAmp: true, 78 }) 79 require.NoError(t.t, err) 80 81 // Ensure we get a notification of the invoice being added by Bob. 82 rpcInvoice, err := bobInvoiceSubscription.Recv() 83 require.NoError(t.t, err) 84 85 require.False(t.t, rpcInvoice.Settled) // nolint:staticcheck 86 require.Equal(t.t, lnrpc.Invoice_OPEN, rpcInvoice.State) 87 require.Equal(t.t, int64(0), rpcInvoice.AmtPaidAtoms) 88 require.Equal(t.t, int64(0), rpcInvoice.AmtPaidMAtoms) 89 90 require.Equal(t.t, 0, len(rpcInvoice.Htlcs)) 91 92 // Increase Dave's fee to make the test deterministic. Otherwise it 93 // would be unpredictable whether pathfinding would go through Charlie 94 // or Dave for the first shard. 95 _, err = ctx.dave.UpdateChannelPolicy( 96 context.Background(), 97 &lnrpc.PolicyUpdateRequest{ 98 Scope: &lnrpc.PolicyUpdateRequest_Global{Global: true}, 99 BaseFeeMAtoms: 500000, 100 FeeRate: 0.001, 101 TimeLockDelta: 40, 102 }, 103 ) 104 if err != nil { 105 t.Fatalf("dave policy update: %v", err) 106 } 107 108 // Generate an external payment address when attempting to pseudo-reuse 109 // an AMP invoice. When using an external payment address, we'll also 110 // expect an extra invoice to appear in the ListInvoices response, since 111 // a new invoice will be JIT inserted under a different payment address 112 // than the one in the invoice. 113 var ( 114 expNumInvoices = 1 115 externalPayAddr []byte 116 ) 117 if useExternalPayAddr { 118 expNumInvoices = 2 119 externalPayAddr = make([]byte, 32) 120 _, err = rand.Read(externalPayAddr) 121 require.NoError(t.t, err) 122 } 123 124 payment := sendAndAssertSuccess( 125 t, ctx.alice, &routerrpc.SendPaymentRequest{ 126 PaymentRequest: addInvoiceResp.PaymentRequest, 127 PaymentAddr: externalPayAddr, 128 TimeoutSeconds: 60, 129 FeeLimitMAtoms: noFeeLimitMAtoms, 130 }, 131 ) 132 133 // Check that Alice split the payment in at least three shards. Because 134 // the hand-off of the htlc to the link is asynchronous (via a mailbox), 135 // there is some non-determinism in the process. Depending on whether 136 // the new pathfinding round is started before or after the htlc is 137 // locked into the channel, different sharding may occur. Therefore we 138 // can only check if the number of shards isn't below the theoretical 139 // minimum. 140 succeeded := 0 141 for _, htlc := range payment.Htlcs { 142 if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED { 143 succeeded++ 144 } 145 } 146 147 const minExpectedShards = 3 148 if succeeded < minExpectedShards { 149 t.Fatalf("expected at least %v shards, but got %v", 150 minExpectedShards, succeeded) 151 } 152 153 // When an external payment address is supplied, we'll get an extra 154 // notification for the JIT inserted invoice, since it differs from the 155 // original. 156 if useExternalPayAddr { 157 _, err = bobInvoiceSubscription.Recv() 158 require.NoError(t.t, err) 159 } 160 161 // There should now be a settle event for the invoice. 162 rpcInvoice, err = bobInvoiceSubscription.Recv() 163 require.NoError(t.t, err) 164 165 // Also fetch Bob's invoice from ListInvoices and assert it is equal to 166 // the one recevied via the subscription. 167 invoiceResp, err := ctx.bob.ListInvoices( 168 ctxb, &lnrpc.ListInvoiceRequest{}, 169 ) 170 require.NoError(t.t, err) 171 require.Equal(t.t, expNumInvoices, len(invoiceResp.Invoices)) 172 assertInvoiceEqual(t.t, rpcInvoice, invoiceResp.Invoices[expNumInvoices-1]) 173 174 // Assert that the invoice is settled for the total payment amount and 175 // has the correct payment address. 176 require.True(t.t, rpcInvoice.Settled) // nolint:staticcheck 177 require.Equal(t.t, lnrpc.Invoice_SETTLED, rpcInvoice.State) 178 require.Equal(t.t, int64(paymentAmt), rpcInvoice.AmtPaidAtoms) 179 require.Equal(t.t, int64(paymentAmt*1000), rpcInvoice.AmtPaidMAtoms) 180 181 // Finally, assert that the same set id is recorded for each htlc, and 182 // that the preimage hash pair is valid. 183 var setID []byte 184 require.Equal(t.t, succeeded, len(rpcInvoice.Htlcs)) 185 for _, htlc := range rpcInvoice.Htlcs { 186 require.NotNil(t.t, htlc.Amp) 187 if setID == nil { 188 setID = make([]byte, 32) 189 copy(setID, htlc.Amp.SetId) 190 } 191 require.Equal(t.t, setID, htlc.Amp.SetId) 192 193 // Parse the child hash and child preimage, and assert they are 194 // well-formed. 195 childHash, err := lntypes.MakeHash(htlc.Amp.Hash) 196 require.NoError(t.t, err) 197 childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage) 198 require.NoError(t.t, err) 199 200 // Assert that the preimage actually matches the hashes. 201 validPreimage := childPreimage.Matches(childHash) 202 require.True(t.t, validPreimage) 203 } 204 205 // The set ID we extract above should be shown in the final settled 206 // state. 207 ampState := rpcInvoice.AmpInvoiceState[hex.EncodeToString(setID)] 208 require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State) 209 } 210 211 // testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP 212 // invoice multiple times by having the client generate a new setID each time. 213 func testSendPaymentAMPInvoiceRepeat(net *lntest.NetworkHarness, 214 t *harnessTest) { 215 216 // In this basic test, we'll only need two nodes as we want to 217 // primarily test the recurring payment feature. So we'll re-use the 218 carol := net.NewNode(t.t, "Carol", nil) 219 defer shutdownAndAssert(net, t, carol) 220 221 // Send Carol enough coins to be able to open a channel to Dave. 222 net.SendCoins(t.t, dcrutil.AtomsPerCoin, carol) 223 224 dave := net.NewNode(t.t, "Dave", nil) 225 defer shutdownAndAssert(net, t, dave) 226 227 // Before we start the test, we'll ensure both sides are connected to 228 // the funding flow can properly be executed. 229 net.EnsureConnected(t.t, carol, dave) 230 231 // Set up an invoice subscription so we can be notified when Dave 232 // receives his repeated payments. 233 req := &lnrpc.InvoiceSubscription{} 234 ctxb := context.Background() 235 ctxc, cancelSubscription := context.WithCancel(ctxb) 236 invSubscription, err := dave.SubscribeInvoices(ctxc, req) 237 require.NoError(t.t, err) 238 defer cancelSubscription() 239 240 // Establish a channel between Carol and Dave. 241 chanAmt := dcrutil.Amount(100_000) 242 chanPoint := openChannelAndAssert( 243 t, net, carol, dave, 244 lntest.OpenChannelParams{ 245 Amt: chanAmt, 246 }, 247 ) 248 err = carol.WaitForNetworkChannelOpen(chanPoint) 249 require.NoError(t.t, err, "carol didn't report channel") 250 err = dave.WaitForNetworkChannelOpen(chanPoint) 251 require.NoError(t.t, err, "dave didn't report channel") 252 253 // Create an AMP invoice of a trivial amount, that we'll pay repeatedly 254 // in this integration test. 255 paymentAmt := 10000 256 addInvoiceResp, err := dave.AddInvoice(ctxb, &lnrpc.Invoice{ 257 Value: int64(paymentAmt), 258 IsAmp: true, 259 }) 260 require.NoError(t.t, err) 261 262 // We should get an initial notification that the HTLC has been added. 263 rpcInvoice, err := invSubscription.Recv() 264 require.NoError(t.t, err) 265 require.False(t.t, rpcInvoice.Settled) // nolint:staticcheck 266 require.Equal(t.t, lnrpc.Invoice_OPEN, rpcInvoice.State) 267 require.Equal(t.t, int64(0), rpcInvoice.AmtPaidAtoms) 268 require.Equal(t.t, int64(0), rpcInvoice.AmtPaidMAtoms) 269 270 require.Equal(t.t, 0, len(rpcInvoice.Htlcs)) 271 272 // Now we'll use Carol to pay the invoice that Dave created. 273 _ = sendAndAssertSuccess( 274 t, carol, &routerrpc.SendPaymentRequest{ 275 PaymentRequest: addInvoiceResp.PaymentRequest, 276 TimeoutSeconds: 60, 277 FeeLimitMAtoms: noFeeLimitMAtoms, 278 }, 279 ) 280 281 // Dave should get a notification that the invoice has been settled. 282 invoiceNtfn, err := invSubscription.Recv() 283 require.NoError(t.t, err) 284 285 // The notification should signal that the invoice is now settled, and 286 // should also include the set ID, and show the proper amount paid. 287 require.True(t.t, invoiceNtfn.Settled) // nolint:staticcheck 288 require.Equal(t.t, lnrpc.Invoice_SETTLED, invoiceNtfn.State) 289 require.Equal(t.t, paymentAmt, int(invoiceNtfn.AmtPaidAtoms)) 290 require.Equal(t.t, 1, len(invoiceNtfn.AmpInvoiceState)) 291 var firstSetID []byte 292 for setIDStr, ampState := range invoiceNtfn.AmpInvoiceState { 293 firstSetID, _ = hex.DecodeString(setIDStr) 294 require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State) 295 } 296 297 // Pay the invoice again, we should get another notification that Dave 298 // has received another payment. 299 _ = sendAndAssertSuccess( 300 t, carol, &routerrpc.SendPaymentRequest{ 301 PaymentRequest: addInvoiceResp.PaymentRequest, 302 TimeoutSeconds: 60, 303 FeeLimitMAtoms: noFeeLimitMAtoms, 304 }, 305 ) 306 307 // Dave should get another notification. 308 invoiceNtfn, err = invSubscription.Recv() 309 require.NoError(t.t, err) 310 311 // The invoice should still be shown as settled, and also include the 312 // information about this newly generated setID, showing 2x the amount 313 // paid. 314 require.True(t.t, invoiceNtfn.Settled) // nolint:staticcheck 315 require.Equal(t.t, paymentAmt*2, int(invoiceNtfn.AmtPaidAtoms)) 316 317 var secondSetID []byte 318 for setIDStr, ampState := range invoiceNtfn.AmpInvoiceState { 319 secondSetID, _ = hex.DecodeString(setIDStr) 320 require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State) 321 } 322 323 // The returned invoice should only include a single HTLC since we 324 // return the "projected" sub-invoice for a given setID. 325 require.Equal(t.t, 1, len(invoiceNtfn.Htlcs)) 326 327 // However the AMP state index should show that there've been two 328 // repeated payments to this invoice so far. 329 require.Equal(t.t, 2, len(invoiceNtfn.AmpInvoiceState)) 330 331 // Now we'll look up the invoice using the new LookupInvoice2 RPC call 332 // by the set ID of each of the invoices. 333 subInvoice1, err := dave.LookupInvoiceV2(ctxb, &invoicesrpc.LookupInvoiceMsg{ 334 InvoiceRef: &invoicesrpc.LookupInvoiceMsg_SetId{ 335 SetId: firstSetID, 336 }, 337 LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_ONLY, 338 }) 339 require.Nil(t.t, err) 340 subInvoice2, err := dave.LookupInvoiceV2(ctxb, &invoicesrpc.LookupInvoiceMsg{ 341 InvoiceRef: &invoicesrpc.LookupInvoiceMsg_SetId{ 342 SetId: secondSetID, 343 }, 344 LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_ONLY, 345 }) 346 require.Nil(t.t, err) 347 348 // Each invoice should only show a single HTLC present, as we passed 349 // the HTLC set only modifier. 350 require.Equal(t.t, 1, len(subInvoice1.Htlcs)) 351 require.Equal(t.t, 1, len(subInvoice2.Htlcs)) 352 353 // If we look up the same invoice, by its payment address, but now with 354 // the HTLC blank modifier, then none of them should be returned. 355 rootInvoice, err := dave.LookupInvoiceV2(ctxb, &invoicesrpc.LookupInvoiceMsg{ 356 InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{ 357 PaymentAddr: addInvoiceResp.PaymentAddr, 358 }, 359 LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_BLANK, 360 }) 361 require.Nil(t.t, err) 362 require.Equal(t.t, 0, len(rootInvoice.Htlcs)) 363 364 // If we look up the same invoice, by its payment address, but without 365 // that modified, then we should get all the relevant HTLCs. 366 rootInvoice, err = dave.LookupInvoiceV2(ctxb, 367 &invoicesrpc.LookupInvoiceMsg{ 368 InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{ 369 PaymentAddr: addInvoiceResp.PaymentAddr, 370 }, 371 }) 372 require.Nil(t.t, err) 373 require.Equal(t.t, 2, len(rootInvoice.Htlcs)) 374 375 // Finally, we'll test that if we subscribe for notifications of 376 // settled invoices, we get a backlog, which includes the invoice we 377 // settled last (since you can only fetch from index 1 onwards), and 378 // only the relevant set of HTLCs. 379 req = &lnrpc.InvoiceSubscription{ 380 SettleIndex: 1, 381 } 382 ctxc, cancelSubscription2 := context.WithCancel(ctxb) 383 invSub2, err := dave.SubscribeInvoices(ctxc, req) 384 require.NoError(t.t, err) 385 defer cancelSubscription2() 386 387 // The first invoice we get back should match the state of the invoice 388 // after our second payment: amt updated, but only a single HTLC shown 389 // through. 390 backlogInv, _ := invSub2.Recv() 391 require.Equal(t.t, 1, len(backlogInv.Htlcs)) 392 require.Equal(t.t, 2, len(backlogInv.AmpInvoiceState)) 393 require.True(t.t, backlogInv.Settled) // nolint:staticcheck 394 require.Equal(t.t, paymentAmt*2, int(backlogInv.AmtPaidAtoms)) 395 } 396 397 // testSendPaymentAMP tests that we can send an AMP payment to a specified 398 // destination using SendPaymentV2. 399 func testSendPaymentAMP(net *lntest.NetworkHarness, t *harnessTest) { 400 ctxb := context.Background() 401 402 ctx := newMppTestContext(t, net) 403 defer ctx.shutdownNodes() 404 405 const paymentAmt = dcrutil.Amount(300000) 406 407 // Set up a network with three different paths Alice <-> Bob. Channel 408 // capacities are set such that the payment can only succeed if (at 409 // least) three paths are used. 410 // 411 // _ Eve _ 412 // / \ 413 // Alice -- Carol ---- Bob 414 // \ / 415 // \__ Dave ____/ 416 // 417 ctx.openChannel(ctx.carol, ctx.bob, 135000) 418 ctx.openChannel(ctx.alice, ctx.carol, 235000) 419 ctx.openChannel(ctx.dave, ctx.bob, 135000) 420 ctx.openChannel(ctx.alice, ctx.dave, 135000) 421 ctx.openChannel(ctx.eve, ctx.bob, 135000) 422 ctx.openChannel(ctx.carol, ctx.eve, 135000) 423 424 defer ctx.closeChannels() 425 426 ctx.waitForChannels() 427 428 // Increase Dave's fee to make the test deterministic. Otherwise it 429 // would be unpredictable whether pathfinding would go through Charlie 430 // or Dave for the first shard. 431 _, err := ctx.dave.UpdateChannelPolicy( 432 context.Background(), 433 &lnrpc.PolicyUpdateRequest{ 434 Scope: &lnrpc.PolicyUpdateRequest_Global{Global: true}, 435 BaseFeeMAtoms: 500000, 436 FeeRate: 0.001, 437 TimeLockDelta: 40, 438 }, 439 ) 440 if err != nil { 441 t.Fatalf("dave policy update: %v", err) 442 } 443 444 payment := sendAndAssertSuccess( 445 t, ctx.alice, &routerrpc.SendPaymentRequest{ 446 Dest: ctx.bob.PubKey[:], 447 Amt: int64(paymentAmt), 448 FinalCltvDelta: chainreg.DefaultDecredTimeLockDelta, 449 TimeoutSeconds: 60, 450 FeeLimitMAtoms: noFeeLimitMAtoms, 451 Amp: true, 452 }, 453 ) 454 455 // Check that Alice split the payment in at least three shards. Because 456 // the hand-off of the htlc to the link is asynchronous (via a mailbox), 457 // there is some non-determinism in the process. Depending on whether 458 // the new pathfinding round is started before or after the htlc is 459 // locked into the channel, different sharding may occur. Therefore we 460 // can only check if the number of shards isn't below the theoretical 461 // minimum. 462 succeeded := 0 463 for _, htlc := range payment.Htlcs { 464 if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED { 465 succeeded++ 466 } 467 } 468 469 const minExpectedShards = 3 470 if succeeded < minExpectedShards { 471 t.Fatalf("expected at least %v shards, but got %v", 472 minExpectedShards, succeeded) 473 } 474 475 // Fetch Bob's invoices. 476 invoiceResp, err := ctx.bob.ListInvoices( 477 ctxb, &lnrpc.ListInvoiceRequest{}, 478 ) 479 require.NoError(t.t, err) 480 481 // There should only be one invoice. 482 require.Equal(t.t, 1, len(invoiceResp.Invoices)) 483 rpcInvoice := invoiceResp.Invoices[0] 484 485 // Assert that the invoice is settled for the total payment amount and 486 // has the correct payment address. 487 require.True(t.t, rpcInvoice.Settled) 488 require.Equal(t.t, lnrpc.Invoice_SETTLED, rpcInvoice.State) 489 require.Equal(t.t, int64(paymentAmt), rpcInvoice.AmtPaidAtoms) 490 require.Equal(t.t, int64(paymentAmt*1000), rpcInvoice.AmtPaidMAtoms) 491 492 // Finally, assert that the same set id is recorded for each htlc, and 493 // that the preimage hash pair is valid. 494 var setID []byte 495 require.Equal(t.t, succeeded, len(rpcInvoice.Htlcs)) 496 for _, htlc := range rpcInvoice.Htlcs { 497 require.NotNil(t.t, htlc.Amp) 498 if setID == nil { 499 setID = make([]byte, 32) 500 copy(setID, htlc.Amp.SetId) 501 } 502 require.Equal(t.t, setID, htlc.Amp.SetId) 503 504 // Parse the child hash and child preimage, and assert they are 505 // well-formed. 506 childHash, err := lntypes.MakeHash(htlc.Amp.Hash) 507 require.NoError(t.t, err) 508 childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage) 509 require.NoError(t.t, err) 510 511 // Assert that the preimage actually matches the hashes. 512 validPreimage := childPreimage.Matches(childHash) 513 require.True(t.t, validPreimage) 514 } 515 516 // The set ID we extract above should be shown in the final settled 517 // state. 518 ampState := rpcInvoice.AmpInvoiceState[hex.EncodeToString(setID)] 519 require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State) 520 } 521 522 func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) { 523 ctxb := context.Background() 524 525 ctx := newMppTestContext(t, net) 526 defer ctx.shutdownNodes() 527 528 const ( 529 paymentAmt = dcrutil.Amount(300000) 530 numShards = 3 531 shardAmt = paymentAmt / numShards 532 chanAmt = shardAmt * 3 / 2 533 ) 534 535 // Set up a network with three different paths Alice <-> Bob. 536 // _ Eve _ 537 // / \ 538 // Alice -- Carol ---- Bob 539 // \ / 540 // \__ Dave ____/ 541 // 542 ctx.openChannel(ctx.carol, ctx.bob, chanAmt) 543 ctx.openChannel(ctx.dave, ctx.bob, chanAmt) 544 ctx.openChannel(ctx.alice, ctx.dave, chanAmt) 545 ctx.openChannel(ctx.eve, ctx.bob, chanAmt) 546 ctx.openChannel(ctx.carol, ctx.eve, chanAmt) 547 548 // Since the channel Alice-> Carol will have to carry two 549 // shards, we make it larger. 550 ctx.openChannel(ctx.alice, ctx.carol, chanAmt+shardAmt) 551 552 defer ctx.closeChannels() 553 554 ctx.waitForChannels() 555 556 // Subscribe to bob's invoices. 557 req := &lnrpc.InvoiceSubscription{} 558 ctxc, cancelSubscription := context.WithCancel(ctxb) 559 bobInvoiceSubscription, err := ctx.bob.SubscribeInvoices(ctxc, req) 560 require.NoError(t.t, err) 561 defer cancelSubscription() 562 563 // We'll send shards along three routes from Alice. 564 sendRoutes := [numShards][]*lntest.HarnessNode{ 565 {ctx.carol, ctx.bob}, 566 {ctx.dave, ctx.bob}, 567 {ctx.carol, ctx.eve, ctx.bob}, 568 } 569 570 payAddr := make([]byte, 32) 571 _, err = rand.Read(payAddr) 572 require.NoError(t.t, err) 573 574 setID := make([]byte, 32) 575 _, err = rand.Read(setID) 576 require.NoError(t.t, err) 577 578 var sharer amp.Sharer 579 sharer, err = amp.NewSeedSharer() 580 require.NoError(t.t, err) 581 582 time.Sleep(time.Second) 583 ctx.alice.LogPrintf("======================== gonna start %s", shardAmt) 584 585 childPreimages := make(map[lntypes.Preimage]uint32) 586 responses := make(chan *lnrpc.HTLCAttempt, len(sendRoutes)) 587 588 // Define a closure for sending each of the three shards. 589 sendShard := func(i int, hops []*lntest.HarnessNode) { 590 // Build a route for the specified hops. 591 r, err := ctx.buildRoute(ctxb, shardAmt, ctx.alice, hops) 592 if err != nil { 593 t.Fatalf("unable to build route: %v", err) 594 } 595 596 // Set the MPP records to indicate this is a payment shard. 597 hop := r.Hops[len(r.Hops)-1] 598 hop.TlvPayload = true 599 hop.MppRecord = &lnrpc.MPPRecord{ 600 PaymentAddr: payAddr, 601 TotalAmtMAtoms: int64(paymentAmt * 1000), 602 } 603 604 var child *amp.Child 605 if i < len(sendRoutes)-1 { 606 var left amp.Sharer 607 left, sharer, err = sharer.Split() 608 require.NoError(t.t, err) 609 610 child = left.Child(uint32(i)) 611 } else { 612 child = sharer.Child(uint32(i)) 613 } 614 childPreimages[child.Preimage] = child.Index 615 616 hop.AmpRecord = &lnrpc.AMPRecord{ 617 RootShare: child.Share[:], 618 SetId: setID, 619 ChildIndex: child.Index, 620 } 621 622 // Send the shard. 623 sendReq := &routerrpc.SendToRouteRequest{ 624 PaymentHash: child.Hash[:], 625 Route: r, 626 } 627 628 // We'll send all shards in their own goroutine, since SendToRoute will 629 // block as long as the payment is in flight. 630 go func() { 631 ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) 632 resp, err := ctx.alice.RouterClient.SendToRouteV2(ctxt, sendReq) 633 if err != nil { 634 t.Fatalf("unable to send payment: %v", err) 635 } 636 637 responses <- resp 638 }() 639 } 640 641 // Send the first shard, this cause Bob to JIT add an invoice. 642 sendShard(0, sendRoutes[0]) 643 644 // Ensure we get a notification of the invoice being added by Bob. 645 rpcInvoice, err := bobInvoiceSubscription.Recv() 646 require.NoError(t.t, err) 647 648 require.False(t.t, rpcInvoice.Settled) // nolint:staticcheck 649 require.Equal(t.t, lnrpc.Invoice_OPEN, rpcInvoice.State) 650 require.Equal(t.t, int64(0), rpcInvoice.AmtPaidAtoms) 651 require.Equal(t.t, int64(0), rpcInvoice.AmtPaidMAtoms) 652 require.Equal(t.t, payAddr, rpcInvoice.PaymentAddr) 653 654 require.Equal(t.t, 0, len(rpcInvoice.Htlcs)) 655 656 sendShard(1, sendRoutes[1]) 657 sendShard(2, sendRoutes[2]) 658 659 // Assert that all of the child preimages are unique. 660 require.Equal(t.t, len(sendRoutes), len(childPreimages)) 661 662 // Make a copy of the childPreimages map for validating the resulting 663 // invoice. 664 childPreimagesCopy := make(map[lntypes.Preimage]uint32) 665 for preimage, childIndex := range childPreimages { 666 childPreimagesCopy[preimage] = childIndex 667 } 668 669 // Wait for all responses to be back, and check that they all 670 // succeeded. 671 for range sendRoutes { 672 var resp *lnrpc.HTLCAttempt 673 select { 674 case resp = <-responses: 675 case <-time.After(defaultTimeout): 676 t.Fatalf("response not received") 677 } 678 679 if resp.Failure != nil { 680 t.Fatalf("received payment failure : %v", resp.Failure) 681 } 682 683 preimage, err := lntypes.MakePreimage(resp.Preimage) 684 require.NoError(t.t, err) 685 686 // Assert that the response includes one of our child preimages. 687 _, ok := childPreimages[preimage] 688 require.True(t.t, ok) 689 690 // Remove this preimage from out set so that we ensure all 691 // responses have a unique child preimage. 692 delete(childPreimages, preimage) 693 } 694 childPreimages = childPreimagesCopy 695 696 // There should now be a settle event for the invoice. 697 rpcInvoice, err = bobInvoiceSubscription.Recv() 698 require.NoError(t.t, err) 699 700 // Also fetch Bob's invoice from ListInvoices and assert it is equal to 701 // the one recevied via the subscription. 702 invoiceResp, err := ctx.bob.ListInvoices( 703 ctxb, &lnrpc.ListInvoiceRequest{}, 704 ) 705 require.NoError(t.t, err) 706 require.Equal(t.t, 1, len(invoiceResp.Invoices)) 707 assertInvoiceEqual(t.t, rpcInvoice, invoiceResp.Invoices[0]) 708 709 // Assert that the invoice is settled for the total payment amount and 710 // has the correct payment address. 711 require.True(t.t, rpcInvoice.Settled) 712 require.Equal(t.t, lnrpc.Invoice_SETTLED, rpcInvoice.State) 713 require.Equal(t.t, int64(paymentAmt), rpcInvoice.AmtPaidAtoms) 714 require.Equal(t.t, int64(paymentAmt*1000), rpcInvoice.AmtPaidMAtoms) 715 require.Equal(t.t, payAddr, rpcInvoice.PaymentAddr) 716 717 // Finally, assert that the proper set id is recorded for each htlc, and 718 // that the preimage hash pair is valid. 719 require.Equal(t.t, numShards, len(rpcInvoice.Htlcs)) 720 for _, htlc := range rpcInvoice.Htlcs { 721 require.NotNil(t.t, htlc.Amp) 722 require.Equal(t.t, setID, htlc.Amp.SetId) 723 724 // Parse the child hash and child preimage, and assert they are 725 // well-formed. 726 childHash, err := lntypes.MakeHash(htlc.Amp.Hash) 727 require.NoError(t.t, err) 728 childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage) 729 require.NoError(t.t, err) 730 731 // Assert that the preimage actually matches the hashes. 732 validPreimage := childPreimage.Matches(childHash) 733 require.True(t.t, validPreimage) 734 735 // Assert that the HTLC includes one of our child preimages. 736 childIndex, ok := childPreimages[childPreimage] 737 require.True(t.t, ok) 738 739 // Assert that the correct child index is reflected. 740 require.Equal(t.t, childIndex, htlc.Amp.ChildIndex) 741 742 // Remove this preimage from our set so that we ensure all HTLCs 743 // have a unique child preimage. 744 delete(childPreimages, childPreimage) 745 } 746 } 747 748 // assertInvoiceEqual asserts that two lnrpc.Invoices are equivalent. A custom 749 // comparison function is defined for these tests, since proto message returned 750 // from unary and streaming RPCs (as of protobuf 1.23.0 and grpc 1.29.1) aren't 751 // consistent with the private fields set on the messages. As a result, we avoid 752 // using require.Equal and test only the actual data members. 753 func assertInvoiceEqual(t *testing.T, a, b *lnrpc.Invoice) { 754 t.Helper() 755 756 // Ensure the HTLCs are sorted properly before attempting to compare. 757 sort.Slice(a.Htlcs, func(i, j int) bool { 758 return a.Htlcs[i].ChanId < a.Htlcs[j].ChanId 759 }) 760 sort.Slice(b.Htlcs, func(i, j int) bool { 761 return b.Htlcs[i].ChanId < b.Htlcs[j].ChanId 762 }) 763 764 require.Equal(t, a.Memo, b.Memo) 765 require.Equal(t, a.RPreimage, b.RPreimage) 766 require.Equal(t, a.RHash, b.RHash) 767 require.Equal(t, a.Value, b.Value) 768 require.Equal(t, a.ValueMAtoms, b.ValueMAtoms) 769 require.Equal(t, a.CreationDate, b.CreationDate) 770 require.Equal(t, a.SettleDate, b.SettleDate) 771 require.Equal(t, a.PaymentRequest, b.PaymentRequest) 772 require.Equal(t, a.DescriptionHash, b.DescriptionHash) 773 require.Equal(t, a.Expiry, b.Expiry) 774 require.Equal(t, a.FallbackAddr, b.FallbackAddr) 775 require.Equal(t, a.CltvExpiry, b.CltvExpiry) 776 require.Equal(t, a.RouteHints, b.RouteHints) 777 require.Equal(t, a.Private, b.Private) 778 require.Equal(t, a.AddIndex, b.AddIndex) 779 require.Equal(t, a.SettleIndex, b.SettleIndex) 780 require.Equal(t, a.AmtPaidAtoms, b.AmtPaidAtoms) 781 require.Equal(t, a.AmtPaidMAtoms, b.AmtPaidMAtoms) 782 require.Equal(t, a.State, b.State) 783 require.Equal(t, a.Features, b.Features) 784 require.Equal(t, a.IsKeysend, b.IsKeysend) 785 require.Equal(t, a.PaymentAddr, b.PaymentAddr) 786 require.Equal(t, a.IsAmp, b.IsAmp) 787 788 require.Equal(t, len(a.Htlcs), len(b.Htlcs)) 789 for i := range a.Htlcs { 790 htlcA, htlcB := a.Htlcs[i], b.Htlcs[i] 791 require.Equal(t, htlcA.ChanId, htlcB.ChanId) 792 require.Equal(t, htlcA.HtlcIndex, htlcB.HtlcIndex) 793 require.Equal(t, htlcA.AmtMAtoms, htlcB.AmtMAtoms) 794 require.Equal(t, htlcA.AcceptHeight, htlcB.AcceptHeight) 795 require.Equal(t, htlcA.AcceptTime, htlcB.AcceptTime) 796 require.Equal(t, htlcA.ResolveTime, htlcB.ResolveTime) 797 require.Equal(t, htlcA.ExpiryHeight, htlcB.ExpiryHeight) 798 require.Equal(t, htlcA.State, htlcB.State) 799 require.Equal(t, htlcA.CustomRecords, htlcB.CustomRecords) 800 require.Equal(t, htlcA.MppTotalAmtMAtoms, htlcB.MppTotalAmtMAtoms) 801 require.Equal(t, htlcA.Amp, htlcB.Amp) 802 } 803 }