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"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -2077,3 +2078,58 @@ func (h *HarnessTest) ReceiveSendToRouteUpdate(
|
||||
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",
|
||||
TestFunc: testSendPaymentAMP,
|
||||
},
|
||||
{
|
||||
Name: "sendtoroute amp",
|
||||
TestFunc: testSendToRouteAMP,
|
||||
},
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
package itest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -15,7 +12,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"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
|
||||
// the one received via the subscription.
|
||||
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
|
||||
// has the correct payment address.
|
||||
@ -463,12 +460,8 @@ func testSendPaymentAMP(ht *lntemp.HarnessTest) {
|
||||
mts.closeChannels()
|
||||
}
|
||||
|
||||
func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
ctxb := context.Background()
|
||||
|
||||
ctx := newMppTestContext(t, net)
|
||||
defer ctx.shutdownNodes()
|
||||
|
||||
func testSendToRouteAMP(ht *lntemp.HarnessTest) {
|
||||
mts := newMppTestScenario(ht)
|
||||
const (
|
||||
paymentAmt = btcutil.Amount(300000)
|
||||
numShards = 3
|
||||
@ -476,63 +469,50 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
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.
|
||||
// _ Eve _
|
||||
// / \
|
||||
// Alice -- Carol ---- Bob
|
||||
// \ /
|
||||
// \__ Dave ____/
|
||||
//
|
||||
ctx.openChannel(ctx.carol, ctx.bob, chanAmt)
|
||||
ctx.openChannel(ctx.dave, ctx.bob, chanAmt)
|
||||
ctx.openChannel(ctx.alice, ctx.dave, chanAmt)
|
||||
ctx.openChannel(ctx.eve, ctx.bob, chanAmt)
|
||||
ctx.openChannel(ctx.carol, ctx.eve, chanAmt)
|
||||
|
||||
// Since the channel Alice-> Carol will have to carry two
|
||||
// shards, we make it larger.
|
||||
ctx.openChannel(ctx.alice, ctx.carol, chanAmt+shardAmt)
|
||||
|
||||
defer ctx.closeChannels()
|
||||
|
||||
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()
|
||||
///
|
||||
mppReq := &mppOpenChannelRequest{
|
||||
// Since the channel Alice-> Carol will have to carry two
|
||||
// shards, we make it larger.
|
||||
amtAliceCarol: chanAmt + shardAmt,
|
||||
amtAliceDave: chanAmt,
|
||||
amtCarolBob: chanAmt,
|
||||
amtCarolEve: chanAmt,
|
||||
amtDaveBob: chanAmt,
|
||||
amtEveBob: chanAmt,
|
||||
}
|
||||
mts.openChannels(mppReq)
|
||||
|
||||
// We'll send shards along three routes from Alice.
|
||||
sendRoutes := [numShards][]*lntest.HarnessNode{
|
||||
{ctx.carol, ctx.bob},
|
||||
{ctx.dave, ctx.bob},
|
||||
{ctx.carol, ctx.eve, ctx.bob},
|
||||
sendRoutes := [numShards][]*node.HarnessNode{
|
||||
{mts.carol, mts.bob},
|
||||
{mts.dave, mts.bob},
|
||||
{mts.carol, mts.eve, mts.bob},
|
||||
}
|
||||
|
||||
payAddr := make([]byte, 32)
|
||||
_, err = rand.Read(payAddr)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
setID := make([]byte, 32)
|
||||
_, err = rand.Read(setID)
|
||||
require.NoError(t.t, err)
|
||||
payAddr := ht.Random32Bytes()
|
||||
setID := ht.Random32Bytes()
|
||||
|
||||
var sharer amp.Sharer
|
||||
sharer, err = amp.NewSeedSharer()
|
||||
require.NoError(t.t, err)
|
||||
sharer, err := amp.NewSeedSharer()
|
||||
require.NoError(ht, err)
|
||||
|
||||
childPreimages := make(map[lntypes.Preimage]uint32)
|
||||
responses := make(chan *lnrpc.HTLCAttempt, len(sendRoutes))
|
||||
|
||||
// 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.
|
||||
r, err := ctx.buildRoute(ctxb, shardAmt, ctx.alice, hops)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to build route: %v", err)
|
||||
}
|
||||
r := mts.buildRoute(shardAmt, mts.alice, hops)
|
||||
|
||||
// Set the MPP records to indicate this is a payment shard.
|
||||
hop := r.Hops[len(r.Hops)-1]
|
||||
@ -546,7 +526,7 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
if i < len(sendRoutes)-1 {
|
||||
var left amp.Sharer
|
||||
left, sharer, err = sharer.Split()
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
|
||||
child = left.Child(uint32(i))
|
||||
} else {
|
||||
@ -566,15 +546,10 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
Route: r,
|
||||
}
|
||||
|
||||
// We'll send all shards in their own goroutine, since SendToRoute will
|
||||
// block as long as the payment is in flight.
|
||||
// We'll send all shards in their own goroutine, since
|
||||
// SendToRoute will block as long as the payment is in flight.
|
||||
go func() {
|
||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||
resp, err := ctx.alice.RouterClient.SendToRouteV2(ctxt, sendReq)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send payment: %v", err)
|
||||
}
|
||||
|
||||
resp := mts.alice.RPC.SendToRouteV2(sendReq)
|
||||
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.
|
||||
rpcInvoice, err := bobInvoiceSubscription.Recv()
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
|
||||
require.False(t.t, rpcInvoice.Settled) // nolint:staticcheck
|
||||
require.Equal(t.t, lnrpc.Invoice_OPEN, rpcInvoice.State)
|
||||
require.Equal(t.t, int64(0), rpcInvoice.AmtPaidSat)
|
||||
require.Equal(t.t, int64(0), rpcInvoice.AmtPaidMsat)
|
||||
require.Equal(t.t, payAddr, rpcInvoice.PaymentAddr)
|
||||
require.False(ht, rpcInvoice.Settled) // nolint:staticcheck
|
||||
require.Equal(ht, lnrpc.Invoice_OPEN, rpcInvoice.State)
|
||||
require.Equal(ht, int64(0), rpcInvoice.AmtPaidSat)
|
||||
require.Equal(ht, int64(0), rpcInvoice.AmtPaidMsat)
|
||||
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(2, sendRoutes[2])
|
||||
|
||||
// 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
|
||||
// invoice.
|
||||
@ -609,24 +584,23 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
// Wait for all responses to be back, and check that they all
|
||||
// succeeded.
|
||||
timer := time.After(defaultTimeout)
|
||||
for range sendRoutes {
|
||||
var resp *lnrpc.HTLCAttempt
|
||||
select {
|
||||
case resp = <-responses:
|
||||
case <-time.After(defaultTimeout):
|
||||
t.Fatalf("response not received")
|
||||
case <-timer:
|
||||
require.Fail(ht, "response not received")
|
||||
}
|
||||
|
||||
if resp.Failure != nil {
|
||||
t.Fatalf("received payment failure : %v", resp.Failure)
|
||||
}
|
||||
require.Nil(ht, resp.Failure, "received payment failure")
|
||||
|
||||
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.
|
||||
_, ok := childPreimages[preimage]
|
||||
require.True(t.t, ok)
|
||||
require.True(ht, ok)
|
||||
|
||||
// Remove this preimage from out set so that we ensure all
|
||||
// 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.
|
||||
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
|
||||
// the one received via the subscription.
|
||||
invoiceResp, err := ctx.bob.ListInvoices(
|
||||
ctxb, &lnrpc.ListInvoiceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.Equal(t.t, 1, len(invoiceResp.Invoices))
|
||||
assertInvoiceEqual(t.t, rpcInvoice, invoiceResp.Invoices[0])
|
||||
invoices := ht.AssertNumInvoices(mts.bob, 1)
|
||||
ht.AssertInvoiceEqual(rpcInvoice, invoices[0])
|
||||
|
||||
// Assert that the invoice is settled for the total payment amount and
|
||||
// has the correct payment address.
|
||||
require.True(t.t, rpcInvoice.Settled) // nolint:staticcheck
|
||||
require.Equal(t.t, lnrpc.Invoice_SETTLED, rpcInvoice.State)
|
||||
require.Equal(t.t, int64(paymentAmt), rpcInvoice.AmtPaidSat)
|
||||
require.Equal(t.t, int64(paymentAmt*1000), rpcInvoice.AmtPaidMsat)
|
||||
require.Equal(t.t, payAddr, rpcInvoice.PaymentAddr)
|
||||
require.True(ht, rpcInvoice.Settled) // nolint:staticcheck
|
||||
require.Equal(ht, lnrpc.Invoice_SETTLED, rpcInvoice.State)
|
||||
require.Equal(ht, int64(paymentAmt), rpcInvoice.AmtPaidSat)
|
||||
require.Equal(ht, int64(paymentAmt*1000), rpcInvoice.AmtPaidMsat)
|
||||
require.Equal(ht, payAddr, rpcInvoice.PaymentAddr)
|
||||
|
||||
// Finally, assert that the proper set id is recorded for each htlc, and
|
||||
// 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 {
|
||||
require.NotNil(t.t, htlc.Amp)
|
||||
require.Equal(t.t, setID, htlc.Amp.SetId)
|
||||
require.NotNil(ht, htlc.Amp)
|
||||
require.Equal(ht, setID, htlc.Amp.SetId)
|
||||
|
||||
// Parse the child hash and child preimage, and assert they are
|
||||
// well-formed.
|
||||
childHash, err := lntypes.MakeHash(htlc.Amp.Hash)
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage)
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
|
||||
// Assert that the preimage actually matches the hashes.
|
||||
validPreimage := childPreimage.Matches(childHash)
|
||||
require.True(t.t, validPreimage)
|
||||
require.True(ht, validPreimage)
|
||||
|
||||
// Assert that the HTLC includes one of our child preimages.
|
||||
childIndex, ok := childPreimages[childPreimage]
|
||||
require.True(t.t, ok)
|
||||
require.True(ht, ok)
|
||||
|
||||
// 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
|
||||
// have a unique child preimage.
|
||||
delete(childPreimages, childPreimage)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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)
|
||||
}
|
||||
|
||||
// Finally, close all channels.
|
||||
mts.closeChannels()
|
||||
}
|
||||
|
@ -1,18 +1,14 @@
|
||||
package itest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/chainreg"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -162,138 +158,6 @@ func testSendToRouteMultiPath(ht *lntemp.HarnessTest) {
|
||||
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.
|
||||
// It has two standby nodes, alice and bob, and three new nodes, carol, dave,
|
||||
// and eve.
|
||||
|
@ -40,10 +40,6 @@ var allTestCases = []*testCase{
|
||||
name: "sign psbt",
|
||||
test: testSignPsbt,
|
||||
},
|
||||
{
|
||||
name: "sendtoroute amp",
|
||||
test: testSendToRouteAMP,
|
||||
},
|
||||
{
|
||||
name: "forward interceptor",
|
||||
test: testForwardInterceptorBasic,
|
||||
|
Loading…
Reference in New Issue
Block a user