itest: refactor testBidirectionalAsyncPayments

This commit is contained in:
yyforyongyu 2022-08-11 19:08:25 +08:00
parent 6618ab493a
commit e500074017
No known key found for this signature in database
GPG key ID: 9BCD95C4FF296868
3 changed files with 78 additions and 171 deletions

View file

@ -509,4 +509,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "zero conf reorg edge existence", Name: "zero conf reorg edge existence",
TestFunc: testZeroConfReorg, TestFunc: testZeroConfReorg,
}, },
{
Name: "async bidirectional payments",
TestFunc: testBidirectionalAsyncPayments,
},
} }

View file

@ -1,7 +1,6 @@
package itest package itest
import ( import (
"context"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@ -304,46 +303,13 @@ func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
// 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)
// assertChannelState asserts the channel state by checking the values
// in fields, LocalBalance, RemoteBalance and num of PendingHtlcs.
assertChannelState := func(hn *node.HarnessNode, cp *lnrpc.ChannelPoint,
localBalance, remoteBalance int64, numPendingHtlcs int) {
// Get the funding point.
err := wait.NoError(func() error {
// Find the target channel first.
target := ht.GetChannelByChanPoint(hn, cp)
if len(target.PendingHtlcs) != numPendingHtlcs {
return fmt.Errorf("pending htlcs is "+
"incorrect, got %v, expected %v",
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 // Wait for the revocation to be received so alice no longer has
// pending htlcs listed and has correct balances. This is needed due to // pending htlcs listed and has correct balances. This is needed due to
// the fact that we now pipeline the settles. // the fact that we now pipeline the settles.
assertChannelState(alice, chanPoint, aliceAmt, bobAmt, 0) assertChannelState(ht, alice, chanPoint, aliceAmt, bobAmt)
// Wait for Bob to receive revocation from Alice. // Wait for Bob to receive revocation from Alice.
assertChannelState(bob, chanPoint, bobAmt, aliceAmt, 0) assertChannelState(ht, bob, chanPoint, bobAmt, aliceAmt)
ht.Log("\tBenchmark info: Elapsed time: ", timeTaken) ht.Log("\tBenchmark info: Elapsed time: ", timeTaken)
ht.Log("\tBenchmark info: TPS: ", ht.Log("\tBenchmark info: TPS: ",
@ -357,28 +323,28 @@ func runAsyncPayments(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode) {
// testBidirectionalAsyncPayments tests that nodes are able to send the // testBidirectionalAsyncPayments tests that nodes are able to send the
// payments to each other in async manner without blocking. // payments to each other in async manner without blocking.
func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) { func testBidirectionalAsyncPayments(ht *lntemp.HarnessTest) {
ctxb := context.Background() const paymentAmt = 1000
const ( // We use new nodes here as the benchmark test creates lots of data
paymentAmt = 1000 // 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)
// 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.
chanPoint := openChannelAndAssert( chanPoint := ht.OpenChannel(
t, net, net.Alice, net.Bob, alice, bob, lntemp.OpenChannelParams{
lntest.OpenChannelParams{
Amt: paymentAmt * 2000, Amt: paymentAmt * 2000,
PushAmt: paymentAmt * 1000, PushAmt: paymentAmt * 1000,
}, },
) )
info, err := getChanInfo(net.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
@ -394,155 +360,64 @@ func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest)
// 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)
net.Bob, paymentAmt, numInvoices,
)
if err != nil {
t.Fatalf("unable to create pay reqs: %v", err)
}
// With the channel open, we'll create invoices for Alice that Bob // With the channel open, we'll create invoices for Alice that Bob
// will pay to in order to advance the state of the channel. // will pay to in order to advance the state of the channel.
alicePayReqs, _, _, err := createPayReqs( alicePayReqs, _, _ := ht.CreatePayReqs(alice, paymentAmt, numInvoices)
net.Alice, 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.
if err = net.Alice.WaitForNetworkChannelOpen(chanPoint); err != nil {
t.Fatalf("alice didn't see the alice->bob channel before "+
"timeout: %v", err)
}
if err = net.Bob.WaitForNetworkChannelOpen(chanPoint); err != nil {
t.Fatalf("bob didn't see the bob->alice channel before "+
"timeout: %v", err)
}
// Reset mission control to prevent previous payment results from // Reset mission control to prevent previous payment results from
// interfering with this test. A new channel has been opened, but // interfering with this test. A new channel has been opened, but
// mission control operates on node pairs. // mission control operates on node pairs.
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) alice.RPC.ResetMissionControl()
_, err = net.Alice.RouterClient.ResetMissionControl(
ctxt, &routerrpc.ResetMissionControlRequest{},
)
if err != nil {
t.Fatalf("unable to reset mc for alice: %v", err)
}
// Send payments from Alice to Bob and from Bob to Alice in async // Send payments from Alice to Bob and from Bob to Alice in async
// manner. // manner.
errChan := make(chan error) settled := make(chan struct{})
statusChan := make(chan *lnrpc.Payment) defer close(settled)
send := func(node *lntest.HarnessNode, payReq string) { timeout := lntest.AsyncBenchmarkTimeout * 4
go func() { send := func(node *node.HarnessNode, payReq string) {
ctxt, _ = context.WithTimeout( req := &routerrpc.SendPaymentRequest{
ctxb, lntest.AsyncBenchmarkTimeout, PaymentRequest: payReq,
) TimeoutSeconds: int32(timeout.Seconds()),
stream, err := node.RouterClient.SendPaymentV2( FeeLimitMsat: noFeeLimitMsat,
ctxt, }
&routerrpc.SendPaymentRequest{ // AssertPaymentStatusWithTimeout will assert that the
PaymentRequest: payReq, // payment is settled.
TimeoutSeconds: 60, stream := node.RPC.SendPayment(req)
FeeLimitMsat: noFeeLimitMsat, ht.AssertPaymentSucceedWithTimeout(stream, timeout)
},
)
if err != nil {
errChan <- err
}
result, err := getPaymentResult(stream)
if err != nil {
errChan <- err
}
statusChan <- result settled <- struct{}{}
}()
} }
for i := 0; i < numInvoices; i++ { for i := 0; i < numInvoices; i++ {
send(net.Bob, alicePayReqs[i]) go send(bob, alicePayReqs[i])
send(net.Alice, bobPayReqs[i]) go send(alice, bobPayReqs[i])
} }
// Expect all payments to succeed. // Expect all payments to succeed.
timer := time.After(timeout)
for i := 0; i < 2*numInvoices; i++ { for i := 0; i < 2*numInvoices; i++ {
select { select {
case result := <-statusChan: case <-settled:
if result.Status != lnrpc.Payment_SUCCEEDED { case <-timer:
t.Fatalf("payment error: %v", result.Status) require.Fail(ht, "timeout", "wait payment failed")
}
case err := <-errChan:
t.Fatalf("payment error: %v", err)
} }
} }
// Wait for Alice and Bob to receive revocations messages, and update // Wait for Alice and Bob to receive revocations messages, and update
// states, i.e. balance info. // states, i.e. balance info.
err = wait.NoError(func() error { assertChannelState(ht, alice, chanPoint, aliceAmt, bobAmt)
aliceInfo, err := getChanInfo(net.Alice)
if err != nil {
t.Fatalf("unable to get alice's channel info: %v", err)
}
if aliceInfo.RemoteBalance != bobAmt {
return fmt.Errorf("alice's remote balance is incorrect, "+
"got %v, expected %v", aliceInfo.RemoteBalance,
bobAmt)
}
if aliceInfo.LocalBalance != aliceAmt {
return fmt.Errorf("alice's local balance is incorrect, "+
"got %v, expected %v", aliceInfo.LocalBalance,
aliceAmt)
}
if len(aliceInfo.PendingHtlcs) != 0 {
return fmt.Errorf("alice's pending htlcs is incorrect, "+
"got %v expected %v",
len(aliceInfo.PendingHtlcs), 0)
}
return nil
}, defaultTimeout)
require.NoError(t.t, err)
// Next query for Bob's and Alice's channel states, in order to confirm // Next query for Bob's and Alice's channel states, in order to confirm
// that all payment have been successful transmitted. // that all payment have been successful transmitted.
err = wait.NoError(func() error { assertChannelState(ht, bob, chanPoint, bobAmt, aliceAmt)
bobInfo, err := getChanInfo(net.Bob)
if err != nil {
t.Fatalf("unable to get bob's channel info: %v", err)
}
if bobInfo.LocalBalance != bobAmt {
return fmt.Errorf("bob's local balance is incorrect, "+
"got %v, expected %v", bobInfo.LocalBalance,
bobAmt)
}
if bobInfo.RemoteBalance != aliceAmt {
return fmt.Errorf("bob's remote balance is incorrect, "+
"got %v, expected %v", bobInfo.RemoteBalance,
aliceAmt)
}
if len(bobInfo.PendingHtlcs) != 0 {
return fmt.Errorf("bob's pending htlcs is incorrect, "+
"got %v, expected %v",
len(bobInfo.PendingHtlcs), 0)
}
return nil
}, defaultTimeout)
require.NoError(t.t, err)
// 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, net.Alice, chanPoint, false) ht.CloseChannel(alice, chanPoint)
} }
func testInvoiceSubscriptions(ht *lntemp.HarnessTest) { func testInvoiceSubscriptions(ht *lntemp.HarnessTest) {
@ -672,3 +547,36 @@ func testInvoiceSubscriptions(ht *lntemp.HarnessTest) {
ht.CloseChannel(alice, chanPoint) ht.CloseChannel(alice, chanPoint)
} }
// assertChannelState asserts the channel state by checking the values in
// fields, LocalBalance, RemoteBalance and num of PendingHtlcs.
func assertChannelState(ht *lntemp.HarnessTest, hn *node.HarnessNode,
cp *lnrpc.ChannelPoint, localBalance, remoteBalance int64) {
// Get the funding point.
err := wait.NoError(func() error {
// Find the target channel first.
target := ht.GetChannelByChanPoint(hn, cp)
if len(target.PendingHtlcs) != 0 {
return fmt.Errorf("pending htlcs is "+
"incorrect, got %v, expected %v",
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")
}

View file

@ -3,9 +3,4 @@
package itest package itest
var allTestCases = []*testCase{ var allTestCases = []*testCase{}
{
name: "async bidirectional payments",
test: testBidirectionalAsyncPayments,
},
}