Skip to content

Commit

Permalink
itest: add testSendDirectPayment
Browse files Browse the repository at this point in the history
Adds a new test to check direct payments between two nodes. The fee rate
is tuned to 1 sat/vb to catch edge cases.
  • Loading branch information
yyforyongyu committed Sep 28, 2023
1 parent ec58543 commit 62d240b
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
4 changes: 4 additions & 0 deletions itest/list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ var allTestCases = []*lntest.TestCase{
Name: "list outgoing payments",
TestFunc: testListPayments,
},
{
Name: "send direct payment",
TestFunc: testSendDirectPayment,
},
{
Name: "immediate payment after channel opened",
TestFunc: testPaymentFollowingChannelOpen,
Expand Down
125 changes: 125 additions & 0 deletions itest/lnd_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"testing"
"time"

"github.com/btcsuite/btcd/btcutil"
Expand All @@ -16,6 +17,130 @@ import (
"github.com/stretchr/testify/require"
)

// testSendDirectPayment creates a topology Alice->Bob and then tests that
// Alice can send a direct payment to Bob. This test modifies the fee estimator
// to return floor fee rate(1 sat/vb).
func testSendDirectPayment(ht *lntest.HarnessTest) {
// Grab Alice and Bob's nodes for convenience.
alice, bob := ht.Alice, ht.Bob

// Create a list of commitment types we want to test.
commitTyes := []lnrpc.CommitmentType{
lnrpc.CommitmentType_LEGACY,
lnrpc.CommitmentType_ANCHORS,
lnrpc.CommitmentType_SIMPLE_TAPROOT,
}

// testSendPayment opens a channel between Alice and Bob using the
// specified params. It then sends a payment from Alice to Bob and
// asserts it being successful.
testSendPayment := func(ht *lntest.HarnessTest,
params lntest.OpenChannelParams) {

// Check that there are no payments before test.
chanPoint := ht.OpenChannel(alice, bob, params)

// Now that the channel is open, create an invoice for Bob
// which expects a payment of 1000 satoshis from Alice paid via
// a particular preimage.
const paymentAmt = 1000
preimage := ht.Random32Bytes()
invoice := &lnrpc.Invoice{
RPreimage: preimage,
Value: paymentAmt,
}
invoiceResp := bob.RPC.AddInvoice(invoice)

// With the invoice for Bob added, send a payment towards Alice
// paying to the above generated invoice.
payReqs := []string{invoiceResp.PaymentRequest}
ht.CompletePaymentRequests(alice, payReqs)

p := ht.AssertNumPayments(alice, 1)[0]
path := p.Htlcs[len(p.Htlcs)-1].Route.Hops

// Ensure that the stored path shows a direct payment to Bob
// with no other nodes in-between.
require.Len(ht, path, 1, "wrong number of routes in path")
require.Equal(ht, bob.PubKeyStr, path[0].PubKey, "wrong pubkey")

// The payment amount should also match our previous payment
// directly.
require.EqualValues(ht, paymentAmt, p.ValueSat,
"incorrect sat amount")
require.EqualValues(ht, paymentAmt*1000, p.ValueMsat,
"incorrect msat amount")

// The payment hash (or r-hash) should have been stored
// correctly.
correctRHash := hex.EncodeToString(invoiceResp.RHash)
require.Equal(ht, correctRHash, p.PaymentHash, "incorrect hash")

// As we made a single-hop direct payment, there should have
// been no fee applied.
require.Zero(ht, p.FeeSat, "fee should be 0")
require.Zero(ht, p.FeeMsat, "fee should be 0")

// Now verify that the payment request returned by the rpc
// matches the invoice that we paid.
require.Equal(ht, invoiceResp.PaymentRequest, p.PaymentRequest,
"incorrect payreq")

// Delete all payments from Alice. DB should have no payments.
alice.RPC.DeleteAllPayments()
ht.AssertNumPayments(alice, 0)

// TODO(yy): remove the sleep once the following bug is fixed.
// When the invoice is reported settled, the commitment dance
// is not yet finished, which can cause an error when closing
// the channel, saying there's active HTLCs. We need to
// investigate this issue and reverse the order to, first
// finish the commitment dance, then report the invoice as
// settled.
time.Sleep(2 * time.Second)

// Close the channel.
//
// NOTE: This implicitly tests that the channel link is active
// before closing this channel. The above payment will trigger
// a commitment dance in both of the nodes. If the node fails
// to update the commitment state, we will fail to close the
// channel as the link won't be active.
ht.CloseChannel(alice, chanPoint)
}

// Run the test cases.
for _, ct := range commitTyes {
ht.Run(ct.String(), func(t *testing.T) {
st := ht.Subtest(t)

// Set the fee estimate to 1sat/vbyte.
st.SetFeeEstimate(250)

// Restart the nodes with the specified commitment type.
args := lntest.NodeArgsForCommitType(ct)
st.RestartNodeWithExtraArgs(alice, args)
st.RestartNodeWithExtraArgs(bob, args)

// Make sure they are connected.
st.EnsureConnected(alice, bob)

// Open a channel with 100k satoshis between Alice and
// Bob with Alice being the sole funder of the channel.
params := lntest.OpenChannelParams{
Amt: 100_000,
CommitmentType: ct,
}

// Open private channel for taproot channels.
params.Private = ct ==
lnrpc.CommitmentType_SIMPLE_TAPROOT

testSendPayment(st, params)
})
}
}

func testListPayments(ht *lntest.HarnessTest) {
alice, bob := ht.Alice, ht.Bob

Expand Down

0 comments on commit 62d240b

Please sign in to comment.