Merge pull request #5253 from cfromknecht/amp-invoice
Support paying AMP invoices via SendPaymentV2
This commit is contained in:
30 files changed
+1528
-1023
No files matched your search
+247
-13
@@ -3,6 +3,8 @@ package itest
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcutil"
|
||||
@@ -15,6 +17,152 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testSendPaymentAMPInvoice tests that we can send an AMP payment to a
|
||||
// specified AMP invoice using SendPaymentV2.
|
||||
func testSendPaymentAMPInvoice(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
ctxb := context.Background()
|
||||
|
||||
ctx := newMppTestContext(t, net)
|
||||
defer ctx.shutdownNodes()
|
||||
|
||||
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 ____/
|
||||
//
|
||||
ctx.openChannel(ctx.carol, ctx.bob, 135000)
|
||||
ctx.openChannel(ctx.alice, ctx.carol, 235000)
|
||||
ctx.openChannel(ctx.dave, ctx.bob, 135000)
|
||||
ctx.openChannel(ctx.alice, ctx.dave, 135000)
|
||||
ctx.openChannel(ctx.eve, ctx.bob, 135000)
|
||||
ctx.openChannel(ctx.carol, ctx.eve, 135000)
|
||||
|
||||
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()
|
||||
|
||||
addInvoiceResp, err := ctx.bob.AddInvoice(context.Background(), &lnrpc.Invoice{
|
||||
Value: int64(paymentAmt),
|
||||
IsAmp: true,
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// Ensure we get a notification of the invoice being added by Bob.
|
||||
rpcInvoice, err := bobInvoiceSubscription.Recv()
|
||||
require.NoError(t.t, 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, 0, len(rpcInvoice.Htlcs))
|
||||
|
||||
// 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.
|
||||
_, err = ctx.dave.UpdateChannelPolicy(
|
||||
context.Background(),
|
||||
&lnrpc.PolicyUpdateRequest{
|
||||
Scope: &lnrpc.PolicyUpdateRequest_Global{Global: true},
|
||||
BaseFeeMsat: 500000,
|
||||
FeeRate: 0.001,
|
||||
TimeLockDelta: 40,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("dave policy update: %v", err)
|
||||
}
|
||||
|
||||
ctxt, _ := context.WithTimeout(context.Background(), 4*defaultTimeout)
|
||||
payment := sendAndAssertSuccess(
|
||||
ctxt, t, ctx.alice,
|
||||
&routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: addInvoiceResp.PaymentRequest,
|
||||
TimeoutSeconds: 60,
|
||||
FeeLimitMsat: noFeeLimitMsat,
|
||||
},
|
||||
)
|
||||
|
||||
// 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
|
||||
if succeeded < minExpectedShards {
|
||||
t.Fatalf("expected at least %v shards, but got %v",
|
||||
minExpectedShards, succeeded)
|
||||
}
|
||||
|
||||
// There should now be a settle event for the invoice.
|
||||
rpcInvoice, err = bobInvoiceSubscription.Recv()
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// Also fetch Bob's invoice from ListInvoices and assert it is equal to
|
||||
// the one recevied 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])
|
||||
|
||||
// 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)
|
||||
|
||||
// Finally, assert that the same set id is recorded for each htlc, and
|
||||
// that the preimage hash pair is valid.
|
||||
var setID []byte
|
||||
require.Equal(t.t, succeeded, len(rpcInvoice.Htlcs))
|
||||
for _, htlc := range rpcInvoice.Htlcs {
|
||||
require.NotNil(t.t, htlc.Amp)
|
||||
if setID == nil {
|
||||
setID = make([]byte, 32)
|
||||
copy(setID, htlc.Amp.SetId)
|
||||
}
|
||||
require.Equal(t.t, 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)
|
||||
childPreimage, err := lntypes.MakePreimage(htlc.Amp.Preimage)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// Assert that the preimage actually matches the hashes.
|
||||
validPreimage := childPreimage.Matches(childHash)
|
||||
require.True(t.t, validPreimage)
|
||||
}
|
||||
}
|
||||
|
||||
// testSendPaymentAMP tests that we can send an AMP payment to a specified
|
||||
// destination using SendPaymentV2.
|
||||
func testSendPaymentAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
@@ -64,12 +212,11 @@ func testSendPaymentAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
ctxt, _ := context.WithTimeout(context.Background(), 4*defaultTimeout)
|
||||
payment := sendAndAssertSuccess(
|
||||
ctxt, t, net.Alice,
|
||||
ctxt, t, ctx.alice,
|
||||
&routerrpc.SendPaymentRequest{
|
||||
Dest: net.Bob.PubKey[:],
|
||||
Dest: ctx.bob.PubKey[:],
|
||||
Amt: int64(paymentAmt),
|
||||
FinalCltvDelta: chainreg.DefaultBitcoinTimeLockDelta,
|
||||
MaxParts: 10,
|
||||
TimeoutSeconds: 60,
|
||||
FeeLimitMsat: noFeeLimitMsat,
|
||||
Amp: true,
|
||||
@@ -97,7 +244,7 @@ func testSendPaymentAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
}
|
||||
|
||||
// Fetch Bob's invoices.
|
||||
invoiceResp, err := net.Bob.ListInvoices(
|
||||
invoiceResp, err := ctx.bob.ListInvoices(
|
||||
ctxb, &lnrpc.ListInvoiceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
@@ -172,6 +319,13 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
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.
|
||||
sendRoutes := [numShards][]*lntest.HarnessNode{
|
||||
{ctx.carol, ctx.bob},
|
||||
@@ -180,7 +334,7 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
}
|
||||
|
||||
payAddr := make([]byte, 32)
|
||||
_, err := rand.Read(payAddr)
|
||||
_, err = rand.Read(payAddr)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
setID := make([]byte, 32)
|
||||
@@ -193,9 +347,11 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
childPreimages := make(map[lntypes.Preimage]uint32)
|
||||
responses := make(chan *lnrpc.HTLCAttempt, len(sendRoutes))
|
||||
for i, hops := range sendRoutes {
|
||||
|
||||
// Define a closure for sending each of the three shards.
|
||||
sendShard := func(i int, hops []*lntest.HarnessNode) {
|
||||
// Build a route for the specified hops.
|
||||
r, err := ctx.buildRoute(ctxb, shardAmt, net.Alice, hops)
|
||||
r, err := ctx.buildRoute(ctxb, shardAmt, ctx.alice, hops)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to build route: %v", err)
|
||||
}
|
||||
@@ -236,7 +392,7 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
// block as long as the payment is in flight.
|
||||
go func() {
|
||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||
resp, err := net.Alice.RouterClient.SendToRouteV2(ctxt, sendReq)
|
||||
resp, err := ctx.alice.RouterClient.SendToRouteV2(ctxt, sendReq)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send payment: %v", err)
|
||||
}
|
||||
@@ -245,6 +401,24 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
}()
|
||||
}
|
||||
|
||||
// Send the first shard, this cause Bob to JIT add an invoice.
|
||||
sendShard(0, sendRoutes[0])
|
||||
|
||||
// Ensure we get a notification of the invoice being added by Bob.
|
||||
rpcInvoice, err := bobInvoiceSubscription.Recv()
|
||||
require.NoError(t.t, 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.Equal(t.t, 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))
|
||||
|
||||
@@ -282,15 +456,18 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
}
|
||||
childPreimages = childPreimagesCopy
|
||||
|
||||
// Fetch Bob's invoices.
|
||||
invoiceResp, err := net.Bob.ListInvoices(
|
||||
// There should now be a settle event for the invoice.
|
||||
rpcInvoice, err = bobInvoiceSubscription.Recv()
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// Also fetch Bob's invoice from ListInvoices and assert it is equal to
|
||||
// the one recevied via the subscription.
|
||||
invoiceResp, err := ctx.bob.ListInvoices(
|
||||
ctxb, &lnrpc.ListInvoiceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// There should only be one invoice.
|
||||
require.Equal(t.t, 1, len(invoiceResp.Invoices))
|
||||
rpcInvoice := invoiceResp.Invoices[0]
|
||||
assertInvoiceEqual(t.t, rpcInvoice, invoiceResp.Invoices[0])
|
||||
|
||||
// Assert that the invoice is settled for the total payment amount and
|
||||
// has the correct payment address.
|
||||
@@ -330,3 +507,60 @@ func testSendToRouteAMP(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func testSendToRouteMultiPath(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
// Make Bob create an invoice for Alice to pay.
|
||||
payReqs, rHashes, invoices, err := createPayReqs(
|
||||
net.Bob, paymentAmt, 1,
|
||||
ctx.bob, paymentAmt, 1,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create pay reqs: %v", err)
|
||||
@@ -65,7 +65,7 @@ func testSendToRouteMultiPath(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
payReq := payReqs[0]
|
||||
|
||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||
decodeResp, err := net.Bob.DecodePayReq(
|
||||
decodeResp, err := ctx.bob.DecodePayReq(
|
||||
ctxt, &lnrpc.PayReqString{PayReq: payReq},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -84,7 +84,7 @@ func testSendToRouteMultiPath(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
responses := make(chan *lnrpc.HTLCAttempt, len(sendRoutes))
|
||||
for _, hops := range sendRoutes {
|
||||
// Build a route for the specified hops.
|
||||
r, err := ctx.buildRoute(ctxb, shardAmt, net.Alice, hops)
|
||||
r, err := ctx.buildRoute(ctxb, shardAmt, ctx.alice, hops)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to build route: %v", err)
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func testSendToRouteMultiPath(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
// block as long as the payment is in flight.
|
||||
go func() {
|
||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||
resp, err := net.Alice.RouterClient.SendToRouteV2(ctxt, sendReq)
|
||||
resp, err := ctx.alice.RouterClient.SendToRouteV2(ctxt, sendReq)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send payment: %v", err)
|
||||
}
|
||||
@@ -234,10 +234,10 @@ func testSendToRouteMultiPath(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
// Finally check that the payment shows up with three settled HTLCs in
|
||||
// Alice's list of payments...
|
||||
assertNumHtlcs(net.Alice, 3)
|
||||
assertNumHtlcs(ctx.alice, 3)
|
||||
|
||||
// ...and in Bob's list of paid invoices.
|
||||
assertSettledInvoice(net.Bob, rHash, 3)
|
||||
assertSettledInvoice(ctx.bob, rHash, 3)
|
||||
}
|
||||
|
||||
type mppTestContext struct {
|
||||
@@ -257,6 +257,16 @@ func newMppTestContext(t *harnessTest,
|
||||
|
||||
ctxb := context.Background()
|
||||
|
||||
alice, err := net.NewNode("alice", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create alice: %v", err)
|
||||
}
|
||||
|
||||
bob, err := net.NewNode("bob", []string{"--accept-amp"})
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create bob: %v", err)
|
||||
}
|
||||
|
||||
// Create a five-node context consisting of Alice, Bob and three new
|
||||
// nodes.
|
||||
carol, err := net.NewNode("carol", nil)
|
||||
@@ -275,7 +285,7 @@ func newMppTestContext(t *harnessTest,
|
||||
}
|
||||
|
||||
// Connect nodes to ensure propagation of channels.
|
||||
nodes := []*lntest.HarnessNode{net.Alice, net.Bob, carol, dave, eve}
|
||||
nodes := []*lntest.HarnessNode{alice, bob, carol, dave, eve}
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
for j := i + 1; j < len(nodes); j++ {
|
||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||
@@ -288,8 +298,8 @@ func newMppTestContext(t *harnessTest,
|
||||
ctx := mppTestContext{
|
||||
t: t,
|
||||
net: net,
|
||||
alice: net.Alice,
|
||||
bob: net.Bob,
|
||||
alice: alice,
|
||||
bob: bob,
|
||||
carol: carol,
|
||||
dave: dave,
|
||||
eve: eve,
|
||||
|
||||
@@ -59,7 +59,7 @@ func testSendMultiPathPayment(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
// Our first test will be Alice paying Bob using a SendPayment call.
|
||||
// Let Bob create an invoice for Alice to pay.
|
||||
payReqs, rHashes, invoices, err := createPayReqs(
|
||||
net.Bob, paymentAmt, 1,
|
||||
ctx.bob, paymentAmt, 1,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create pay reqs: %v", err)
|
||||
@@ -70,7 +70,7 @@ func testSendMultiPathPayment(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
|
||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||
payment := sendAndAssertSuccess(
|
||||
ctxt, t, net.Alice,
|
||||
ctxt, t, ctx.alice,
|
||||
&routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: payReq,
|
||||
MaxParts: 10,
|
||||
|
||||
@@ -278,7 +278,10 @@ var allTestCases = []*testCase{
|
||||
name: "sendpayment amp",
|
||||
test: testSendPaymentAMP,
|
||||
},
|
||||
|
||||
{
|
||||
name: "sendpayment amp invoice",
|
||||
test: testSendPaymentAMPInvoice,
|
||||
},
|
||||
{
|
||||
name: "send multi path payment",
|
||||
test: testSendMultiPathPayment,
|
||||
|
||||
@@ -210,6 +210,7 @@ type NodeConfig struct {
|
||||
ProfilePort int
|
||||
|
||||
AcceptKeySend bool
|
||||
AcceptAMP bool
|
||||
|
||||
FeeURL string
|
||||
|
||||
@@ -297,6 +298,10 @@ func (cfg NodeConfig) genArgs() []string {
|
||||
args = append(args, "--accept-keysend")
|
||||
}
|
||||
|
||||
if cfg.AcceptAMP {
|
||||
args = append(args, "--accept-amp")
|
||||
}
|
||||
|
||||
if cfg.Etcd {
|
||||
args = append(args, "--db.backend=etcd")
|
||||
args = append(args, "--db.etcd.embedded")
|
||||
|
||||
Reference in new issue
Block a user