itest: refactor testSendPaymentAMPInvoice

This commit is contained in:
yyforyongyu 2022-08-11 04:10:40 +08:00
parent 47c5809081
commit 780f2e84a3
No known key found for this signature in database
GPG key ID: 9BCD95C4FF296868
4 changed files with 79 additions and 89 deletions

View file

@ -393,4 +393,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "send multi path payment", Name: "send multi path payment",
TestFunc: testSendMultiPathPayment, TestFunc: testSendMultiPathPayment,
}, },
{
Name: "sendpayment amp invoice",
TestFunc: testSendPaymentAMPInvoice,
},
} }

View file

@ -14,6 +14,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -21,33 +22,33 @@ import (
// testSendPaymentAMPInvoice tests that we can send an AMP payment to a // testSendPaymentAMPInvoice tests that we can send an AMP payment to a
// specified AMP invoice using SendPaymentV2. // specified AMP invoice using SendPaymentV2.
func testSendPaymentAMPInvoice(net *lntest.NetworkHarness, t *harnessTest) { func testSendPaymentAMPInvoice(ht *lntemp.HarnessTest) {
t.t.Run("native payaddr", func(t *testing.T) { succeed := ht.Run("native payaddr", func(t *testing.T) {
tt := newHarnessTest(t, net) tt := ht.Subtest(t)
testSendPaymentAMPInvoiceCase(net, tt, false) testSendPaymentAMPInvoiceCase(tt, false)
}) })
t.t.Run("external payaddr", func(t *testing.T) {
tt := newHarnessTest(t, net) // Abort the test if failed.
testSendPaymentAMPInvoiceCase(net, tt, true) if !succeed {
return
}
ht.Run("external payaddr", func(t *testing.T) {
tt := ht.Subtest(t)
testSendPaymentAMPInvoiceCase(tt, true)
}) })
} }
func testSendPaymentAMPInvoiceCase(net *lntest.NetworkHarness, t *harnessTest, func testSendPaymentAMPInvoiceCase(ht *lntemp.HarnessTest,
useExternalPayAddr bool) { useExternalPayAddr bool) {
ctxb := context.Background() mts := newMppTestScenario(ht)
ctx := newMppTestContext(t, net)
defer ctx.shutdownNodes()
// Subscribe to bob's invoices. Do this early in the test to make sure // Subscribe to bob's invoices. Do this early in the test to make sure
// that the subscription has actually been completed when we add an // that the subscription has actually been completed when we add an
// invoice. Otherwise the notification will be missed. // invoice. Otherwise the notification will be missed.
req := &lnrpc.InvoiceSubscription{} req := &lnrpc.InvoiceSubscription{}
ctxc, cancelSubscription := context.WithCancel(ctxb) bobInvoiceSubscription := mts.bob.RPC.SubscribeInvoices(req)
bobInvoiceSubscription, err := ctx.bob.SubscribeInvoices(ctxc, req)
require.NoError(t.t, err)
defer cancelSubscription()
const paymentAmt = btcutil.Amount(300000) const paymentAmt = btcutil.Amount(300000)
@ -61,49 +62,45 @@ func testSendPaymentAMPInvoiceCase(net *lntest.NetworkHarness, t *harnessTest,
// \ / // \ /
// \__ Dave ____/ // \__ Dave ____/
// //
ctx.openChannel(ctx.carol, ctx.bob, 135000) mppReq := &mppOpenChannelRequest{
ctx.openChannel(ctx.alice, ctx.carol, 235000) amtAliceCarol: 235000,
ctx.openChannel(ctx.dave, ctx.bob, 135000) amtAliceDave: 135000,
ctx.openChannel(ctx.alice, ctx.dave, 135000) amtCarolBob: 135000,
ctx.openChannel(ctx.eve, ctx.bob, 135000) amtCarolEve: 135000,
ctx.openChannel(ctx.carol, ctx.eve, 135000) amtDaveBob: 135000,
amtEveBob: 135000,
}
mts.openChannels(mppReq)
chanPointAliceDave := mts.channelPoints[1]
chanPointDaveBob := mts.channelPoints[4]
defer ctx.closeChannels() invoice := &lnrpc.Invoice{
ctx.waitForChannels()
addInvoiceResp, err := ctx.bob.AddInvoice(context.Background(), &lnrpc.Invoice{
Value: int64(paymentAmt), Value: int64(paymentAmt),
IsAmp: true, IsAmp: true,
}) }
require.NoError(t.t, err) addInvoiceResp := mts.bob.RPC.AddInvoice(invoice)
// Ensure we get a notification of the invoice being added by Bob. // Ensure we get a notification of the invoice being added by Bob.
rpcInvoice, err := bobInvoiceSubscription.Recv() rpcInvoice := ht.ReceiveInvoiceUpdate(bobInvoiceSubscription)
require.NoError(t.t, err)
require.False(t.t, rpcInvoice.Settled) // nolint:staticcheck require.False(ht, rpcInvoice.Settled) // nolint:staticcheck
require.Equal(t.t, lnrpc.Invoice_OPEN, rpcInvoice.State) require.Equal(ht, lnrpc.Invoice_OPEN, rpcInvoice.State)
require.Equal(t.t, int64(0), rpcInvoice.AmtPaidSat) require.Equal(ht, int64(0), rpcInvoice.AmtPaidSat)
require.Equal(t.t, int64(0), rpcInvoice.AmtPaidMsat) require.Equal(ht, int64(0), rpcInvoice.AmtPaidMsat)
require.Equal(ht, 0, len(rpcInvoice.Htlcs))
require.Equal(t.t, 0, len(rpcInvoice.Htlcs))
// Increase Dave's fee to make the test deterministic. Otherwise it // Increase Dave's fee to make the test deterministic. Otherwise it
// would be unpredictable whether pathfinding would go through Charlie // would be unpredictable whether pathfinding would go through Charlie
// or Dave for the first shard. // or Dave for the first shard.
_, err = ctx.dave.UpdateChannelPolicy( expectedPolicy := mts.updateDaveGlobalPolicy()
context.Background(),
&lnrpc.PolicyUpdateRequest{ // Make sure Alice has heard it for both Dave's channels.
Scope: &lnrpc.PolicyUpdateRequest_Global{Global: true}, ht.AssertChannelPolicyUpdate(
BaseFeeMsat: 500000, mts.alice, mts.dave, expectedPolicy, chanPointAliceDave, false,
FeeRate: 0.001, )
TimeLockDelta: 40, ht.AssertChannelPolicyUpdate(
}, mts.alice, mts.dave, expectedPolicy, chanPointDaveBob, false,
) )
if err != nil {
t.Fatalf("dave policy update: %v", err)
}
// Generate an external payment address when attempting to pseudo-reuse // Generate an external payment address when attempting to pseudo-reuse
// an AMP invoice. When using an external payment address, we'll also // an AMP invoice. When using an external payment address, we'll also
@ -116,19 +113,16 @@ func testSendPaymentAMPInvoiceCase(net *lntest.NetworkHarness, t *harnessTest,
) )
if useExternalPayAddr { if useExternalPayAddr {
expNumInvoices = 2 expNumInvoices = 2
externalPayAddr = make([]byte, 32) externalPayAddr = ht.Random32Bytes()
_, err = rand.Read(externalPayAddr)
require.NoError(t.t, err)
} }
payment := sendAndAssertSuccess( sendReq := &routerrpc.SendPaymentRequest{
t, ctx.alice, &routerrpc.SendPaymentRequest{ PaymentRequest: addInvoiceResp.PaymentRequest,
PaymentRequest: addInvoiceResp.PaymentRequest, PaymentAddr: externalPayAddr,
PaymentAddr: externalPayAddr, TimeoutSeconds: 60,
TimeoutSeconds: 60, FeeLimitMsat: noFeeLimitMsat,
FeeLimitMsat: noFeeLimitMsat, }
}, payment := ht.SendPaymentAssertSettled(mts.alice, sendReq)
)
// Check that Alice split the payment in at least three shards. Because // 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), // the hand-off of the htlc to the link is asynchronous (via a mailbox),
@ -145,67 +139,62 @@ func testSendPaymentAMPInvoiceCase(net *lntest.NetworkHarness, t *harnessTest,
} }
const minExpectedShards = 3 const minExpectedShards = 3
if succeeded < minExpectedShards { require.GreaterOrEqual(ht, succeeded, minExpectedShards,
t.Fatalf("expected at least %v shards, but got %v", "expected num of shards not reached")
minExpectedShards, succeeded)
}
// When an external payment address is supplied, we'll get an extra // When an external payment address is supplied, we'll get an extra
// notification for the JIT inserted invoice, since it differs from the // notification for the JIT inserted invoice, since it differs from the
// original. // original.
if useExternalPayAddr { if useExternalPayAddr {
_, err = bobInvoiceSubscription.Recv() ht.ReceiveInvoiceUpdate(bobInvoiceSubscription)
require.NoError(t.t, err)
} }
// There should now be a settle event for the invoice. // There should now be a settle event for the invoice.
rpcInvoice, err = bobInvoiceSubscription.Recv() rpcInvoice = ht.ReceiveInvoiceUpdate(bobInvoiceSubscription)
require.NoError(t.t, err)
// Also fetch Bob's invoice from ListInvoices and assert it is equal to // Also fetch Bob's invoice from ListInvoices and assert it is equal to
// the one received via the subscription. // the one received via the subscription.
invoiceResp, err := ctx.bob.ListInvoices( invoices := ht.AssertNumInvoices(mts.bob, expNumInvoices)
ctxb, &lnrpc.ListInvoiceRequest{}, assertInvoiceEqual(ht.T, rpcInvoice, invoices[expNumInvoices-1])
)
require.NoError(t.t, err)
require.Equal(t.t, expNumInvoices, len(invoiceResp.Invoices))
assertInvoiceEqual(t.t, rpcInvoice, invoiceResp.Invoices[expNumInvoices-1])
// Assert that the invoice is settled for the total payment amount and // Assert that the invoice is settled for the total payment amount and
// has the correct payment address. // has the correct payment address.
require.True(t.t, rpcInvoice.Settled) // nolint:staticcheck require.True(ht, rpcInvoice.Settled) // nolint:staticcheck
require.Equal(t.t, lnrpc.Invoice_SETTLED, rpcInvoice.State) require.Equal(ht, lnrpc.Invoice_SETTLED, rpcInvoice.State)
require.Equal(t.t, int64(paymentAmt), rpcInvoice.AmtPaidSat) require.Equal(ht, int64(paymentAmt), rpcInvoice.AmtPaidSat)
require.Equal(t.t, int64(paymentAmt*1000), rpcInvoice.AmtPaidMsat) require.Equal(ht, int64(paymentAmt*1000), rpcInvoice.AmtPaidMsat)
// Finally, assert that the same set id is recorded for each htlc, and // Finally, assert that the same set id is recorded for each htlc, and
// that the preimage hash pair is valid. // that the preimage hash pair is valid.
var setID []byte var setID []byte
require.Equal(t.t, succeeded, len(rpcInvoice.Htlcs)) require.Equal(ht, succeeded, len(rpcInvoice.Htlcs))
for _, htlc := range rpcInvoice.Htlcs { for _, htlc := range rpcInvoice.Htlcs {
require.NotNil(t.t, htlc.Amp) require.NotNil(ht, htlc.Amp)
if setID == nil { if setID == nil {
setID = make([]byte, 32) setID = make([]byte, 32)
copy(setID, htlc.Amp.SetId) copy(setID, htlc.Amp.SetId)
} }
require.Equal(t.t, setID, htlc.Amp.SetId) require.Equal(ht, setID, htlc.Amp.SetId)
// Parse the child hash and child preimage, and assert they are // Parse the child hash and child preimage, and assert they are
// well-formed. // well-formed.
childHash, err := lntypes.MakeHash(htlc.Amp.Hash) childHash, err := lntypes.MakeHash(htlc.Amp.Hash)
require.NoError(t.t, err) require.NoError(ht, err)
childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage) childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage)
require.NoError(t.t, err) require.NoError(ht, err)
// Assert that the preimage actually matches the hashes. // Assert that the preimage actually matches the hashes.
validPreimage := childPreimage.Matches(childHash) validPreimage := childPreimage.Matches(childHash)
require.True(t.t, validPreimage) require.True(ht, validPreimage)
} }
// The set ID we extract above should be shown in the final settled // The set ID we extract above should be shown in the final settled
// state. // state.
ampState := rpcInvoice.AmpInvoiceState[hex.EncodeToString(setID)] ampState := rpcInvoice.AmpInvoiceState[hex.EncodeToString(setID)]
require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State) require.Equal(ht, lnrpc.InvoiceHTLCState_SETTLED, ampState.State)
// Finally, close all channels.
mts.closeChannels()
} }
// testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP // testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP

View file

@ -488,7 +488,8 @@ func (m *mppTestScenario) buildRoute(amt btcutil.Amount,
} }
// updatePolicy updates a Dave's global channel policy and returns the expected // updatePolicy updates a Dave's global channel policy and returns the expected
// policy for further check. // policy for further check. It changes Dave's `FeeBaseMsat` from 1000 msat to
// 500,000 msat, and `FeeProportionalMillonths` from 1 msat to 1000 msat.
func (m *mppTestScenario) updateDaveGlobalPolicy() *lnrpc.RoutingPolicy { func (m *mppTestScenario) updateDaveGlobalPolicy() *lnrpc.RoutingPolicy {
const ( const (
baseFeeMsat = 500_000 baseFeeMsat = 500_000

View file

@ -48,10 +48,6 @@ var allTestCases = []*testCase{
name: "sendpayment amp", name: "sendpayment amp",
test: testSendPaymentAMP, test: testSendPaymentAMP,
}, },
{
name: "sendpayment amp invoice",
test: testSendPaymentAMPInvoice,
},
{ {
name: "sendpayment amp invoice repeat", name: "sendpayment amp invoice repeat",
test: testSendPaymentAMPInvoiceRepeat, test: testSendPaymentAMPInvoiceRepeat,