lntemp+itest: refactor testAsyncPayments
This commit is contained in:
4 files changed
+103
-118
No files matched your search
@@ -928,6 +928,16 @@ func (h *HarnessTest) AssertPaymentStatusFromStream(stream rpc.PaymentClient,
|
|||||||
return h.assertPaymentStatusWithTimeout(stream, status, DefaultTimeout)
|
return h.assertPaymentStatusWithTimeout(stream, status, DefaultTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertPaymentSucceedWithTimeout asserts that a payment is succeeded within
|
||||||
|
// the specified timeout.
|
||||||
|
func (h *HarnessTest) AssertPaymentSucceedWithTimeout(stream rpc.PaymentClient,
|
||||||
|
timeout time.Duration) *lnrpc.Payment {
|
||||||
|
|
||||||
|
return h.assertPaymentStatusWithTimeout(
|
||||||
|
stream, lnrpc.Payment_SUCCEEDED, timeout,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// assertPaymentStatusWithTimeout takes a client stream and asserts the payment
|
// assertPaymentStatusWithTimeout takes a client stream and asserts the payment
|
||||||
// is in desired status before the specified timeout. The payment found is
|
// is in desired status before the specified timeout. The payment found is
|
||||||
// returned once succeeded.
|
// returned once succeeded.
|
||||||
@@ -939,7 +949,9 @@ func (h *HarnessTest) assertPaymentStatusWithTimeout(stream rpc.PaymentClient,
|
|||||||
err := wait.NoError(func() error {
|
err := wait.NoError(func() error {
|
||||||
// Consume one message. This will raise an error if the message
|
// Consume one message. This will raise an error if the message
|
||||||
// is not received within DefaultTimeout.
|
// is not received within DefaultTimeout.
|
||||||
payment, err := h.ReceivePaymentUpdate(stream)
|
payment, err := h.receivePaymentUpdateWithTimeout(
|
||||||
|
stream, timeout,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("received error from payment "+
|
return fmt.Errorf("received error from payment "+
|
||||||
"stream: %s", err)
|
"stream: %s", err)
|
||||||
@@ -968,8 +980,17 @@ func (h *HarnessTest) assertPaymentStatusWithTimeout(stream rpc.PaymentClient,
|
|||||||
func (h *HarnessTest) ReceivePaymentUpdate(
|
func (h *HarnessTest) ReceivePaymentUpdate(
|
||||||
stream rpc.PaymentClient) (*lnrpc.Payment, error) {
|
stream rpc.PaymentClient) (*lnrpc.Payment, error) {
|
||||||
|
|
||||||
|
return h.receivePaymentUpdateWithTimeout(stream, DefaultTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// receivePaymentUpdateWithTimeout waits until a message is received on the
|
||||||
|
// payment client stream or the timeout is reached.
|
||||||
|
func (h *HarnessTest) receivePaymentUpdateWithTimeout(stream rpc.PaymentClient,
|
||||||
|
timeout time.Duration) (*lnrpc.Payment, error) {
|
||||||
|
|
||||||
chanMsg := make(chan *lnrpc.Payment, 1)
|
chanMsg := make(chan *lnrpc.Payment, 1)
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// Consume one message. This will block until the message is
|
// Consume one message. This will block until the message is
|
||||||
// received.
|
// received.
|
||||||
@@ -983,7 +1004,7 @@ func (h *HarnessTest) ReceivePaymentUpdate(
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(DefaultTimeout):
|
case <-time.After(timeout):
|
||||||
require.Fail(h, "timeout", "timeout waiting for payment update")
|
require.Fail(h, "timeout", "timeout waiting for payment update")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
||||||
|
|||||||
@@ -477,4 +477,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "wallet import pubkey",
|
Name: "wallet import pubkey",
|
||||||
TestFunc: testWalletImportPubKey,
|
TestFunc: testWalletImportPubKey,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "async payments benchmark",
|
||||||
|
TestFunc: testAsyncPayments,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"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/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -225,35 +226,31 @@ func testPaymentFollowingChannelOpen(ht *lntemp.HarnessTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// testAsyncPayments tests the performance of the async payments.
|
// testAsyncPayments tests the performance of the async payments.
|
||||||
func testAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
func testAsyncPayments(ht *lntemp.HarnessTest) {
|
||||||
runAsyncPayments(net, t, net.Alice, net.Bob)
|
// We use new nodes here as the benchmark test creates lots of data
|
||||||
|
// which can be costly to be carried on.
|
||||||
|
alice := ht.NewNode("Alice", []string{"--pending-commit-interval=3m"})
|
||||||
|
bob := ht.NewNode("Bob", []string{"--pending-commit-interval=3m"})
|
||||||
|
|
||||||
|
ht.EnsureConnected(alice, bob)
|
||||||
|
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
|
||||||
|
|
||||||
|
runAsyncPayments(ht, alice, bob)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runAsyncPayments tests the performance of the async payments.
|
// runAsyncPayments tests the performance of the async payments.
|
||||||
func runAsyncPayments(net *lntest.NetworkHarness, t *harnessTest, alice,
|
func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
|
||||||
bob *lntest.HarnessNode) {
|
const paymentAmt = 100
|
||||||
|
|
||||||
ctxb := context.Background()
|
|
||||||
|
|
||||||
const (
|
|
||||||
paymentAmt = 100
|
|
||||||
)
|
|
||||||
|
|
||||||
// First establish a channel with a capacity equals to the overall
|
// First establish a channel with a capacity equals to the overall
|
||||||
// amount of payments, between Alice and Bob, at the end of the test
|
// amount of payments, between Alice and Bob, at the end of the test
|
||||||
// Alice should send all money from her side to Bob.
|
// Alice should send all money from her side to Bob.
|
||||||
channelCapacity := btcutil.Amount(paymentAmt * 2000)
|
channelCapacity := btcutil.Amount(paymentAmt * 2000)
|
||||||
chanPoint := openChannelAndAssert(
|
chanPoint := ht.OpenChannel(
|
||||||
t, net, alice, bob,
|
alice, bob, lntemp.OpenChannelParams{Amt: channelCapacity},
|
||||||
lntest.OpenChannelParams{
|
|
||||||
Amt: channelCapacity,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
info, err := getChanInfo(alice)
|
info := ht.QueryChannelByChanPoint(alice, chanPoint)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get alice channel info: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll create a number of invoices equal the max number of HTLCs that
|
// We'll create a number of invoices equal the max number of HTLCs that
|
||||||
// can be carried in one direction. The number on the commitment will
|
// can be carried in one direction. The number on the commitment will
|
||||||
@@ -267,128 +264,95 @@ func runAsyncPayments(net *lntest.NetworkHarness, t *harnessTest, alice,
|
|||||||
|
|
||||||
// With the channel open, we'll create invoices for Bob that Alice
|
// With the channel open, we'll create invoices for Bob that Alice
|
||||||
// will pay to in order to advance the state of the channel.
|
// will pay to in order to advance the state of the channel.
|
||||||
bobPayReqs, _, _, err := createPayReqs(
|
bobPayReqs, _, _ := ht.CreatePayReqs(bob, paymentAmt, numInvoices)
|
||||||
bob, paymentAmt, numInvoices,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create pay reqs: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for Alice to receive the channel edge from the funding manager.
|
// Simultaneously send payments from Alice to Bob using of Bob's
|
||||||
err = alice.WaitForNetworkChannelOpen(chanPoint)
|
// payment hashes generated above.
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("alice didn't see the alice->bob channel before "+
|
|
||||||
"timeout: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simultaneously send payments from Alice to Bob using of Bob's payment
|
|
||||||
// hashes generated above.
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
errChan := make(chan error)
|
|
||||||
statusChan := make(chan *lnrpc.Payment)
|
settled := make(chan struct{})
|
||||||
|
defer close(settled)
|
||||||
|
|
||||||
|
timeout := lntest.AsyncBenchmarkTimeout * 2
|
||||||
for i := 0; i < numInvoices; i++ {
|
for i := 0; i < numInvoices; i++ {
|
||||||
payReq := bobPayReqs[i]
|
payReq := bobPayReqs[i]
|
||||||
go func() {
|
go func() {
|
||||||
ctxt, _ := context.WithTimeout(ctxb, lntest.AsyncBenchmarkTimeout)
|
req := &routerrpc.SendPaymentRequest{
|
||||||
stream, err := alice.RouterClient.SendPaymentV2(
|
PaymentRequest: payReq,
|
||||||
ctxt,
|
TimeoutSeconds: int32(timeout.Seconds()),
|
||||||
&routerrpc.SendPaymentRequest{
|
FeeLimitMsat: noFeeLimitMsat,
|
||||||
PaymentRequest: payReq,
|
|
||||||
TimeoutSeconds: 60,
|
|
||||||
FeeLimitMsat: noFeeLimitMsat,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
errChan <- err
|
|
||||||
}
|
|
||||||
result, err := getPaymentResult(stream)
|
|
||||||
if err != nil {
|
|
||||||
errChan <- err
|
|
||||||
}
|
}
|
||||||
|
// AssertPaymentStatusWithTimeout will assert that the
|
||||||
|
// payment is settled.
|
||||||
|
stream := alice.RPC.SendPayment(req)
|
||||||
|
ht.AssertPaymentSucceedWithTimeout(stream, timeout)
|
||||||
|
|
||||||
statusChan <- result
|
settled <- struct{}{}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until all the payments have settled.
|
// Wait until all the payments have settled.
|
||||||
|
timer := time.After(timeout)
|
||||||
for i := 0; i < numInvoices; i++ {
|
for i := 0; i < numInvoices; i++ {
|
||||||
select {
|
select {
|
||||||
case result := <-statusChan:
|
case <-settled:
|
||||||
if result.Status == lnrpc.Payment_SUCCEEDED {
|
case <-timer:
|
||||||
continue
|
require.Fail(ht, "timeout", "wait payment failed")
|
||||||
}
|
|
||||||
|
|
||||||
case err := <-errChan:
|
|
||||||
t.Fatalf("payment error: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All payments have been sent, mark the finish time.
|
// All payments have been sent, mark the finish time.
|
||||||
timeTaken := time.Since(now)
|
timeTaken := time.Since(now)
|
||||||
|
|
||||||
// Next query for Bob's and Alice's channel states, in order to confirm
|
// assertChannelState asserts the channel state by checking the values
|
||||||
// that all payment have been successful transmitted.
|
// in fields, LocalBalance, RemoteBalance and num of PendingHtlcs.
|
||||||
|
assertChannelState := func(hn *node.HarnessNode, cp *lnrpc.ChannelPoint,
|
||||||
|
localBalance, remoteBalance int64, numPendingHtlcs int) {
|
||||||
|
|
||||||
// Wait for the revocation to be received so alice no longer has pending
|
// Get the funding point.
|
||||||
// htlcs listed and has correct balances. This is needed due to the fact
|
err := wait.NoError(func() error {
|
||||||
// that we now pipeline the settles.
|
// Find the target channel first.
|
||||||
err = wait.Predicate(func() bool {
|
target := ht.GetChannelByChanPoint(hn, cp)
|
||||||
aliceChan, err := getChanInfo(alice)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(aliceChan.PendingHtlcs) != 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if aliceChan.RemoteBalance != bobAmt {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if aliceChan.LocalBalance != aliceAmt {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
if len(target.PendingHtlcs) != numPendingHtlcs {
|
||||||
}, defaultTimeout)
|
return fmt.Errorf("pending htlcs is "+
|
||||||
if err != nil {
|
"incorrect, got %v, expected %v",
|
||||||
t.Fatalf("failed to assert alice's pending htlcs and/or remote/local balance")
|
len(target.PendingHtlcs), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.LocalBalance != localBalance {
|
||||||
|
return fmt.Errorf("local balance is "+
|
||||||
|
"incorrect, got %v, expected %v",
|
||||||
|
target.LocalBalance, localBalance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.RemoteBalance != remoteBalance {
|
||||||
|
return fmt.Errorf("remote balance is "+
|
||||||
|
"incorrect, got %v, expected %v",
|
||||||
|
target.RemoteBalance, remoteBalance)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, lntemp.DefaultTimeout)
|
||||||
|
require.NoError(ht, err, "timeout while chekcing for balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the revocation to be received so alice no longer has
|
||||||
|
// pending htlcs listed and has correct balances. This is needed due to
|
||||||
|
// the fact that we now pipeline the settles.
|
||||||
|
assertChannelState(alice, chanPoint, aliceAmt, bobAmt, 0)
|
||||||
|
|
||||||
// Wait for Bob to receive revocation from Alice.
|
// Wait for Bob to receive revocation from Alice.
|
||||||
err = wait.NoError(func() error {
|
assertChannelState(bob, chanPoint, bobAmt, aliceAmt, 0)
|
||||||
bobChan, err := getChanInfo(bob)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get bob's channel info: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(bobChan.PendingHtlcs) != 0 {
|
ht.Log("\tBenchmark info: Elapsed time: ", timeTaken)
|
||||||
return fmt.Errorf("bob's pending htlcs is incorrect, "+
|
ht.Log("\tBenchmark info: TPS: ",
|
||||||
"got %v, expected %v",
|
float64(numInvoices)/timeTaken.Seconds())
|
||||||
len(bobChan.PendingHtlcs), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if bobChan.LocalBalance != bobAmt {
|
|
||||||
return fmt.Errorf("bob's local balance is incorrect, "+
|
|
||||||
"got %v, expected %v", bobChan.LocalBalance,
|
|
||||||
bobAmt)
|
|
||||||
}
|
|
||||||
|
|
||||||
if bobChan.RemoteBalance != aliceAmt {
|
|
||||||
return fmt.Errorf("bob's remote balance is incorrect, "+
|
|
||||||
"got %v, expected %v", bobChan.RemoteBalance,
|
|
||||||
aliceAmt)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}, defaultTimeout)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
t.Log("\tBenchmark info: Elapsed time: ", timeTaken)
|
|
||||||
t.Log("\tBenchmark info: TPS: ", float64(numInvoices)/timeTaken.Seconds())
|
|
||||||
|
|
||||||
// Finally, immediately close the channel. This function will also
|
// Finally, immediately close the channel. This function will also
|
||||||
// block until the channel is closed and will additionally assert the
|
// block until the channel is closed and will additionally assert the
|
||||||
// relevant channel closing post conditions.
|
// relevant channel closing post conditions.
|
||||||
closeChannelAndAssert(t, net, alice, chanPoint, false)
|
ht.CloseChannel(alice, chanPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// testBidirectionalAsyncPayments tests that nodes are able to send the
|
// testBidirectionalAsyncPayments tests that nodes are able to send the
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
package itest
|
package itest
|
||||||
|
|
||||||
var allTestCases = []*testCase{
|
var allTestCases = []*testCase{
|
||||||
{
|
|
||||||
name: "async payments benchmark",
|
|
||||||
test: testAsyncPayments,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "async bidirectional payments",
|
name: "async bidirectional payments",
|
||||||
test: testBidirectionalAsyncPayments,
|
test: testBidirectionalAsyncPayments,
|
||||||
|
|||||||
Reference in new issue
Block a user