rpcserver+lnrpc: allow users to update max HTLC channel policies

In this commit, we enable callers of UpdateChannelPolicy to
specify their desired max HTLC forwarding policy for one or
multiple channels.
This commit is contained in:
Valentine Wallace 2019-08-19 17:55:30 -07:00 committed by Joost Jager
parent 9a52cb6dab
commit 4b9da07e78
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
5 changed files with 571 additions and 522 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2395,6 +2395,9 @@ message PolicyUpdateRequest {
/// The required timelock delta for HTLCs forwarded over the channel. /// The required timelock delta for HTLCs forwarded over the channel.
uint32 time_lock_delta = 5 [json_name = "time_lock_delta"]; uint32 time_lock_delta = 5 [json_name = "time_lock_delta"];
/// If set, the maximum HTLC size in milli-satoshis. If unset, the maximum HTLC will be unchanged.
uint64 max_htlc_msat = 6 [json_name = "max_htlc_msat"];
} }
message PolicyUpdateResponse { message PolicyUpdateResponse {
} }

View File

@ -3150,6 +3150,11 @@
"type": "integer", "type": "integer",
"format": "int64", "format": "int64",
"description": "/ The required timelock delta for HTLCs forwarded over the channel." "description": "/ The required timelock delta for HTLCs forwarded over the channel."
},
"max_htlc_msat": {
"type": "string",
"format": "uint64",
"description": "/ If set, the maximum HTLC size in milli-satoshis. If unset, the maximum HTLC will be unchanged."
} }
} }
}, },

View File

@ -1122,6 +1122,15 @@ type expectedChanUpdate struct {
chanPoint *lnrpc.ChannelPoint chanPoint *lnrpc.ChannelPoint
} }
// calculateMaxHtlc re-implements the RequiredRemoteChannelReserve of the
// funding manager's config, which corresponds to the maximum MaxHTLC value we
// allow users to set when updating a channel policy.
func calculateMaxHtlc(chanCap btcutil.Amount) uint64 {
reserve := lnwire.NewMSatFromSatoshis(chanCap / 100)
max := lnwire.NewMSatFromSatoshis(chanCap) - reserve
return uint64(max)
}
// waitForChannelUpdate waits for a node to receive the expected channel // waitForChannelUpdate waits for a node to receive the expected channel
// updates. // updates.
func waitForChannelUpdate(t *harnessTest, subscription graphSubscription, func waitForChannelUpdate(t *harnessTest, subscription graphSubscription,
@ -1292,6 +1301,10 @@ func checkChannelPolicy(policy, expectedPolicy *lnrpc.RoutingPolicy) error {
return fmt.Errorf("expected min htlc %v, got %v", return fmt.Errorf("expected min htlc %v, got %v",
expectedPolicy.MinHtlc, policy.MinHtlc) expectedPolicy.MinHtlc, policy.MinHtlc)
} }
if policy.MaxHtlcMsat != expectedPolicy.MaxHtlcMsat {
return fmt.Errorf("expected max htlc %v, got %v",
expectedPolicy.MaxHtlcMsat, policy.MaxHtlcMsat)
}
if policy.Disabled != expectedPolicy.Disabled { if policy.Disabled != expectedPolicy.Disabled {
return errors.New("edge should be disabled but isn't") return errors.New("edge should be disabled but isn't")
} }
@ -1310,6 +1323,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
defaultTimeLockDelta = lnd.DefaultBitcoinTimeLockDelta defaultTimeLockDelta = lnd.DefaultBitcoinTimeLockDelta
defaultMinHtlc = 1000 defaultMinHtlc = 1000
) )
defaultMaxHtlc := calculateMaxHtlc(lnd.MaxBtcFundingAmount)
// Launch notification clients for all nodes, such that we can // Launch notification clients for all nodes, such that we can
// get notified when they discover new channels and updates in the // get notified when they discover new channels and updates in the
@ -1344,6 +1358,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
FeeRateMilliMsat: defaultFeeRate, FeeRateMilliMsat: defaultFeeRate,
TimeLockDelta: defaultTimeLockDelta, TimeLockDelta: defaultTimeLockDelta,
MinHtlc: defaultMinHtlc, MinHtlc: defaultMinHtlc,
MaxHtlcMsat: defaultMaxHtlc,
} }
for _, graphSub := range graphSubs { for _, graphSub := range graphSubs {
@ -1422,6 +1437,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
FeeRateMilliMsat: defaultFeeRate, FeeRateMilliMsat: defaultFeeRate,
TimeLockDelta: defaultTimeLockDelta, TimeLockDelta: defaultTimeLockDelta,
MinHtlc: customMinHtlc, MinHtlc: customMinHtlc,
MaxHtlcMsat: defaultMaxHtlc,
} }
expectedPolicyCarol := &lnrpc.RoutingPolicy{ expectedPolicyCarol := &lnrpc.RoutingPolicy{
@ -1429,6 +1445,7 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
FeeRateMilliMsat: defaultFeeRate, FeeRateMilliMsat: defaultFeeRate,
TimeLockDelta: defaultTimeLockDelta, TimeLockDelta: defaultTimeLockDelta,
MinHtlc: defaultMinHtlc, MinHtlc: defaultMinHtlc,
MaxHtlcMsat: defaultMaxHtlc,
} }
for _, graphSub := range graphSubs { for _, graphSub := range graphSubs {
@ -1589,24 +1606,27 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
sendResp.PaymentError) sendResp.PaymentError)
} }
// With our little cluster set up, we'll update the fees for the // With our little cluster set up, we'll update the fees and the max htlc
// channel Bob side of the Alice->Bob channel, and make sure all nodes // size for the Bob side of the Alice->Bob channel, and make sure
// learn about it. // all nodes learn about it.
baseFee := int64(1500) baseFee := int64(1500)
feeRate := int64(12) feeRate := int64(12)
timeLockDelta := uint32(66) timeLockDelta := uint32(66)
maxHtlc := uint64(500000)
expectedPolicy = &lnrpc.RoutingPolicy{ expectedPolicy = &lnrpc.RoutingPolicy{
FeeBaseMsat: baseFee, FeeBaseMsat: baseFee,
FeeRateMilliMsat: testFeeBase * feeRate, FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: defaultMinHtlc, MinHtlc: defaultMinHtlc,
MaxHtlcMsat: maxHtlc,
} }
req := &lnrpc.PolicyUpdateRequest{ req := &lnrpc.PolicyUpdateRequest{
BaseFeeMsat: baseFee, BaseFeeMsat: baseFee,
FeeRate: float64(feeRate), FeeRate: float64(feeRate),
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MaxHtlcMsat: maxHtlc,
Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{
ChanPoint: chanPoint, ChanPoint: chanPoint,
}, },
@ -1689,22 +1709,25 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
baseFee = int64(800) baseFee = int64(800)
feeRate = int64(123) feeRate = int64(123)
timeLockDelta = uint32(22) timeLockDelta = uint32(22)
maxHtlc = maxHtlc * 2
expectedPolicy.FeeBaseMsat = baseFee expectedPolicy.FeeBaseMsat = baseFee
expectedPolicy.FeeRateMilliMsat = testFeeBase * feeRate expectedPolicy.FeeRateMilliMsat = testFeeBase * feeRate
expectedPolicy.TimeLockDelta = timeLockDelta expectedPolicy.TimeLockDelta = timeLockDelta
expectedPolicy.MaxHtlcMsat = maxHtlc
req = &lnrpc.PolicyUpdateRequest{ req = &lnrpc.PolicyUpdateRequest{
BaseFeeMsat: baseFee, BaseFeeMsat: baseFee,
FeeRate: float64(feeRate), FeeRate: float64(feeRate),
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MaxHtlcMsat: maxHtlc,
} }
req.Scope = &lnrpc.PolicyUpdateRequest_Global{} req.Scope = &lnrpc.PolicyUpdateRequest_Global{}
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
_, err = net.Alice.UpdateChannelPolicy(ctxt, req) _, err = net.Alice.UpdateChannelPolicy(ctxt, req)
if err != nil { if err != nil {
t.Fatalf("unable to get alice's balance: %v", err) t.Fatalf("unable to update alice's channel policy: %v", err)
} }
// Wait for all nodes to have seen the policy updates for both of // Wait for all nodes to have seen the policy updates for both of
@ -3950,7 +3973,8 @@ func assertAmountPaid(t *harnessTest, channelName string,
// listenerNode has received the policy update. // listenerNode has received the policy update.
func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode, func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode,
chanPoint *lnrpc.ChannelPoint, baseFee int64, feeRate int64, chanPoint *lnrpc.ChannelPoint, baseFee int64, feeRate int64,
timeLockDelta uint32, listenerNode *lntest.HarnessNode) { timeLockDelta uint32, maxHtlc uint64, listenerNode *lntest.HarnessNode) {
ctxb := context.Background() ctxb := context.Background()
expectedPolicy := &lnrpc.RoutingPolicy{ expectedPolicy := &lnrpc.RoutingPolicy{
@ -3958,6 +3982,7 @@ func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode,
FeeRateMilliMsat: feeRate, FeeRateMilliMsat: feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: 1000, // default value MinHtlc: 1000, // default value
MaxHtlcMsat: maxHtlc,
} }
updateFeeReq := &lnrpc.PolicyUpdateRequest{ updateFeeReq := &lnrpc.PolicyUpdateRequest{
@ -3967,6 +3992,7 @@ func updateChannelPolicy(t *harnessTest, node *lntest.HarnessNode,
Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{
ChanPoint: chanPoint, ChanPoint: chanPoint,
}, },
MaxHtlcMsat: maxHtlc,
} }
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
@ -4143,14 +4169,15 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
// Set the fee policies of the Alice -> Bob and the Dave -> Alice // Set the fee policies of the Alice -> Bob and the Dave -> Alice
// channel edges to relatively large non default values. This makes it // channel edges to relatively large non default values. This makes it
// possible to pick up more subtle fee calculation errors. // possible to pick up more subtle fee calculation errors.
maxHtlc := uint64(calculateMaxHtlc(chanAmt))
updateChannelPolicy( updateChannelPolicy(
t, net.Alice, chanPointAlice, 1000, 100000, t, net.Alice, chanPointAlice, 1000, 100000,
lnd.DefaultBitcoinTimeLockDelta, carol, lnd.DefaultBitcoinTimeLockDelta, maxHtlc, carol,
) )
updateChannelPolicy( updateChannelPolicy(
t, dave, chanPointDave, 5000, 150000, t, dave, chanPointDave, 5000, 150000,
lnd.DefaultBitcoinTimeLockDelta, carol, lnd.DefaultBitcoinTimeLockDelta, maxHtlc, carol,
) )
// Using Carol as the source, pay to the 5 invoices from Bob created // Using Carol as the source, pay to the 5 invoices from Bob created
@ -12372,18 +12399,21 @@ func testRouteFeeCutoff(net *lntest.NetworkHarness, t *harnessTest) {
baseFee := int64(10000) baseFee := int64(10000)
feeRate := int64(5) feeRate := int64(5)
timeLockDelta := uint32(lnd.DefaultBitcoinTimeLockDelta) timeLockDelta := uint32(lnd.DefaultBitcoinTimeLockDelta)
maxHtlc := calculateMaxHtlc(chanAmt)
expectedPolicy := &lnrpc.RoutingPolicy{ expectedPolicy := &lnrpc.RoutingPolicy{
FeeBaseMsat: baseFee, FeeBaseMsat: baseFee,
FeeRateMilliMsat: testFeeBase * feeRate, FeeRateMilliMsat: testFeeBase * feeRate,
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MinHtlc: 1000, // default value MinHtlc: 1000, // default value
MaxHtlcMsat: maxHtlc,
} }
updateFeeReq := &lnrpc.PolicyUpdateRequest{ updateFeeReq := &lnrpc.PolicyUpdateRequest{
BaseFeeMsat: baseFee, BaseFeeMsat: baseFee,
FeeRate: float64(feeRate), FeeRate: float64(feeRate),
TimeLockDelta: timeLockDelta, TimeLockDelta: timeLockDelta,
MaxHtlcMsat: maxHtlc,
Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{
ChanPoint: chanPointCarolDave, ChanPoint: chanPointCarolDave,
}, },
@ -12634,6 +12664,7 @@ func testSendUpdateDisableChannel(net *lntest.NetworkHarness, t *harnessTest) {
FeeRateMilliMsat: int64(lnd.DefaultBitcoinFeeRate), FeeRateMilliMsat: int64(lnd.DefaultBitcoinFeeRate),
TimeLockDelta: lnd.DefaultBitcoinTimeLockDelta, TimeLockDelta: lnd.DefaultBitcoinTimeLockDelta,
MinHtlc: 1000, // default value MinHtlc: 1000, // default value
MaxHtlcMsat: calculateMaxHtlc(chanAmt),
Disabled: true, Disabled: true,
} }

View File

@ -4602,6 +4602,7 @@ func (r *rpcServer) UpdateChannelPolicy(ctx context.Context,
chanPolicy := routing.ChannelPolicy{ chanPolicy := routing.ChannelPolicy{
FeeSchema: feeSchema, FeeSchema: feeSchema,
TimeLockDelta: req.TimeLockDelta, TimeLockDelta: req.TimeLockDelta,
MaxHTLC: lnwire.MilliSatoshi(req.MaxHtlcMsat),
} }
rpcsLog.Debugf("[updatechanpolicy] updating channel policy base_fee=%v, "+ rpcsLog.Debugf("[updatechanpolicy] updating channel policy base_fee=%v, "+