From 47c40373deeca35529a0bbb1d2a724fbeb03df03 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 29 Jun 2021 04:10:33 +0800 Subject: [PATCH] itest: move channel policy update test into one file --- lntest/itest/lnd_channel_policy_test.go | 564 ++++++++++++++++++++++++ lntest/itest/lnd_test.go | 551 ----------------------- 2 files changed, 564 insertions(+), 551 deletions(-) create mode 100644 lntest/itest/lnd_channel_policy_test.go diff --git a/lntest/itest/lnd_channel_policy_test.go b/lntest/itest/lnd_channel_policy_test.go new file mode 100644 index 00000000..0cac0f38 --- /dev/null +++ b/lntest/itest/lnd_channel_policy_test.go @@ -0,0 +1,564 @@ +package itest + +import ( + "context" + "strings" + + "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/chainreg" + "github.com/lightningnetwork/lnd/funding" + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lntest" + "github.com/lightningnetwork/lnd/lnwire" +) + +// testUpdateChannelPolicy tests that policy updates made to a channel +// gets propagated to other nodes in the network. +func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { + ctxb := context.Background() + + const ( + defaultFeeBase = 1000 + defaultFeeRate = 1 + defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta + defaultMinHtlc = 1000 + ) + defaultMaxHtlc := calculateMaxHtlc(funding.MaxBtcFundingAmount) + + // Launch notification clients for all nodes, such that we can + // get notified when they discover new channels and updates in the + // graph. + aliceSub := subscribeGraphNotifications(ctxb, t, net.Alice) + defer close(aliceSub.quit) + bobSub := subscribeGraphNotifications(ctxb, t, net.Bob) + defer close(bobSub.quit) + + chanAmt := funding.MaxBtcFundingAmount + pushAmt := chanAmt / 2 + + // Create a channel Alice->Bob. + ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) + chanPoint := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, + lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + }, + ) + + // We add all the nodes' update channels to a slice, such that we can + // make sure they all receive the expected updates. + graphSubs := []graphSubscription{aliceSub, bobSub} + nodes := []*lntest.HarnessNode{net.Alice, net.Bob} + + // Alice and Bob should see each other's ChannelUpdates, advertising the + // default routing policies. + expectedPolicy := &lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultFeeBase, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + + for _, graphSub := range graphSubs { + waitForChannelUpdate( + t, graphSub, + []expectedChanUpdate{ + {net.Alice.PubKeyStr, expectedPolicy, chanPoint}, + {net.Bob.PubKeyStr, expectedPolicy, chanPoint}, + }, + ) + } + + // They should now know about the default policies. + for _, node := range nodes { + assertChannelPolicy( + t, node, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + ) + assertChannelPolicy( + t, node, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint) + if err != nil { + t.Fatalf("alice didn't report channel: %v", err) + } + err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint) + if err != nil { + t.Fatalf("bob didn't report channel: %v", err) + } + + // Create Carol with options to rate limit channel updates up to 2 per + // day, and create a new channel Bob->Carol. + carol := net.NewNode( + t.t, "Carol", []string{ + "--gossip.max-channel-update-burst=2", + "--gossip.channel-update-interval=24h", + }, + ) + + // Clean up carol's node when the test finishes. + defer shutdownAndAssert(net, t, carol) + + carolSub := subscribeGraphNotifications(ctxb, t, carol) + defer close(carolSub.quit) + + graphSubs = append(graphSubs, carolSub) + nodes = append(nodes, carol) + + // Send some coins to Carol that can be used for channel funding. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + net.SendCoins(ctxt, t.t, btcutil.SatoshiPerBitcoin, carol) + + net.ConnectNodes(ctxb, t.t, carol, net.Bob) + + // Open the channel Carol->Bob with a custom min_htlc value set. Since + // Carol is opening the channel, she will require Bob to not forward + // HTLCs smaller than this value, and hence he should advertise it as + // part of his ChannelUpdate. + const customMinHtlc = 5000 + ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) + chanPoint2 := openChannelAndAssert( + ctxt, t, net, carol, net.Bob, + lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + MinHtlc: customMinHtlc, + }, + ) + + expectedPolicyBob := &lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultFeeBase, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: customMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + expectedPolicyCarol := &lnrpc.RoutingPolicy{ + FeeBaseMsat: defaultFeeBase, + FeeRateMilliMsat: defaultFeeRate, + TimeLockDelta: defaultTimeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: defaultMaxHtlc, + } + + for _, graphSub := range graphSubs { + waitForChannelUpdate( + t, graphSub, + []expectedChanUpdate{ + {net.Bob.PubKeyStr, expectedPolicyBob, chanPoint2}, + {carol.PubKeyStr, expectedPolicyCarol, chanPoint2}, + }, + ) + } + + // Check that all nodes now know about the updated policies. + for _, node := range nodes { + assertChannelPolicy( + t, node, net.Bob.PubKeyStr, expectedPolicyBob, + chanPoint2, + ) + assertChannelPolicy( + t, node, carol.PubKeyStr, expectedPolicyCarol, + chanPoint2, + ) + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint2) + if err != nil { + t.Fatalf("alice didn't report channel: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint2) + if err != nil { + t.Fatalf("bob didn't report channel: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = carol.WaitForNetworkChannelOpen(ctxt, chanPoint2) + if err != nil { + t.Fatalf("carol didn't report channel: %v", err) + } + + // First we'll try to send a payment from Alice to Carol with an amount + // less than the min_htlc value required by Carol. This payment should + // fail, as the channel Bob->Carol cannot carry HTLCs this small. + payAmt := btcutil.Amount(4) + invoice := &lnrpc.Invoice{ + Memo: "testing", + Value: int64(payAmt), + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := carol.AddInvoice(ctxt, invoice) + if err != nil { + t.Fatalf("unable to add invoice: %v", err) + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = completePaymentRequests( + ctxt, net.Alice, net.Alice.RouterClient, + []string{resp.PaymentRequest}, true, + ) + + // Alice knows about the channel policy of Carol and should therefore + // not be able to find a path during routing. + expErr := lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE + if err.Error() != expErr.String() { + t.Fatalf("expected %v, instead got %v", expErr, err) + } + + // Now we try to send a payment over the channel with a value too low + // to be accepted. First we query for a route to route a payment of + // 5000 mSAT, as this is accepted. + payAmt = btcutil.Amount(5) + routesReq := &lnrpc.QueryRoutesRequest{ + PubKey: carol.PubKeyStr, + Amt: int64(payAmt), + FinalCltvDelta: defaultTimeLockDelta, + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + routes, err := net.Alice.QueryRoutes(ctxt, routesReq) + if err != nil { + t.Fatalf("unable to get route: %v", err) + } + + if len(routes.Routes) != 1 { + t.Fatalf("expected to find 1 route, got %v", len(routes.Routes)) + } + + // We change the route to carry a payment of 4000 mSAT instead of 5000 + // mSAT. + payAmt = btcutil.Amount(4) + amtSat := int64(payAmt) + amtMSat := int64(lnwire.NewMSatFromSatoshis(payAmt)) + routes.Routes[0].Hops[0].AmtToForward = amtSat + routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat + routes.Routes[0].Hops[1].AmtToForward = amtSat + routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat + + // Send the payment with the modified value. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + alicePayStream, err := net.Alice.SendToRoute(ctxt) + if err != nil { + t.Fatalf("unable to create payment stream for alice: %v", err) + } + sendReq := &lnrpc.SendToRouteRequest{ + PaymentHash: resp.RHash, + Route: routes.Routes[0], + } + + err = alicePayStream.Send(sendReq) + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + // We expect this payment to fail, and that the min_htlc value is + // communicated back to us, since the attempted HTLC value was too low. + sendResp, err := alicePayStream.Recv() + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + // Expected as part of the error message. + substrs := []string{ + "AmountBelowMinimum", + "HtlcMinimumMsat: (lnwire.MilliSatoshi) 5000 mSAT", + } + for _, s := range substrs { + if !strings.Contains(sendResp.PaymentError, s) { + t.Fatalf("expected error to contain \"%v\", instead "+ + "got %v", s, sendResp.PaymentError) + } + } + + // Make sure sending using the original value succeeds. + payAmt = btcutil.Amount(5) + amtSat = int64(payAmt) + amtMSat = int64(lnwire.NewMSatFromSatoshis(payAmt)) + routes.Routes[0].Hops[0].AmtToForward = amtSat + routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat + routes.Routes[0].Hops[1].AmtToForward = amtSat + routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat + + // Manually set the MPP payload a new for each payment since + // the payment addr will change with each invoice, although we + // can re-use the route itself. + route := routes.Routes[0] + route.Hops[len(route.Hops)-1].TlvPayload = true + route.Hops[len(route.Hops)-1].MppRecord = &lnrpc.MPPRecord{ + PaymentAddr: resp.PaymentAddr, + TotalAmtMsat: amtMSat, + } + + sendReq = &lnrpc.SendToRouteRequest{ + PaymentHash: resp.RHash, + Route: route, + } + + err = alicePayStream.Send(sendReq) + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + sendResp, err = alicePayStream.Recv() + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + if sendResp.PaymentError != "" { + t.Fatalf("expected payment to succeed, instead got %v", + sendResp.PaymentError) + } + + // With our little cluster set up, we'll update the fees and the max htlc + // size for the Bob side of the Alice->Bob channel, and make sure + // all nodes learn about it. + baseFee := int64(1500) + feeRate := int64(12) + timeLockDelta := uint32(66) + maxHtlc := uint64(500000) + + expectedPolicy = &lnrpc.RoutingPolicy{ + FeeBaseMsat: baseFee, + FeeRateMilliMsat: testFeeBase * feeRate, + TimeLockDelta: timeLockDelta, + MinHtlc: defaultMinHtlc, + MaxHtlcMsat: maxHtlc, + } + + req := &lnrpc.PolicyUpdateRequest{ + BaseFeeMsat: baseFee, + FeeRate: float64(feeRate), + TimeLockDelta: timeLockDelta, + MaxHtlcMsat: maxHtlc, + Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ + ChanPoint: chanPoint, + }, + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + if _, err := net.Bob.UpdateChannelPolicy(ctxt, req); err != nil { + t.Fatalf("unable to get alice's balance: %v", err) + } + + // Wait for all nodes to have seen the policy update done by Bob. + for _, graphSub := range graphSubs { + waitForChannelUpdate( + t, graphSub, + []expectedChanUpdate{ + {net.Bob.PubKeyStr, expectedPolicy, chanPoint}, + }, + ) + } + + // Check that all nodes now know about Bob's updated policy. + for _, node := range nodes { + assertChannelPolicy( + t, node, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) + } + + // Now that all nodes have received the new channel update, we'll try + // to send a payment from Alice to Carol to ensure that Alice has + // internalized this fee update. This shouldn't affect the route that + // Alice takes though: we updated the Alice -> Bob channel and she + // doesn't pay for transit over that channel as it's direct. + // Note that the payment amount is >= the min_htlc value for the + // channel Bob->Carol, so it should successfully be forwarded. + payAmt = btcutil.Amount(5) + invoice = &lnrpc.Invoice{ + Memo: "testing", + Value: int64(payAmt), + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err = carol.AddInvoice(ctxt, invoice) + if err != nil { + t.Fatalf("unable to add invoice: %v", err) + } + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = completePaymentRequests( + ctxt, net.Alice, net.Alice.RouterClient, + []string{resp.PaymentRequest}, true, + ) + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + // We'll now open a channel from Alice directly to Carol. + net.ConnectNodes(ctxb, t.t, net.Alice, carol) + ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) + chanPoint3 := openChannelAndAssert( + ctxt, t, net, net.Alice, carol, + lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + }, + ) + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint3) + if err != nil { + t.Fatalf("alice didn't report channel: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = carol.WaitForNetworkChannelOpen(ctxt, chanPoint3) + if err != nil { + t.Fatalf("bob didn't report channel: %v", err) + } + + // Make a global update, and check that both channels' new policies get + // propagated. + baseFee = int64(800) + feeRate = int64(123) + timeLockDelta = uint32(22) + maxHtlc *= 2 + + expectedPolicy.FeeBaseMsat = baseFee + expectedPolicy.FeeRateMilliMsat = testFeeBase * feeRate + expectedPolicy.TimeLockDelta = timeLockDelta + expectedPolicy.MaxHtlcMsat = maxHtlc + + req = &lnrpc.PolicyUpdateRequest{ + BaseFeeMsat: baseFee, + FeeRate: float64(feeRate), + TimeLockDelta: timeLockDelta, + MaxHtlcMsat: maxHtlc, + } + req.Scope = &lnrpc.PolicyUpdateRequest_Global{} + + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + _, err = net.Alice.UpdateChannelPolicy(ctxt, req) + if err != nil { + t.Fatalf("unable to update alice's channel policy: %v", err) + } + + // Wait for all nodes to have seen the policy updates for both of + // Alice's channels. + for _, graphSub := range graphSubs { + waitForChannelUpdate( + t, graphSub, + []expectedChanUpdate{ + {net.Alice.PubKeyStr, expectedPolicy, chanPoint}, + {net.Alice.PubKeyStr, expectedPolicy, chanPoint3}, + }, + ) + } + + // And finally check that all nodes remembers the policy update they + // received. + for _, node := range nodes { + assertChannelPolicy( + t, node, net.Alice.PubKeyStr, expectedPolicy, + chanPoint, chanPoint3, + ) + } + + // Now, to test that Carol is properly rate limiting incoming updates, + // we'll send two more update from Alice. Carol should accept the first, + // but not the second, as she only allows two updates per day and a day + // has yet to elapse from the previous update. + const numUpdatesTilRateLimit = 2 + for i := 0; i < numUpdatesTilRateLimit; i++ { + prevAlicePolicy := *expectedPolicy + baseFee *= 2 + expectedPolicy.FeeBaseMsat = baseFee + req.BaseFeeMsat = baseFee + + ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) + defer cancel() + _, err = net.Alice.UpdateChannelPolicy(ctxt, req) + if err != nil { + t.Fatalf("unable to update alice's channel policy: %v", err) + } + + // Wait for all nodes to have seen the policy updates for both + // of Alice's channels. Carol will not see the last update as + // the limit has been reached. + for idx, graphSub := range graphSubs { + expUpdates := []expectedChanUpdate{ + {net.Alice.PubKeyStr, expectedPolicy, chanPoint}, + {net.Alice.PubKeyStr, expectedPolicy, chanPoint3}, + } + // Carol was added last, which is why we check the last + // index. + if i == numUpdatesTilRateLimit-1 && idx == len(graphSubs)-1 { + expUpdates = nil + } + waitForChannelUpdate(t, graphSub, expUpdates) + } + + // And finally check that all nodes remembers the policy update + // they received. Since Carol didn't receive the last update, + // she still has Alice's old policy. + for idx, node := range nodes { + policy := expectedPolicy + // Carol was added last, which is why we check the last + // index. + if i == numUpdatesTilRateLimit-1 && idx == len(nodes)-1 { + policy = &prevAlicePolicy + } + assertChannelPolicy( + t, node, net.Alice.PubKeyStr, policy, chanPoint, + chanPoint3, + ) + } + } + + // Close the channels. + ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) + closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) + ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) + closeChannelAndAssert(ctxt, t, net, net.Bob, chanPoint2, false) + ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) + closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint3, false) +} + +// updateChannelPolicy updates the channel policy of node to the +// given fees and timelock delta. This function blocks until +// listenerNode has received the policy update. +func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode, + chanPoint *lnrpc.ChannelPoint, baseFee int64, feeRate int64, + timeLockDelta uint32, maxHtlc uint64, listenerNode *lntest.HarnessNode) { + + ctxb := context.Background() + + expectedPolicy := &lnrpc.RoutingPolicy{ + FeeBaseMsat: baseFee, + FeeRateMilliMsat: feeRate, + TimeLockDelta: timeLockDelta, + MinHtlc: 1000, // default value + MaxHtlcMsat: maxHtlc, + } + + updateFeeReq := &lnrpc.PolicyUpdateRequest{ + BaseFeeMsat: baseFee, + FeeRate: float64(feeRate) / testFeeBase, + TimeLockDelta: timeLockDelta, + Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ + ChanPoint: chanPoint, + }, + MaxHtlcMsat: maxHtlc, + } + + ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) + if _, err := node.UpdateChannelPolicy(ctxt, updateFeeReq); err != nil { + t.Fatalf("unable to update chan policy: %v", err) + } + + // Wait for listener node to receive the channel update from node. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + graphSub := subscribeGraphNotifications(ctxt, t, listenerNode) + defer close(graphSub.quit) + + waitForChannelUpdate( + t, graphSub, + []expectedChanUpdate{ + {node.PubKeyStr, expectedPolicy, chanPoint}, + }, + ) +} diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go index 82d427e4..9974ba6e 100644 --- a/lntest/itest/lnd_test.go +++ b/lntest/itest/lnd_test.go @@ -737,512 +737,6 @@ func calculateMaxHtlc(chanCap btcutil.Amount) uint64 { return uint64(max) } -// testUpdateChannelPolicy tests that policy updates made to a channel -// gets propagated to other nodes in the network. -func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { - ctxb := context.Background() - - const ( - defaultFeeBase = 1000 - defaultFeeRate = 1 - defaultTimeLockDelta = chainreg.DefaultBitcoinTimeLockDelta - defaultMinHtlc = 1000 - ) - defaultMaxHtlc := calculateMaxHtlc(funding.MaxBtcFundingAmount) - - // Launch notification clients for all nodes, such that we can - // get notified when they discover new channels and updates in the - // graph. - aliceSub := subscribeGraphNotifications(ctxb, t, net.Alice) - defer close(aliceSub.quit) - bobSub := subscribeGraphNotifications(ctxb, t, net.Bob) - defer close(bobSub.quit) - - chanAmt := funding.MaxBtcFundingAmount - pushAmt := chanAmt / 2 - - // Create a channel Alice->Bob. - ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) - chanPoint := openChannelAndAssert( - ctxt, t, net, net.Alice, net.Bob, - lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - }, - ) - - // We add all the nodes' update channels to a slice, such that we can - // make sure they all receive the expected updates. - graphSubs := []graphSubscription{aliceSub, bobSub} - nodes := []*lntest.HarnessNode{net.Alice, net.Bob} - - // Alice and Bob should see each other's ChannelUpdates, advertising the - // default routing policies. - expectedPolicy := &lnrpc.RoutingPolicy{ - FeeBaseMsat: defaultFeeBase, - FeeRateMilliMsat: defaultFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - } - - for _, graphSub := range graphSubs { - waitForChannelUpdate( - t, graphSub, - []expectedChanUpdate{ - {net.Alice.PubKeyStr, expectedPolicy, chanPoint}, - {net.Bob.PubKeyStr, expectedPolicy, chanPoint}, - }, - ) - } - - // They should now know about the default policies. - for _, node := range nodes { - assertChannelPolicy( - t, node, net.Alice.PubKeyStr, expectedPolicy, chanPoint, - ) - assertChannelPolicy( - t, node, net.Bob.PubKeyStr, expectedPolicy, chanPoint, - ) - } - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err := net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint) - if err != nil { - t.Fatalf("alice didn't report channel: %v", err) - } - err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint) - if err != nil { - t.Fatalf("bob didn't report channel: %v", err) - } - - // Create Carol with options to rate limit channel updates up to 2 per - // day, and create a new channel Bob->Carol. - carol := net.NewNode( - t.t, "Carol", []string{ - "--gossip.max-channel-update-burst=2", - "--gossip.channel-update-interval=24h", - }, - ) - - // Clean up carol's node when the test finishes. - defer shutdownAndAssert(net, t, carol) - - carolSub := subscribeGraphNotifications(ctxb, t, carol) - defer close(carolSub.quit) - - graphSubs = append(graphSubs, carolSub) - nodes = append(nodes, carol) - - // Send some coins to Carol that can be used for channel funding. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - net.SendCoins(ctxt, t.t, btcutil.SatoshiPerBitcoin, carol) - - net.ConnectNodes(ctxb, t.t, carol, net.Bob) - - // Open the channel Carol->Bob with a custom min_htlc value set. Since - // Carol is opening the channel, she will require Bob to not forward - // HTLCs smaller than this value, and hence he should advertise it as - // part of his ChannelUpdate. - const customMinHtlc = 5000 - ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) - chanPoint2 := openChannelAndAssert( - ctxt, t, net, carol, net.Bob, - lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - MinHtlc: customMinHtlc, - }, - ) - - expectedPolicyBob := &lnrpc.RoutingPolicy{ - FeeBaseMsat: defaultFeeBase, - FeeRateMilliMsat: defaultFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: customMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - } - expectedPolicyCarol := &lnrpc.RoutingPolicy{ - FeeBaseMsat: defaultFeeBase, - FeeRateMilliMsat: defaultFeeRate, - TimeLockDelta: defaultTimeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: defaultMaxHtlc, - } - - for _, graphSub := range graphSubs { - waitForChannelUpdate( - t, graphSub, - []expectedChanUpdate{ - {net.Bob.PubKeyStr, expectedPolicyBob, chanPoint2}, - {carol.PubKeyStr, expectedPolicyCarol, chanPoint2}, - }, - ) - } - - // Check that all nodes now know about the updated policies. - for _, node := range nodes { - assertChannelPolicy( - t, node, net.Bob.PubKeyStr, expectedPolicyBob, - chanPoint2, - ) - assertChannelPolicy( - t, node, carol.PubKeyStr, expectedPolicyCarol, - chanPoint2, - ) - } - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint2) - if err != nil { - t.Fatalf("alice didn't report channel: %v", err) - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint2) - if err != nil { - t.Fatalf("bob didn't report channel: %v", err) - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = carol.WaitForNetworkChannelOpen(ctxt, chanPoint2) - if err != nil { - t.Fatalf("carol didn't report channel: %v", err) - } - - // First we'll try to send a payment from Alice to Carol with an amount - // less than the min_htlc value required by Carol. This payment should - // fail, as the channel Bob->Carol cannot carry HTLCs this small. - payAmt := btcutil.Amount(4) - invoice := &lnrpc.Invoice{ - Memo: "testing", - Value: int64(payAmt), - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - resp, err := carol.AddInvoice(ctxt, invoice) - if err != nil { - t.Fatalf("unable to add invoice: %v", err) - } - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = completePaymentRequests( - ctxt, net.Alice, net.Alice.RouterClient, - []string{resp.PaymentRequest}, true, - ) - - // Alice knows about the channel policy of Carol and should therefore - // not be able to find a path during routing. - expErr := lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE - if err.Error() != expErr.String() { - t.Fatalf("expected %v, instead got %v", expErr, err) - } - - // Now we try to send a payment over the channel with a value too low - // to be accepted. First we query for a route to route a payment of - // 5000 mSAT, as this is accepted. - payAmt = btcutil.Amount(5) - routesReq := &lnrpc.QueryRoutesRequest{ - PubKey: carol.PubKeyStr, - Amt: int64(payAmt), - FinalCltvDelta: defaultTimeLockDelta, - } - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - routes, err := net.Alice.QueryRoutes(ctxt, routesReq) - if err != nil { - t.Fatalf("unable to get route: %v", err) - } - - if len(routes.Routes) != 1 { - t.Fatalf("expected to find 1 route, got %v", len(routes.Routes)) - } - - // We change the route to carry a payment of 4000 mSAT instead of 5000 - // mSAT. - payAmt = btcutil.Amount(4) - amtSat := int64(payAmt) - amtMSat := int64(lnwire.NewMSatFromSatoshis(payAmt)) - routes.Routes[0].Hops[0].AmtToForward = amtSat - routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat - routes.Routes[0].Hops[1].AmtToForward = amtSat - routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat - - // Send the payment with the modified value. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - alicePayStream, err := net.Alice.SendToRoute(ctxt) - if err != nil { - t.Fatalf("unable to create payment stream for alice: %v", err) - } - sendReq := &lnrpc.SendToRouteRequest{ - PaymentHash: resp.RHash, - Route: routes.Routes[0], - } - - err = alicePayStream.Send(sendReq) - if err != nil { - t.Fatalf("unable to send payment: %v", err) - } - - // We expect this payment to fail, and that the min_htlc value is - // communicated back to us, since the attempted HTLC value was too low. - sendResp, err := alicePayStream.Recv() - if err != nil { - t.Fatalf("unable to send payment: %v", err) - } - - // Expected as part of the error message. - substrs := []string{ - "AmountBelowMinimum", - "HtlcMinimumMsat: (lnwire.MilliSatoshi) 5000 mSAT", - } - for _, s := range substrs { - if !strings.Contains(sendResp.PaymentError, s) { - t.Fatalf("expected error to contain \"%v\", instead "+ - "got %v", s, sendResp.PaymentError) - } - } - - // Make sure sending using the original value succeeds. - payAmt = btcutil.Amount(5) - amtSat = int64(payAmt) - amtMSat = int64(lnwire.NewMSatFromSatoshis(payAmt)) - routes.Routes[0].Hops[0].AmtToForward = amtSat - routes.Routes[0].Hops[0].AmtToForwardMsat = amtMSat - routes.Routes[0].Hops[1].AmtToForward = amtSat - routes.Routes[0].Hops[1].AmtToForwardMsat = amtMSat - - // Manually set the MPP payload a new for each payment since - // the payment addr will change with each invoice, although we - // can re-use the route itself. - route := routes.Routes[0] - route.Hops[len(route.Hops)-1].TlvPayload = true - route.Hops[len(route.Hops)-1].MppRecord = &lnrpc.MPPRecord{ - PaymentAddr: resp.PaymentAddr, - TotalAmtMsat: amtMSat, - } - - sendReq = &lnrpc.SendToRouteRequest{ - PaymentHash: resp.RHash, - Route: route, - } - - err = alicePayStream.Send(sendReq) - if err != nil { - t.Fatalf("unable to send payment: %v", err) - } - - sendResp, err = alicePayStream.Recv() - if err != nil { - t.Fatalf("unable to send payment: %v", err) - } - - if sendResp.PaymentError != "" { - t.Fatalf("expected payment to succeed, instead got %v", - sendResp.PaymentError) - } - - // With our little cluster set up, we'll update the fees and the max htlc - // size for the Bob side of the Alice->Bob channel, and make sure - // all nodes learn about it. - baseFee := int64(1500) - feeRate := int64(12) - timeLockDelta := uint32(66) - maxHtlc := uint64(500000) - - expectedPolicy = &lnrpc.RoutingPolicy{ - FeeBaseMsat: baseFee, - FeeRateMilliMsat: testFeeBase * feeRate, - TimeLockDelta: timeLockDelta, - MinHtlc: defaultMinHtlc, - MaxHtlcMsat: maxHtlc, - } - - req := &lnrpc.PolicyUpdateRequest{ - BaseFeeMsat: baseFee, - FeeRate: float64(feeRate), - TimeLockDelta: timeLockDelta, - MaxHtlcMsat: maxHtlc, - Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ - ChanPoint: chanPoint, - }, - } - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - if _, err := net.Bob.UpdateChannelPolicy(ctxt, req); err != nil { - t.Fatalf("unable to get alice's balance: %v", err) - } - - // Wait for all nodes to have seen the policy update done by Bob. - for _, graphSub := range graphSubs { - waitForChannelUpdate( - t, graphSub, - []expectedChanUpdate{ - {net.Bob.PubKeyStr, expectedPolicy, chanPoint}, - }, - ) - } - - // Check that all nodes now know about Bob's updated policy. - for _, node := range nodes { - assertChannelPolicy( - t, node, net.Bob.PubKeyStr, expectedPolicy, chanPoint, - ) - } - - // Now that all nodes have received the new channel update, we'll try - // to send a payment from Alice to Carol to ensure that Alice has - // internalized this fee update. This shouldn't affect the route that - // Alice takes though: we updated the Alice -> Bob channel and she - // doesn't pay for transit over that channel as it's direct. - // Note that the payment amount is >= the min_htlc value for the - // channel Bob->Carol, so it should successfully be forwarded. - payAmt = btcutil.Amount(5) - invoice = &lnrpc.Invoice{ - Memo: "testing", - Value: int64(payAmt), - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - resp, err = carol.AddInvoice(ctxt, invoice) - if err != nil { - t.Fatalf("unable to add invoice: %v", err) - } - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = completePaymentRequests( - ctxt, net.Alice, net.Alice.RouterClient, - []string{resp.PaymentRequest}, true, - ) - if err != nil { - t.Fatalf("unable to send payment: %v", err) - } - - // We'll now open a channel from Alice directly to Carol. - net.ConnectNodes(ctxb, t.t, net.Alice, carol) - ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) - chanPoint3 := openChannelAndAssert( - ctxt, t, net, net.Alice, carol, - lntest.OpenChannelParams{ - Amt: chanAmt, - PushAmt: pushAmt, - }, - ) - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint3) - if err != nil { - t.Fatalf("alice didn't report channel: %v", err) - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = carol.WaitForNetworkChannelOpen(ctxt, chanPoint3) - if err != nil { - t.Fatalf("bob didn't report channel: %v", err) - } - - // Make a global update, and check that both channels' new policies get - // propagated. - baseFee = int64(800) - feeRate = int64(123) - timeLockDelta = uint32(22) - maxHtlc *= 2 - - expectedPolicy.FeeBaseMsat = baseFee - expectedPolicy.FeeRateMilliMsat = testFeeBase * feeRate - expectedPolicy.TimeLockDelta = timeLockDelta - expectedPolicy.MaxHtlcMsat = maxHtlc - - req = &lnrpc.PolicyUpdateRequest{ - BaseFeeMsat: baseFee, - FeeRate: float64(feeRate), - TimeLockDelta: timeLockDelta, - MaxHtlcMsat: maxHtlc, - } - req.Scope = &lnrpc.PolicyUpdateRequest_Global{} - - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - _, err = net.Alice.UpdateChannelPolicy(ctxt, req) - if err != nil { - t.Fatalf("unable to update alice's channel policy: %v", err) - } - - // Wait for all nodes to have seen the policy updates for both of - // Alice's channels. - for _, graphSub := range graphSubs { - waitForChannelUpdate( - t, graphSub, - []expectedChanUpdate{ - {net.Alice.PubKeyStr, expectedPolicy, chanPoint}, - {net.Alice.PubKeyStr, expectedPolicy, chanPoint3}, - }, - ) - } - - // And finally check that all nodes remembers the policy update they - // received. - for _, node := range nodes { - assertChannelPolicy( - t, node, net.Alice.PubKeyStr, expectedPolicy, - chanPoint, chanPoint3, - ) - } - - // Now, to test that Carol is properly rate limiting incoming updates, - // we'll send two more update from Alice. Carol should accept the first, - // but not the second, as she only allows two updates per day and a day - // has yet to elapse from the previous update. - const numUpdatesTilRateLimit = 2 - for i := 0; i < numUpdatesTilRateLimit; i++ { - prevAlicePolicy := *expectedPolicy - baseFee *= 2 - expectedPolicy.FeeBaseMsat = baseFee - req.BaseFeeMsat = baseFee - - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - _, err = net.Alice.UpdateChannelPolicy(ctxt, req) - if err != nil { - t.Fatalf("unable to update alice's channel policy: %v", err) - } - - // Wait for all nodes to have seen the policy updates for both - // of Alice's channels. Carol will not see the last update as - // the limit has been reached. - for idx, graphSub := range graphSubs { - expUpdates := []expectedChanUpdate{ - {net.Alice.PubKeyStr, expectedPolicy, chanPoint}, - {net.Alice.PubKeyStr, expectedPolicy, chanPoint3}, - } - // Carol was added last, which is why we check the last - // index. - if i == numUpdatesTilRateLimit-1 && idx == len(graphSubs)-1 { - expUpdates = nil - } - waitForChannelUpdate(t, graphSub, expUpdates) - } - - // And finally check that all nodes remembers the policy update - // they received. Since Carol didn't receive the last update, - // she still has Alice's old policy. - for idx, node := range nodes { - policy := expectedPolicy - // Carol was added last, which is why we check the last - // index. - if i == numUpdatesTilRateLimit-1 && idx == len(nodes)-1 { - policy = &prevAlicePolicy - } - assertChannelPolicy( - t, node, net.Alice.PubKeyStr, policy, chanPoint, - chanPoint3, - ) - } - } - - // Close the channels. - ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) - closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) - ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) - closeChannelAndAssert(ctxt, t, net, net.Bob, chanPoint2, false) - ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) - closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint3, false) -} - // waitForNodeBlockHeight queries the node for its current block height until // it reaches the passed height. func waitForNodeBlockHeight(ctx context.Context, node *lntest.HarnessNode, @@ -2712,51 +2206,6 @@ func testUpdateChanStatus(net *lntest.NetworkHarness, t *harnessTest) { assertEdgeDisabled(alice, chanPoint, false) } -// updateChannelPolicy updates the channel policy of node to the -// given fees and timelock delta. This function blocks until -// listenerNode has received the policy update. -func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode, - chanPoint *lnrpc.ChannelPoint, baseFee int64, feeRate int64, - timeLockDelta uint32, maxHtlc uint64, listenerNode *lntest.HarnessNode) { - - ctxb := context.Background() - - expectedPolicy := &lnrpc.RoutingPolicy{ - FeeBaseMsat: baseFee, - FeeRateMilliMsat: feeRate, - TimeLockDelta: timeLockDelta, - MinHtlc: 1000, // default value - MaxHtlcMsat: maxHtlc, - } - - updateFeeReq := &lnrpc.PolicyUpdateRequest{ - BaseFeeMsat: baseFee, - FeeRate: float64(feeRate) / testFeeBase, - TimeLockDelta: timeLockDelta, - Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ - ChanPoint: chanPoint, - }, - MaxHtlcMsat: maxHtlc, - } - - ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) - if _, err := node.UpdateChannelPolicy(ctxt, updateFeeReq); err != nil { - t.Fatalf("unable to update chan policy: %v", err) - } - - // Wait for listener node to receive the channel update from node. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - graphSub := subscribeGraphNotifications(ctxt, t, listenerNode) - defer close(graphSub.quit) - - waitForChannelUpdate( - t, graphSub, - []expectedChanUpdate{ - {node.PubKeyStr, expectedPolicy, chanPoint}, - }, - ) -} - // testUnannouncedChannels checks unannounced channels are not returned by // describeGraph RPC request unless explicitly asked for. func testUnannouncedChannels(net *lntest.NetworkHarness, t *harnessTest) {