mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 18:10:34 +01:00
116 lines
3.4 KiB
Go
116 lines
3.4 KiB
Go
package itest
|
|
|
|
import (
|
|
"encoding/hex"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
|
"github.com/lightningnetwork/lnd/lntest"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// testSendMultiPathPayment tests that we are able to successfully route a
|
|
// payment using multiple shards across different paths.
|
|
func testSendMultiPathPayment(ht *lntest.HarnessTest) {
|
|
mts := newMppTestScenario(ht)
|
|
|
|
const paymentAmt = btcutil.Amount(300000)
|
|
|
|
// Set up a network with three different paths Alice <-> Bob. Channel
|
|
// capacities are set such that the payment can only succeed if (at
|
|
// least) three paths are used.
|
|
//
|
|
// _ Eve _
|
|
// / \
|
|
// Alice -- Carol ---- Bob
|
|
// \ /
|
|
// \__ Dave ____/
|
|
//
|
|
req := &mppOpenChannelRequest{
|
|
amtAliceCarol: 285000,
|
|
amtAliceDave: 155000,
|
|
amtCarolBob: 200000,
|
|
amtCarolEve: 155000,
|
|
amtDaveBob: 155000,
|
|
amtEveBob: 155000,
|
|
}
|
|
mts.openChannels(req)
|
|
chanPointAliceDave := mts.channelPoints[1]
|
|
|
|
// Increase Dave's fee to make the test deterministic. Otherwise, it
|
|
// would be unpredictable whether pathfinding would go through Charlie
|
|
// or Dave for the first shard.
|
|
expectedPolicy := &lnrpc.RoutingPolicy{
|
|
FeeBaseMsat: 500_000,
|
|
FeeRateMilliMsat: int64(0.001 * 1_000_000),
|
|
TimeLockDelta: 40,
|
|
MinHtlc: 1000, // default value
|
|
MaxHtlcMsat: 133_650_000,
|
|
}
|
|
mts.dave.UpdateGlobalPolicy(expectedPolicy)
|
|
|
|
// Make sure Alice has heard it.
|
|
ht.AssertChannelPolicyUpdate(
|
|
mts.alice, mts.dave, expectedPolicy, chanPointAliceDave, false,
|
|
)
|
|
|
|
// Our first test will be Alice paying Bob using a SendPayment call.
|
|
// Let Bob create an invoice for Alice to pay.
|
|
payReqs, rHashes, invoices := ht.CreatePayReqs(mts.bob, paymentAmt, 1)
|
|
|
|
rHash := rHashes[0]
|
|
payReq := payReqs[0]
|
|
|
|
sendReq := &routerrpc.SendPaymentRequest{
|
|
PaymentRequest: payReq,
|
|
MaxParts: 10,
|
|
TimeoutSeconds: 60,
|
|
FeeLimitMsat: noFeeLimitMsat,
|
|
}
|
|
payment := ht.SendPaymentAssertSettled(mts.alice, sendReq)
|
|
|
|
// Make sure we got the preimage.
|
|
require.Equal(ht, hex.EncodeToString(invoices[0].RPreimage),
|
|
payment.PaymentPreimage, "preimage doesn't match")
|
|
|
|
// Check that Alice split the payment in at least three shards. Because
|
|
// the hand-off of the htlc to the link is asynchronous (via a mailbox),
|
|
// there is some non-determinism in the process. Depending on whether
|
|
// the new pathfinding round is started before or after the htlc is
|
|
// locked into the channel, different sharding may occur. Therefore we
|
|
// can only check if the number of shards isn't below the theoretical
|
|
// minimum.
|
|
succeeded := 0
|
|
for _, htlc := range payment.Htlcs {
|
|
if htlc.Status == lnrpc.HTLCAttempt_SUCCEEDED {
|
|
succeeded++
|
|
}
|
|
}
|
|
|
|
const minExpectedShards = 3
|
|
require.GreaterOrEqual(ht, succeeded, minExpectedShards,
|
|
"expected shards not reached")
|
|
|
|
// Make sure Bob show the invoice as settled for the full amount.
|
|
inv := mts.bob.RPC.LookupInvoice(rHash)
|
|
|
|
require.EqualValues(ht, paymentAmt, inv.AmtPaidSat,
|
|
"incorrect payment amt")
|
|
|
|
require.Equal(ht, lnrpc.Invoice_SETTLED, inv.State,
|
|
"Invoice not settled")
|
|
|
|
settled := 0
|
|
for _, htlc := range inv.Htlcs {
|
|
if htlc.State == lnrpc.InvoiceHTLCState_SETTLED {
|
|
settled++
|
|
}
|
|
}
|
|
require.Equal(ht, succeeded, settled,
|
|
"num of HTLCs wrong")
|
|
|
|
// Finally, close all channels.
|
|
mts.closeChannels()
|
|
}
|