Created
March 4, 2023 21:59
-
-
Save bshramin/9a26a9dfefc23f8c22bf898fa623f247 to your computer and use it in GitHub Desktop.
LND multi-hop payment test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func testSingleHopInvoice(ht *lntemp.HarnessTest) { | |
// Open a channel with 100k satoshis between Alice and Bob with Alice | |
// being the sole funder of the channel. | |
chanAmt := btcutil.Amount(100000) | |
alice, bob := ht.Alice, ht.Bob | |
carol := ht.NewNode("Carol", nil) | |
cp := ht.OpenChannel( | |
alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, | |
) | |
cp2 := ht.OpenChannel( | |
bob, carol, lntemp.OpenChannelParams{Amt: chanAmt}, | |
) | |
// assertAmountPaid is a helper closure that asserts the amount paid by | |
// Alice and received by Bob are expected. | |
assertAmountPaid := func(expected int64) { | |
ht.AssertAmountPaid("alice -> bob", alice, cp, expected, 0) | |
ht.AssertAmountPaid("bob <- alice", bob, cp, 0, expected) | |
ht.AssertAmountPaid("carol -> bob", carol, cp, expected, 0) | |
ht.AssertAmountPaid("bob <- carol", bob, cp, 0, expected) | |
} | |
// Now that the channel is open, create an invoice for Carol which | |
// expects a payment of 1000 satoshis from Alice paid via a particular | |
// preimage. | |
const paymentAmt = 1000 | |
preimage := bytes.Repeat([]byte("A"), 32) | |
invoice := &lnrpc.Invoice{ | |
Memo: "testing", | |
RPreimage: preimage, | |
Value: paymentAmt, | |
} | |
invoiceResp := carol.RPC.AddInvoice(invoice) | |
// With the invoice for Carol added, send a payment towards Alice paying | |
// to the above generated invoice. | |
ht.CompletePaymentRequests(alice, []string{invoiceResp.PaymentRequest}) | |
// Carol's invoice should now be found and marked as settled. | |
dbInvoice := bob.RPC.LookupInvoice(invoiceResp.RHash) | |
require.Equal(ht, lnrpc.Invoice_SETTLED, dbInvoice.State, | |
"carol's invoice should be marked as settled") | |
// With the payment completed all balance related stats should be | |
// properly updated. | |
assertAmountPaid(paymentAmt) | |
// Create another invoice for Carol, this time leaving off the preimage | |
// to one will be randomly generated. We'll test the proper | |
// encoding/decoding of the zpay32 payment requests. | |
invoice = &lnrpc.Invoice{ | |
Memo: "test3", | |
Value: paymentAmt, | |
} | |
invoiceResp = carol.RPC.AddInvoice(invoice) | |
// Next send another payment, but this time using a zpay32 encoded | |
// invoice rather than manually specifying the payment details. | |
ht.CompletePaymentRequests(alice, []string{invoiceResp.PaymentRequest}) | |
// The second payment should also have succeeded, with the balances | |
// being update accordingly. | |
assertAmountPaid(paymentAmt * 2) | |
// Next send a keysend payment. | |
keySendPreimage := lntypes.Preimage{3, 4, 5, 11} | |
keySendHash := keySendPreimage.Hash() | |
req := &routerrpc.SendPaymentRequest{ | |
Dest: carol.PubKey[:], | |
Amt: paymentAmt, | |
FinalCltvDelta: 40, | |
PaymentHash: keySendHash[:], | |
DestCustomRecords: map[uint64][]byte{ | |
record.KeySendType: keySendPreimage[:], | |
}, | |
TimeoutSeconds: 60, | |
FeeLimitMsat: noFeeLimitMsat, | |
} | |
ht.SendPaymentAssertSettled(alice, req) | |
// The keysend payment should also have succeeded, with the balances | |
// being update accordingly. | |
assertAmountPaid(paymentAmt * 3) | |
// Assert that the invoice has the proper AMP fields set, since the | |
// legacy keysend payment should have been promoted into an AMP payment | |
// internally. | |
keysendInvoice := carol.RPC.LookupInvoice(keySendHash[:]) | |
require.Len(ht, keysendInvoice.Htlcs, 1) | |
htlc := keysendInvoice.Htlcs[0] | |
require.Zero(ht, htlc.MppTotalAmtMsat) | |
require.Nil(ht, htlc.Amp) | |
// Now create an invoice and specify routing hints. | |
// We will test that the routing hints are encoded properly. | |
hintChannel := lnwire.ShortChannelID{BlockHeight: 10} | |
carolPubKey := hex.EncodeToString(carol.PubKey[:]) | |
hint := &lnrpc.HopHint{ | |
NodeId: carolPubKey, | |
ChanId: hintChannel.ToUint64(), | |
FeeBaseMsat: 1, | |
FeeProportionalMillionths: 1000000, | |
CltvExpiryDelta: 20, | |
} | |
hints := []*lnrpc.RouteHint{{HopHints: []*lnrpc.HopHint{hint}}} | |
invoice = &lnrpc.Invoice{ | |
Memo: "hints", | |
Value: paymentAmt, | |
RouteHints: hints, | |
} | |
invoiceResp = carol.RPC.AddInvoice(invoice) | |
payreq := carol.RPC.DecodePayReq(invoiceResp.PaymentRequest) | |
require.Len(ht, payreq.RouteHints, 1, "expected one routing hint") | |
routingHint := payreq.RouteHints[0] | |
require.Len(ht, routingHint.HopHints, 1, "expected one hop hint") | |
hopHint := routingHint.HopHints[0] | |
require.EqualValues(ht, 1000000, hopHint.FeeProportionalMillionths, | |
"wrong FeeProportionalMillionths") | |
require.Equal(ht, carolPubKey, hopHint.NodeId, "wrong NodeId") | |
require.Equal(ht, hintChannel.ToUint64(), hopHint.ChanId, | |
"wrong ChanId") | |
require.EqualValues(ht, 1, hopHint.FeeBaseMsat, "wrong FeeBaseMsat") | |
require.EqualValues(ht, 20, hopHint.CltvExpiryDelta, | |
"wrong CltvExpiryDelta") | |
ht.CloseChannel(alice, cp) | |
ht.CloseChannel(carol, cp2) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment