lntemp+itest: refactor testSwitchOfflineDelivery

This commit is contained in:
yyforyongyu 2022-08-09 19:04:36 +08:00
parent baeb78e2cc
commit 476434f546
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868
4 changed files with 26 additions and 263 deletions

View File

@ -127,6 +127,9 @@ func (h *HarnessTest) ConnectNodesPerm(a, b *node.HarnessNode) {
func (h *HarnessTest) DisconnectNodes(a, b *node.HarnessNode) {
bobInfo := b.RPC.GetInfo()
a.RPC.DisconnectPeer(bobInfo.IdentityPubkey)
// Assert disconnected.
h.AssertPeerNotConnected(a, b)
}
// EnsureConnected will try to connect to two nodes, returning no error if they

View File

@ -373,4 +373,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "switch circuit persistence",
TestFunc: testSwitchCircuitPersistence,
},
{
Name: "switch offline delivery",
TestFunc: testSwitchOfflineDelivery,
},
}

View File

@ -10,7 +10,6 @@ import (
"github.com/lightningnetwork/lnd/lntemp/node"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require"
)
const (
@ -100,244 +99,41 @@ func testSwitchCircuitPersistence(ht *lntemp.HarnessTest) {
// 2. Carol --- Dave X Alice --- Bob disconnect intermediaries
// 3. Carol --- Dave X Alice <-- Bob settle last hop
// 4. Carol <-- Dave <-- Alice --- Bob reconnect, expect settle to propagate
func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background()
const chanAmt = btcutil.Amount(1000000)
const pushAmt = btcutil.Amount(900000)
var networkChans []*lnrpc.ChannelPoint
// Open a channel with 100k satoshis between Alice and Bob with Alice
// being the sole funder of the channel.
chanPointAlice := openChannelAndAssert(
t, net, net.Alice, net.Bob,
lntest.OpenChannelParams{
Amt: chanAmt,
PushAmt: pushAmt,
},
)
networkChans = append(networkChans, chanPointAlice)
aliceChanTXID, err := lnrpc.GetChanPointFundingTxid(chanPointAlice)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
aliceFundPoint := wire.OutPoint{
Hash: *aliceChanTXID,
Index: chanPointAlice.OutputIndex,
}
// As preliminary setup, we'll create two new nodes: Carol and Dave,
// such that we now have a 4 ndoe, 3 channel topology. Dave will make
// a channel with Alice, and Carol with Dave. After this setup, the
// network topology should now look like:
// Carol -> Dave -> Alice -> Bob
//
// First, we'll create Dave and establish a channel to Alice.
dave := net.NewNode(t.t, "Dave", nil)
defer shutdownAndAssert(net, t, dave)
net.ConnectNodes(t.t, dave, net.Alice)
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, dave)
chanPointDave := openChannelAndAssert(
t, net, dave, net.Alice,
lntest.OpenChannelParams{
Amt: chanAmt,
PushAmt: pushAmt,
},
)
networkChans = append(networkChans, chanPointDave)
daveChanTXID, err := lnrpc.GetChanPointFundingTxid(chanPointDave)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
daveFundPoint := wire.OutPoint{
Hash: *daveChanTXID,
Index: chanPointDave.OutputIndex,
}
// Next, we'll create Carol and establish a channel to from her to
// Dave. Carol is started in htlchodl mode so that we can disconnect the
// intermediary hops before starting the settle.
carol := net.NewNode(t.t, "Carol", []string{"--hodl.exit-settle"})
defer shutdownAndAssert(net, t, carol)
net.ConnectNodes(t.t, carol, dave)
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, carol)
chanPointCarol := openChannelAndAssert(
t, net, carol, dave,
lntest.OpenChannelParams{
Amt: chanAmt,
PushAmt: pushAmt,
},
)
networkChans = append(networkChans, chanPointCarol)
carolChanTXID, err := lnrpc.GetChanPointFundingTxid(chanPointCarol)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
carolFundPoint := wire.OutPoint{
Hash: *carolChanTXID,
Index: chanPointCarol.OutputIndex,
}
// Wait for all nodes to have seen all channels.
nodes := []*lntest.HarnessNode{net.Alice, net.Bob, carol, dave}
nodeNames := []string{"Alice", "Bob", "Carol", "Dave"}
for _, chanPoint := range networkChans {
for i, node := range nodes {
txid, err := lnrpc.GetChanPointFundingTxid(chanPoint)
if err != nil {
t.Fatalf("unable to get txid: %v", err)
}
point := wire.OutPoint{
Hash: *txid,
Index: chanPoint.OutputIndex,
}
err = node.WaitForNetworkChannelOpen(chanPoint)
if err != nil {
t.Fatalf("%s(%d): timeout waiting for "+
"channel(%s) open: %v", nodeNames[i],
node.NodeID, point, err)
}
}
}
// Create 5 invoices for Carol, which expect a payment from Bob for 1k
// satoshis with a different preimage each time.
const numPayments = 5
const paymentAmt = 1000
payReqs, _, _, err := createPayReqs(
carol, paymentAmt, numPayments,
)
if err != nil {
t.Fatalf("unable to create pay reqs: %v", err)
}
// We'll wait for all parties to recognize the new channels within the
// network.
err = dave.WaitForNetworkChannelOpen(chanPointDave)
if err != nil {
t.Fatalf("dave didn't advertise his channel: %v", err)
}
err = carol.WaitForNetworkChannelOpen(chanPointCarol)
if err != nil {
t.Fatalf("carol didn't advertise her channel in time: %v",
err)
}
// Make sure all nodes are fully synced before we continue.
for _, node := range nodes {
err := node.WaitForBlockchainSync()
if err != nil {
t.Fatalf("unable to wait for sync: %v", err)
}
}
// Using Carol as the source, pay to the 5 invoices from Bob created
// above.
err = completePaymentRequests(
net.Bob, net.Bob.RouterClient, payReqs, false,
)
if err != nil {
t.Fatalf("unable to send payments: %v", err)
}
// Wait for all of the payments to reach Carol.
var predErr error
err = wait.Predicate(func() bool {
predErr = assertNumActiveHtlcs(nodes, numPayments)
return predErr == nil
}, defaultTimeout)
if err != nil {
t.Fatalf("htlc mismatch: %v", predErr)
}
peerReq := &lnrpc.PeerEventSubscription{}
peerClient, err := dave.SubscribePeerEvents(ctxb, peerReq)
require.NoError(t.t, err)
func testSwitchOfflineDelivery(ht *lntemp.HarnessTest) {
// Setup our test scenario. We should now have four nodes running with
// three channels.
s := setupScenarioFourNodes(ht)
defer s.cleanUp()
// First, disconnect Dave and Alice so that their link is broken.
if err := net.DisconnectNodes(dave, net.Alice); err != nil {
t.Fatalf("unable to disconnect alice from dave: %v", err)
}
// Wait to receive the PEER_OFFLINE event before reconnecting them.
peerEvent, err := peerClient.Recv()
require.NoError(t.t, err)
require.Equal(t.t, lnrpc.PeerEvent_PEER_OFFLINE, peerEvent.GetType())
ht.DisconnectNodes(s.dave, s.alice)
// Then, reconnect them to ensure Dave doesn't just fail back the htlc.
// We use EnsureConnected here in case they have already re-connected.
net.EnsureConnected(t.t, dave, net.Alice)
ht.ConnectNodes(s.dave, s.alice)
// Wait to ensure that the payment remain are not failed back after
// reconnecting. All node should report the number payments initiated
// for the duration of the interval.
err = wait.Invariant(func() bool {
predErr = assertNumActiveHtlcs(nodes, numPayments)
return predErr == nil
}, defaultTimeout)
if err != nil {
t.Fatalf("htlc change: %v", predErr)
}
s.assertHTLCs(ht, numPayments)
// Now, disconnect Dave from Alice again before settling back the
// payment.
if err := net.DisconnectNodes(dave, net.Alice); err != nil {
t.Fatalf("unable to disconnect alice from dave: %v", err)
}
// Wait to receive the PEER_ONLINE and then the PEER_OFFLINE event
// before advancing.
peerEvent2, err := peerClient.Recv()
require.NoError(t.t, err)
require.Equal(t.t, lnrpc.PeerEvent_PEER_ONLINE, peerEvent2.GetType())
peerEvent3, err := peerClient.Recv()
require.NoError(t.t, err)
require.Equal(t.t, lnrpc.PeerEvent_PEER_OFFLINE, peerEvent3.GetType())
ht.DisconnectNodes(s.dave, s.alice)
// Now restart carol without hodl mode, to settle back the outstanding
// payments.
carol.SetExtraArgs(nil)
if err := net.RestartNode(carol, nil); err != nil {
t.Fatalf("Node restart failed: %v", err)
}
s.carol.SetExtraArgs(nil)
ht.RestartNode(s.carol)
// Wait for Carol to report no outstanding htlcs.
carolNode := []*lntest.HarnessNode{carol}
err = wait.Predicate(func() bool {
predErr = assertNumActiveHtlcs(carolNode, 0)
return predErr == nil
}, defaultTimeout)
if err != nil {
t.Fatalf("htlc mismatch: %v", predErr)
}
// Make sure all nodes are fully synced again.
for _, node := range nodes {
err := node.WaitForBlockchainSync()
if err != nil {
t.Fatalf("unable to wait for sync: %v", err)
}
}
ht.AssertNumActiveHtlcs(s.carol, 0)
// Now that the settles have reached Dave, reconnect him with Alice,
// allowing the settles to return to the sender.
net.EnsureConnected(t.t, dave, net.Alice)
ht.EnsureConnected(s.dave, s.alice)
// Wait until all outstanding htlcs in the network have been settled.
err = wait.Predicate(func() bool {
return assertNumActiveHtlcs(nodes, 0) == nil
}, defaultTimeout)
if err != nil {
t.Fatalf("htlc mismatch: %v", predErr)
}
s.assertHTLCs(ht, 0)
// When asserting the amount of satoshis moved, we'll factor in the
// default base fee, as we didn't modify the fee structure when
@ -351,18 +147,7 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) {
// transaction, in channel Bob->Alice->David->Carol, order is Carol,
// David, Alice, Bob.
var amountPaid = int64(5000)
assertAmountPaid(t, "Dave(local) => Carol(remote)", carol,
carolFundPoint, int64(0), amountPaid)
assertAmountPaid(t, "Dave(local) => Carol(remote)", dave,
carolFundPoint, amountPaid, int64(0))
assertAmountPaid(t, "Alice(local) => Dave(remote)", dave,
daveFundPoint, int64(0), amountPaid+(baseFee*numPayments))
assertAmountPaid(t, "Alice(local) => Dave(remote)", net.Alice,
daveFundPoint, amountPaid+(baseFee*numPayments), int64(0))
assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Alice,
aliceFundPoint, int64(0), amountPaid+((baseFee*numPayments)*2))
assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Bob,
aliceFundPoint, amountPaid+(baseFee*numPayments)*2, int64(0))
s.assertAmoutPaid(ht, amountPaid, numPayments)
// Lastly, we will send one more payment to ensure all channels are
// still functioning properly.
@ -370,40 +155,15 @@ func testSwitchOfflineDelivery(net *lntest.NetworkHarness, t *harnessTest) {
Memo: "testing",
Value: paymentAmt,
}
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
resp, err := carol.AddInvoice(ctxt, finalInvoice)
if err != nil {
t.Fatalf("unable to add invoice: %v", err)
}
payReqs = []string{resp.PaymentRequest}
resp := s.carol.RPC.AddInvoice(finalInvoice)
payReqs := []string{resp.PaymentRequest}
// Using Carol as the source, pay to the 5 invoices from Bob created
// above.
err = completePaymentRequests(
net.Bob, net.Bob.RouterClient, payReqs, true,
)
if err != nil {
t.Fatalf("unable to send payments: %v", err)
}
ht.CompletePaymentRequests(s.bob, payReqs)
amountPaid = int64(6000)
assertAmountPaid(t, "Dave(local) => Carol(remote)", carol,
carolFundPoint, int64(0), amountPaid)
assertAmountPaid(t, "Dave(local) => Carol(remote)", dave,
carolFundPoint, amountPaid, int64(0))
assertAmountPaid(t, "Alice(local) => Dave(remote)", dave,
daveFundPoint, int64(0), amountPaid+(baseFee*(numPayments+1)))
assertAmountPaid(t, "Alice(local) => Dave(remote)", net.Alice,
daveFundPoint, amountPaid+(baseFee*(numPayments+1)), int64(0))
assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Alice,
aliceFundPoint, int64(0), amountPaid+((baseFee*(numPayments+1))*2))
assertAmountPaid(t, "Bob(local) => Alice(remote)", net.Bob,
aliceFundPoint, amountPaid+(baseFee*(numPayments+1))*2, int64(0))
closeChannelAndAssert(t, net, net.Alice, chanPointAlice, false)
closeChannelAndAssert(t, net, dave, chanPointDave, false)
closeChannelAndAssert(t, net, carol, chanPointCarol, false)
s.assertAmoutPaid(ht, amountPaid, numPayments+1)
}
// testSwitchOfflineDeliveryPersistence constructs a set of multihop payments,

View File

@ -28,10 +28,6 @@ var allTestCases = []*testCase{
name: "async bidirectional payments",
test: testBidirectionalAsyncPayments,
},
{
name: "switch offline delivery",
test: testSwitchOfflineDelivery,
},
{
name: "switch offline delivery persistence",
test: testSwitchOfflineDeliveryPersistence,