mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-19 05:45:21 +01:00
lntemp+itest: refactor testSendToRouteAMP
This commit is contained in:
parent
44b9068de5
commit
707d888aa4
@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -2077,3 +2078,58 @@ func (h *HarnessTest) ReceiveSendToRouteUpdate(
|
|||||||
return updateMsg, nil
|
return updateMsg, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertInvoiceEqual asserts that two lnrpc.Invoices are equivalent. A custom
|
||||||
|
// comparison function is defined for these tests, since proto message returned
|
||||||
|
// from unary and streaming RPCs (as of protobuf 1.23.0 and grpc 1.29.1) aren't
|
||||||
|
// consistent with the private fields set on the messages. As a result, we
|
||||||
|
// avoid using require.Equal and test only the actual data members.
|
||||||
|
func (h *HarnessTest) AssertInvoiceEqual(a, b *lnrpc.Invoice) {
|
||||||
|
// Ensure the HTLCs are sorted properly before attempting to compare.
|
||||||
|
sort.Slice(a.Htlcs, func(i, j int) bool {
|
||||||
|
return a.Htlcs[i].ChanId < a.Htlcs[j].ChanId
|
||||||
|
})
|
||||||
|
sort.Slice(b.Htlcs, func(i, j int) bool {
|
||||||
|
return b.Htlcs[i].ChanId < b.Htlcs[j].ChanId
|
||||||
|
})
|
||||||
|
|
||||||
|
require.Equal(h, a.Memo, b.Memo)
|
||||||
|
require.Equal(h, a.RPreimage, b.RPreimage)
|
||||||
|
require.Equal(h, a.RHash, b.RHash)
|
||||||
|
require.Equal(h, a.Value, b.Value)
|
||||||
|
require.Equal(h, a.ValueMsat, b.ValueMsat)
|
||||||
|
require.Equal(h, a.CreationDate, b.CreationDate)
|
||||||
|
require.Equal(h, a.SettleDate, b.SettleDate)
|
||||||
|
require.Equal(h, a.PaymentRequest, b.PaymentRequest)
|
||||||
|
require.Equal(h, a.DescriptionHash, b.DescriptionHash)
|
||||||
|
require.Equal(h, a.Expiry, b.Expiry)
|
||||||
|
require.Equal(h, a.FallbackAddr, b.FallbackAddr)
|
||||||
|
require.Equal(h, a.CltvExpiry, b.CltvExpiry)
|
||||||
|
require.Equal(h, a.RouteHints, b.RouteHints)
|
||||||
|
require.Equal(h, a.Private, b.Private)
|
||||||
|
require.Equal(h, a.AddIndex, b.AddIndex)
|
||||||
|
require.Equal(h, a.SettleIndex, b.SettleIndex)
|
||||||
|
require.Equal(h, a.AmtPaidSat, b.AmtPaidSat)
|
||||||
|
require.Equal(h, a.AmtPaidMsat, b.AmtPaidMsat)
|
||||||
|
require.Equal(h, a.State, b.State)
|
||||||
|
require.Equal(h, a.Features, b.Features)
|
||||||
|
require.Equal(h, a.IsKeysend, b.IsKeysend)
|
||||||
|
require.Equal(h, a.PaymentAddr, b.PaymentAddr)
|
||||||
|
require.Equal(h, a.IsAmp, b.IsAmp)
|
||||||
|
|
||||||
|
require.Equal(h, len(a.Htlcs), len(b.Htlcs))
|
||||||
|
for i := range a.Htlcs {
|
||||||
|
htlcA, htlcB := a.Htlcs[i], b.Htlcs[i]
|
||||||
|
require.Equal(h, htlcA.ChanId, htlcB.ChanId)
|
||||||
|
require.Equal(h, htlcA.HtlcIndex, htlcB.HtlcIndex)
|
||||||
|
require.Equal(h, htlcA.AmtMsat, htlcB.AmtMsat)
|
||||||
|
require.Equal(h, htlcA.AcceptHeight, htlcB.AcceptHeight)
|
||||||
|
require.Equal(h, htlcA.AcceptTime, htlcB.AcceptTime)
|
||||||
|
require.Equal(h, htlcA.ResolveTime, htlcB.ResolveTime)
|
||||||
|
require.Equal(h, htlcA.ExpiryHeight, htlcB.ExpiryHeight)
|
||||||
|
require.Equal(h, htlcA.State, htlcB.State)
|
||||||
|
require.Equal(h, htlcA.CustomRecords, htlcB.CustomRecords)
|
||||||
|
require.Equal(h, htlcA.MppTotalAmtMsat, htlcB.MppTotalAmtMsat)
|
||||||
|
require.Equal(h, htlcA.Amp, htlcB.Amp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -405,4 +405,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "send payment amp",
|
Name: "send payment amp",
|
||||||
TestFunc: testSendPaymentAMP,
|
TestFunc: testSendPaymentAMP,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "sendtoroute amp",
|
||||||
|
TestFunc: testSendToRouteAMP,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package itest
|
package itest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"sort"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -15,7 +12,7 @@ import (
|
|||||||
"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/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -155,7 +152,7 @@ func testSendPaymentAMPInvoiceCase(ht *lntemp.HarnessTest,
|
|||||||
// 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.
|
||||||
invoices := ht.AssertNumInvoices(mts.bob, expNumInvoices)
|
invoices := ht.AssertNumInvoices(mts.bob, expNumInvoices)
|
||||||
assertInvoiceEqual(ht.T, rpcInvoice, invoices[expNumInvoices-1])
|
ht.AssertInvoiceEqual(rpcInvoice, 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.
|
||||||
@ -463,12 +460,8 @@ func testSendPaymentAMP(ht *lntemp.HarnessTest) {
|
|||||||
mts.closeChannels()
|
mts.closeChannels()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
func testSendToRouteAMP(ht *lntemp.HarnessTest) {
|
||||||
ctxb := context.Background()
|
mts := newMppTestScenario(ht)
|
||||||
|
|
||||||
ctx := newMppTestContext(t, net)
|
|
||||||
defer ctx.shutdownNodes()
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
paymentAmt = btcutil.Amount(300000)
|
paymentAmt = btcutil.Amount(300000)
|
||||||
numShards = 3
|
numShards = 3
|
||||||
@ -476,63 +469,50 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
chanAmt = shardAmt * 3 / 2
|
chanAmt = shardAmt * 3 / 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Subscribe to bob's invoices.
|
||||||
|
req := &lnrpc.InvoiceSubscription{}
|
||||||
|
bobInvoiceSubscription := mts.bob.RPC.SubscribeInvoices(req)
|
||||||
|
|
||||||
// Set up a network with three different paths Alice <-> Bob.
|
// Set up a network with three different paths Alice <-> Bob.
|
||||||
// _ Eve _
|
// _ Eve _
|
||||||
// / \
|
// / \
|
||||||
// Alice -- Carol ---- Bob
|
// Alice -- Carol ---- Bob
|
||||||
// \ /
|
// \ /
|
||||||
// \__ Dave ____/
|
// \__ Dave ____/
|
||||||
//
|
///
|
||||||
ctx.openChannel(ctx.carol, ctx.bob, chanAmt)
|
mppReq := &mppOpenChannelRequest{
|
||||||
ctx.openChannel(ctx.dave, ctx.bob, chanAmt)
|
// Since the channel Alice-> Carol will have to carry two
|
||||||
ctx.openChannel(ctx.alice, ctx.dave, chanAmt)
|
// shards, we make it larger.
|
||||||
ctx.openChannel(ctx.eve, ctx.bob, chanAmt)
|
amtAliceCarol: chanAmt + shardAmt,
|
||||||
ctx.openChannel(ctx.carol, ctx.eve, chanAmt)
|
amtAliceDave: chanAmt,
|
||||||
|
amtCarolBob: chanAmt,
|
||||||
// Since the channel Alice-> Carol will have to carry two
|
amtCarolEve: chanAmt,
|
||||||
// shards, we make it larger.
|
amtDaveBob: chanAmt,
|
||||||
ctx.openChannel(ctx.alice, ctx.carol, chanAmt+shardAmt)
|
amtEveBob: chanAmt,
|
||||||
|
}
|
||||||
defer ctx.closeChannels()
|
mts.openChannels(mppReq)
|
||||||
|
|
||||||
ctx.waitForChannels()
|
|
||||||
|
|
||||||
// Subscribe to bob's invoices.
|
|
||||||
req := &lnrpc.InvoiceSubscription{}
|
|
||||||
ctxc, cancelSubscription := context.WithCancel(ctxb)
|
|
||||||
bobInvoiceSubscription, err := ctx.bob.SubscribeInvoices(ctxc, req)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
defer cancelSubscription()
|
|
||||||
|
|
||||||
// We'll send shards along three routes from Alice.
|
// We'll send shards along three routes from Alice.
|
||||||
sendRoutes := [numShards][]*lntest.HarnessNode{
|
sendRoutes := [numShards][]*node.HarnessNode{
|
||||||
{ctx.carol, ctx.bob},
|
{mts.carol, mts.bob},
|
||||||
{ctx.dave, ctx.bob},
|
{mts.dave, mts.bob},
|
||||||
{ctx.carol, ctx.eve, ctx.bob},
|
{mts.carol, mts.eve, mts.bob},
|
||||||
}
|
}
|
||||||
|
|
||||||
payAddr := make([]byte, 32)
|
payAddr := ht.Random32Bytes()
|
||||||
_, err = rand.Read(payAddr)
|
setID := ht.Random32Bytes()
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
setID := make([]byte, 32)
|
|
||||||
_, err = rand.Read(setID)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
var sharer amp.Sharer
|
var sharer amp.Sharer
|
||||||
sharer, err = amp.NewSeedSharer()
|
sharer, err := amp.NewSeedSharer()
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, err)
|
||||||
|
|
||||||
childPreimages := make(map[lntypes.Preimage]uint32)
|
childPreimages := make(map[lntypes.Preimage]uint32)
|
||||||
responses := make(chan *lnrpc.HTLCAttempt, len(sendRoutes))
|
responses := make(chan *lnrpc.HTLCAttempt, len(sendRoutes))
|
||||||
|
|
||||||
// Define a closure for sending each of the three shards.
|
// Define a closure for sending each of the three shards.
|
||||||
sendShard := func(i int, hops []*lntest.HarnessNode) {
|
sendShard := func(i int, hops []*node.HarnessNode) {
|
||||||
// Build a route for the specified hops.
|
// Build a route for the specified hops.
|
||||||
r, err := ctx.buildRoute(ctxb, shardAmt, ctx.alice, hops)
|
r := mts.buildRoute(shardAmt, mts.alice, hops)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to build route: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the MPP records to indicate this is a payment shard.
|
// Set the MPP records to indicate this is a payment shard.
|
||||||
hop := r.Hops[len(r.Hops)-1]
|
hop := r.Hops[len(r.Hops)-1]
|
||||||
@ -546,7 +526,7 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
if i < len(sendRoutes)-1 {
|
if i < len(sendRoutes)-1 {
|
||||||
var left amp.Sharer
|
var left amp.Sharer
|
||||||
left, sharer, err = sharer.Split()
|
left, sharer, err = sharer.Split()
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, err)
|
||||||
|
|
||||||
child = left.Child(uint32(i))
|
child = left.Child(uint32(i))
|
||||||
} else {
|
} else {
|
||||||
@ -566,15 +546,10 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
Route: r,
|
Route: r,
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll send all shards in their own goroutine, since SendToRoute will
|
// We'll send all shards in their own goroutine, since
|
||||||
// block as long as the payment is in flight.
|
// SendToRoute will block as long as the payment is in flight.
|
||||||
go func() {
|
go func() {
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
resp := mts.alice.RPC.SendToRouteV2(sendReq)
|
||||||
resp, err := ctx.alice.RouterClient.SendToRouteV2(ctxt, sendReq)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to send payment: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
responses <- resp
|
responses <- resp
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -584,21 +559,21 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// 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, err := bobInvoiceSubscription.Recv()
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, 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(t.t, payAddr, rpcInvoice.PaymentAddr)
|
require.Equal(ht, payAddr, rpcInvoice.PaymentAddr)
|
||||||
|
|
||||||
require.Equal(t.t, 0, len(rpcInvoice.Htlcs))
|
require.Equal(ht, 0, len(rpcInvoice.Htlcs))
|
||||||
|
|
||||||
sendShard(1, sendRoutes[1])
|
sendShard(1, sendRoutes[1])
|
||||||
sendShard(2, sendRoutes[2])
|
sendShard(2, sendRoutes[2])
|
||||||
|
|
||||||
// Assert that all of the child preimages are unique.
|
// Assert that all of the child preimages are unique.
|
||||||
require.Equal(t.t, len(sendRoutes), len(childPreimages))
|
require.Equal(ht, len(sendRoutes), len(childPreimages))
|
||||||
|
|
||||||
// Make a copy of the childPreimages map for validating the resulting
|
// Make a copy of the childPreimages map for validating the resulting
|
||||||
// invoice.
|
// invoice.
|
||||||
@ -609,24 +584,23 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// Wait for all responses to be back, and check that they all
|
// Wait for all responses to be back, and check that they all
|
||||||
// succeeded.
|
// succeeded.
|
||||||
|
timer := time.After(defaultTimeout)
|
||||||
for range sendRoutes {
|
for range sendRoutes {
|
||||||
var resp *lnrpc.HTLCAttempt
|
var resp *lnrpc.HTLCAttempt
|
||||||
select {
|
select {
|
||||||
case resp = <-responses:
|
case resp = <-responses:
|
||||||
case <-time.After(defaultTimeout):
|
case <-timer:
|
||||||
t.Fatalf("response not received")
|
require.Fail(ht, "response not received")
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Failure != nil {
|
require.Nil(ht, resp.Failure, "received payment failure")
|
||||||
t.Fatalf("received payment failure : %v", resp.Failure)
|
|
||||||
}
|
|
||||||
|
|
||||||
preimage, err := lntypes.MakePreimage(resp.Preimage)
|
preimage, err := lntypes.MakePreimage(resp.Preimage)
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, err)
|
||||||
|
|
||||||
// Assert that the response includes one of our child preimages.
|
// Assert that the response includes one of our child preimages.
|
||||||
_, ok := childPreimages[preimage]
|
_, ok := childPreimages[preimage]
|
||||||
require.True(t.t, ok)
|
require.True(ht, ok)
|
||||||
|
|
||||||
// Remove this preimage from out set so that we ensure all
|
// Remove this preimage from out set so that we ensure all
|
||||||
// responses have a unique child preimage.
|
// responses have a unique child preimage.
|
||||||
@ -636,109 +610,51 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// 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, err = bobInvoiceSubscription.Recv()
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, 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, 1)
|
||||||
ctxb, &lnrpc.ListInvoiceRequest{},
|
ht.AssertInvoiceEqual(rpcInvoice, invoices[0])
|
||||||
)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
require.Equal(t.t, 1, len(invoiceResp.Invoices))
|
|
||||||
assertInvoiceEqual(t.t, rpcInvoice, invoiceResp.Invoices[0])
|
|
||||||
|
|
||||||
// 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)
|
||||||
require.Equal(t.t, payAddr, rpcInvoice.PaymentAddr)
|
require.Equal(ht, payAddr, rpcInvoice.PaymentAddr)
|
||||||
|
|
||||||
// Finally, assert that the proper set id is recorded for each htlc, and
|
// Finally, assert that the proper set id is recorded for each htlc, and
|
||||||
// that the preimage hash pair is valid.
|
// that the preimage hash pair is valid.
|
||||||
require.Equal(t.t, numShards, len(rpcInvoice.Htlcs))
|
require.Equal(ht, numShards, len(rpcInvoice.Htlcs))
|
||||||
for _, htlc := range rpcInvoice.Htlcs {
|
for _, htlc := range rpcInvoice.Htlcs {
|
||||||
require.NotNil(t.t, htlc.Amp)
|
require.NotNil(ht, htlc.Amp)
|
||||||
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)
|
||||||
|
|
||||||
// Assert that the HTLC includes one of our child preimages.
|
// Assert that the HTLC includes one of our child preimages.
|
||||||
childIndex, ok := childPreimages[childPreimage]
|
childIndex, ok := childPreimages[childPreimage]
|
||||||
require.True(t.t, ok)
|
require.True(ht, ok)
|
||||||
|
|
||||||
// Assert that the correct child index is reflected.
|
// Assert that the correct child index is reflected.
|
||||||
require.Equal(t.t, childIndex, htlc.Amp.ChildIndex)
|
require.Equal(ht, childIndex, htlc.Amp.ChildIndex)
|
||||||
|
|
||||||
// Remove this preimage from our set so that we ensure all HTLCs
|
// Remove this preimage from our set so that we ensure all HTLCs
|
||||||
// have a unique child preimage.
|
// have a unique child preimage.
|
||||||
delete(childPreimages, childPreimage)
|
delete(childPreimages, childPreimage)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Finally, close all channels.
|
||||||
// assertInvoiceEqual asserts that two lnrpc.Invoices are equivalent. A custom
|
mts.closeChannels()
|
||||||
// comparison function is defined for these tests, since proto message returned
|
|
||||||
// from unary and streaming RPCs (as of protobuf 1.23.0 and grpc 1.29.1) aren't
|
|
||||||
// consistent with the private fields set on the messages. As a result, we avoid
|
|
||||||
// using require.Equal and test only the actual data members.
|
|
||||||
func assertInvoiceEqual(t *testing.T, a, b *lnrpc.Invoice) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
// Ensure the HTLCs are sorted properly before attempting to compare.
|
|
||||||
sort.Slice(a.Htlcs, func(i, j int) bool {
|
|
||||||
return a.Htlcs[i].ChanId < a.Htlcs[j].ChanId
|
|
||||||
})
|
|
||||||
sort.Slice(b.Htlcs, func(i, j int) bool {
|
|
||||||
return b.Htlcs[i].ChanId < b.Htlcs[j].ChanId
|
|
||||||
})
|
|
||||||
|
|
||||||
require.Equal(t, a.Memo, b.Memo)
|
|
||||||
require.Equal(t, a.RPreimage, b.RPreimage)
|
|
||||||
require.Equal(t, a.RHash, b.RHash)
|
|
||||||
require.Equal(t, a.Value, b.Value)
|
|
||||||
require.Equal(t, a.ValueMsat, b.ValueMsat)
|
|
||||||
require.Equal(t, a.CreationDate, b.CreationDate)
|
|
||||||
require.Equal(t, a.SettleDate, b.SettleDate)
|
|
||||||
require.Equal(t, a.PaymentRequest, b.PaymentRequest)
|
|
||||||
require.Equal(t, a.DescriptionHash, b.DescriptionHash)
|
|
||||||
require.Equal(t, a.Expiry, b.Expiry)
|
|
||||||
require.Equal(t, a.FallbackAddr, b.FallbackAddr)
|
|
||||||
require.Equal(t, a.CltvExpiry, b.CltvExpiry)
|
|
||||||
require.Equal(t, a.RouteHints, b.RouteHints)
|
|
||||||
require.Equal(t, a.Private, b.Private)
|
|
||||||
require.Equal(t, a.AddIndex, b.AddIndex)
|
|
||||||
require.Equal(t, a.SettleIndex, b.SettleIndex)
|
|
||||||
require.Equal(t, a.AmtPaidSat, b.AmtPaidSat)
|
|
||||||
require.Equal(t, a.AmtPaidMsat, b.AmtPaidMsat)
|
|
||||||
require.Equal(t, a.State, b.State)
|
|
||||||
require.Equal(t, a.Features, b.Features)
|
|
||||||
require.Equal(t, a.IsKeysend, b.IsKeysend)
|
|
||||||
require.Equal(t, a.PaymentAddr, b.PaymentAddr)
|
|
||||||
require.Equal(t, a.IsAmp, b.IsAmp)
|
|
||||||
|
|
||||||
require.Equal(t, len(a.Htlcs), len(b.Htlcs))
|
|
||||||
for i := range a.Htlcs {
|
|
||||||
htlcA, htlcB := a.Htlcs[i], b.Htlcs[i]
|
|
||||||
require.Equal(t, htlcA.ChanId, htlcB.ChanId)
|
|
||||||
require.Equal(t, htlcA.HtlcIndex, htlcB.HtlcIndex)
|
|
||||||
require.Equal(t, htlcA.AmtMsat, htlcB.AmtMsat)
|
|
||||||
require.Equal(t, htlcA.AcceptHeight, htlcB.AcceptHeight)
|
|
||||||
require.Equal(t, htlcA.AcceptTime, htlcB.AcceptTime)
|
|
||||||
require.Equal(t, htlcA.ResolveTime, htlcB.ResolveTime)
|
|
||||||
require.Equal(t, htlcA.ExpiryHeight, htlcB.ExpiryHeight)
|
|
||||||
require.Equal(t, htlcA.State, htlcB.State)
|
|
||||||
require.Equal(t, htlcA.CustomRecords, htlcB.CustomRecords)
|
|
||||||
require.Equal(t, htlcA.MppTotalAmtMsat, htlcB.MppTotalAmtMsat)
|
|
||||||
require.Equal(t, htlcA.Amp, htlcB.Amp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
package itest
|
package itest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/wire"
|
|
||||||
"github.com/lightningnetwork/lnd/chainreg"
|
"github.com/lightningnetwork/lnd/chainreg"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -162,138 +158,6 @@ func testSendToRouteMultiPath(ht *lntemp.HarnessTest) {
|
|||||||
mts.closeChannels()
|
mts.closeChannels()
|
||||||
}
|
}
|
||||||
|
|
||||||
type mppTestContext struct {
|
|
||||||
t *harnessTest
|
|
||||||
net *lntest.NetworkHarness
|
|
||||||
|
|
||||||
// Keep a list of all our active channels.
|
|
||||||
networkChans []*lnrpc.ChannelPoint
|
|
||||||
closeChannelFuncs []func()
|
|
||||||
|
|
||||||
alice, bob, carol, dave, eve *lntest.HarnessNode
|
|
||||||
nodes []*lntest.HarnessNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMppTestContext(t *harnessTest,
|
|
||||||
net *lntest.NetworkHarness) *mppTestContext {
|
|
||||||
|
|
||||||
alice := net.NewNode(t.t, "alice", nil)
|
|
||||||
bob := net.NewNode(t.t, "bob", []string{"--accept-amp"})
|
|
||||||
|
|
||||||
// Create a five-node context consisting of Alice, Bob and three new
|
|
||||||
// nodes.
|
|
||||||
carol := net.NewNode(t.t, "carol", nil)
|
|
||||||
dave := net.NewNode(t.t, "dave", nil)
|
|
||||||
eve := net.NewNode(t.t, "eve", nil)
|
|
||||||
|
|
||||||
// Connect nodes to ensure propagation of channels.
|
|
||||||
nodes := []*lntest.HarnessNode{alice, bob, carol, dave, eve}
|
|
||||||
for i := 0; i < len(nodes); i++ {
|
|
||||||
for j := i + 1; j < len(nodes); j++ {
|
|
||||||
net.EnsureConnected(t.t, nodes[i], nodes[j])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := mppTestContext{
|
|
||||||
t: t,
|
|
||||||
net: net,
|
|
||||||
alice: alice,
|
|
||||||
bob: bob,
|
|
||||||
carol: carol,
|
|
||||||
dave: dave,
|
|
||||||
eve: eve,
|
|
||||||
nodes: nodes,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// openChannel is a helper to open a channel from->to.
|
|
||||||
func (c *mppTestContext) openChannel(from, to *lntest.HarnessNode,
|
|
||||||
chanSize btcutil.Amount) {
|
|
||||||
|
|
||||||
c.net.SendCoins(c.t.t, btcutil.SatoshiPerBitcoin, from)
|
|
||||||
|
|
||||||
chanPoint := openChannelAndAssert(
|
|
||||||
c.t, c.net, from, to,
|
|
||||||
lntest.OpenChannelParams{Amt: chanSize},
|
|
||||||
)
|
|
||||||
|
|
||||||
c.closeChannelFuncs = append(c.closeChannelFuncs, func() {
|
|
||||||
closeChannelAndAssert(c.t, c.net, from, chanPoint, false)
|
|
||||||
})
|
|
||||||
|
|
||||||
c.networkChans = append(c.networkChans, chanPoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *mppTestContext) closeChannels() {
|
|
||||||
for _, f := range c.closeChannelFuncs {
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *mppTestContext) shutdownNodes() {
|
|
||||||
shutdownAndAssert(c.net, c.t, c.alice)
|
|
||||||
shutdownAndAssert(c.net, c.t, c.bob)
|
|
||||||
shutdownAndAssert(c.net, c.t, c.carol)
|
|
||||||
shutdownAndAssert(c.net, c.t, c.dave)
|
|
||||||
shutdownAndAssert(c.net, c.t, c.eve)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *mppTestContext) waitForChannels() {
|
|
||||||
// Wait for all nodes to have seen all channels.
|
|
||||||
for _, chanPoint := range c.networkChans {
|
|
||||||
for _, node := range c.nodes {
|
|
||||||
txid, err := lnrpc.GetChanPointFundingTxid(chanPoint)
|
|
||||||
if err != nil {
|
|
||||||
c.t.Fatalf("unable to get txid: %v", err)
|
|
||||||
}
|
|
||||||
point := wire.OutPoint{
|
|
||||||
Hash: *txid,
|
|
||||||
Index: chanPoint.OutputIndex,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = node.WaitForNetworkChannelOpen(chanPoint)
|
|
||||||
if err != nil {
|
|
||||||
c.t.Fatalf("(%v:%d): timeout waiting for "+
|
|
||||||
"channel(%s) open: %v",
|
|
||||||
node.Cfg.Name, node.NodeID, point, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function for Alice to build a route from pubkeys.
|
|
||||||
func (c *mppTestContext) buildRoute(ctxb context.Context, amt btcutil.Amount,
|
|
||||||
sender *lntest.HarnessNode, hops []*lntest.HarnessNode) (*lnrpc.Route,
|
|
||||||
error) {
|
|
||||||
|
|
||||||
rpcHops := make([][]byte, 0, len(hops))
|
|
||||||
for _, hop := range hops {
|
|
||||||
k := hop.PubKeyStr
|
|
||||||
pubkey, err := route.NewVertexFromStr(k)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing %v: %v",
|
|
||||||
k, err)
|
|
||||||
}
|
|
||||||
rpcHops = append(rpcHops, pubkey[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
req := &routerrpc.BuildRouteRequest{
|
|
||||||
AmtMsat: int64(amt * 1000),
|
|
||||||
FinalCltvDelta: chainreg.DefaultBitcoinTimeLockDelta,
|
|
||||||
HopPubkeys: rpcHops,
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
routeResp, err := sender.RouterClient.BuildRoute(ctxt, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return routeResp.Route, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mppTestScenario defines a test scenario used for testing MPP-related tests.
|
// mppTestScenario defines a test scenario used for testing MPP-related tests.
|
||||||
// It has two standby nodes, alice and bob, and three new nodes, carol, dave,
|
// It has two standby nodes, alice and bob, and three new nodes, carol, dave,
|
||||||
// and eve.
|
// and eve.
|
||||||
|
@ -40,10 +40,6 @@ var allTestCases = []*testCase{
|
|||||||
name: "sign psbt",
|
name: "sign psbt",
|
||||||
test: testSignPsbt,
|
test: testSignPsbt,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "sendtoroute amp",
|
|
||||||
test: testSendToRouteAMP,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "forward interceptor",
|
name: "forward interceptor",
|
||||||
test: testForwardInterceptorBasic,
|
test: testForwardInterceptorBasic,
|
||||||
|
Loading…
Reference in New Issue
Block a user