From 624dc6c26afb9851960537c24081aeabfcd83e4f Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 3 Mar 2025 18:19:52 +0800 Subject: [PATCH 1/4] lntest: assert `CustomRecords` fields on channel policy Make sure the `CustomRecords` field is asserted. --- lntest/node/watcher.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lntest/node/watcher.go b/lntest/node/watcher.go index b075c08ab..08f1facfe 100644 --- a/lntest/node/watcher.go +++ b/lntest/node/watcher.go @@ -1,6 +1,7 @@ package node import ( + "bytes" "context" "encoding/json" "errors" @@ -725,5 +726,27 @@ func CheckChannelPolicy(policy, expectedPolicy *lnrpc.RoutingPolicy) error { return errors.New("edge should be disabled but isn't") } + // We now validate custom records. + records := policy.CustomRecords + + if len(records) != len(expectedPolicy.CustomRecords) { + return fmt.Errorf("expected %v CustomRecords, got %v, "+ + "records: %v", len(expectedPolicy.CustomRecords), + len(records), records) + } + + expectedRecords := expectedPolicy.CustomRecords + for k, record := range records { + expected, found := expectedRecords[k] + if !found { + return fmt.Errorf("CustomRecords %v not found", k) + } + + if !bytes.Equal(record, expected) { + return fmt.Errorf("want CustomRecords(%v) %s, got %s", + k, expected, record) + } + } + return nil } From 650e72518c09b07826f4d1339be5828daa25b993 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 3 Mar 2025 17:07:02 +0800 Subject: [PATCH 2/4] rpcserver: remove duplicate info from `RoutingPolicy` We remove the inbound fee record from `RoutingPolicy.CustomRecords` as we already have fields `InboundFeeBaseMsat` and `InboundFeeRateMilliMsat`. --- rpcserver.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 77fe4bb78..87bda9633 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6842,12 +6842,23 @@ func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo, return edge } +// marshalPolicyExtraOpaqueData marshals the given tlv data and filters out +// inbound fee record. +func marshalPolicyExtraOpaqueData(data []byte) map[uint64][]byte { + records := marshalExtraOpaqueData(data) + + // Remove the inbound fee record as we have dedicated fields for it. + delete(records, uint64(lnwire.FeeRecordType)) + + return records +} + func marshalDBRoutingPolicy( policy *models.ChannelEdgePolicy) *lnrpc.RoutingPolicy { disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0 - customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData) + customRecords := marshalPolicyExtraOpaqueData(policy.ExtraOpaqueData) inboundFee := policy.InboundFee.UnwrapOr(lnwire.Fee{}) return &lnrpc.RoutingPolicy{ @@ -7361,7 +7372,7 @@ func marshallTopologyChange( channelUpdates := make([]*lnrpc.ChannelEdgeUpdate, len(topChange.ChannelEdgeUpdates)) for i, channelUpdate := range topChange.ChannelEdgeUpdates { - customRecords := marshalExtraOpaqueData( + customRecords := marshalPolicyExtraOpaqueData( channelUpdate.ExtraOpaqueData, ) inboundFee := channelUpdate.InboundFee.UnwrapOr(lnwire.Fee{}) @@ -7954,12 +7965,9 @@ func (r *rpcServer) UpdateChannelPolicy(ctx context.Context, MinHTLC: minHtlc, } - rpcsLog.Debugf("[updatechanpolicy] updating channel policy "+ - "base_fee=%v, rate_fixed=%v, time_lock_delta: %v, "+ - "min_htlc=%v, max_htlc=%v, targets=%v", - req.BaseFeeMsat, feeRateFixed, req.TimeLockDelta, - minHtlc, maxHtlc, - spew.Sdump(targetChans)) + rpcsLog.Debugf("[updatechanpolicy] updating channel policy, "+ + "targets=%v, req=%v", lnutils.SpewLogClosure(targetChans), + lnutils.SpewLogClosure(req)) // With the scope resolved, we'll now send this to the local channel // manager so it can propagate the new policy for our target channel(s). From 9ed32bddf3b9cb4cd71debba531e9f7b6dff7cca Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 3 Mar 2025 17:39:00 +0800 Subject: [PATCH 3/4] docs: update release notes for 0.20 --- docs/release-notes/release-notes-0.20.0.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/release-notes/release-notes-0.20.0.md b/docs/release-notes/release-notes-0.20.0.md index d0e163c45..ee36d7c8f 100644 --- a/docs/release-notes/release-notes-0.20.0.md +++ b/docs/release-notes/release-notes-0.20.0.md @@ -94,6 +94,12 @@ circuit. The indices are only available for forwarding events saved after v0.20. * [11](https://github.com/lightningnetwork/lnd/pull/9972) ## RPC Updates +* Previously the `RoutingPolicy` would return the inbound fee record in its + `CustomRecords` field, which is duplicated info as it's already presented in + fields `InboundFeeBaseMsat` and `InboundFeeRateMilliMsat`. This is now + [fixed](https://github.com/lightningnetwork/lnd/pull/9572), the affected RPCs + are `SubscribeChannelGraph`, `GetChanInfo`, `GetNodeInfo` and `DescribeGraph`. + ## lncli Updates From 43ea309f2cee39a6aa3a207c17c2a44f165f5c54 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 1 Jul 2025 15:00:13 +0800 Subject: [PATCH 4/4] lnrpc: update description for `RoutingPolicy.CustomRecords` --- lnrpc/devrpc/dev.swagger.json | 2 +- lnrpc/lightning.pb.go | 3 ++- lnrpc/lightning.proto | 3 ++- lnrpc/lightning.swagger.json | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lnrpc/devrpc/dev.swagger.json b/lnrpc/devrpc/dev.swagger.json index 0861855b1..25338c398 100644 --- a/lnrpc/devrpc/dev.swagger.json +++ b/lnrpc/devrpc/dev.swagger.json @@ -320,7 +320,7 @@ "type": "string", "format": "byte" }, - "description": "Custom channel update tlv records." + "description": "Custom channel update tlv records. These are customized fields that are\nnot defined by LND and cannot be extracted." }, "inbound_fee_base_msat": { "type": "integer", diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go index 859854b3e..5aaa3ac05 100644 --- a/lnrpc/lightning.pb.go +++ b/lnrpc/lightning.pb.go @@ -10993,7 +10993,8 @@ type RoutingPolicy struct { Disabled bool `protobuf:"varint,5,opt,name=disabled,proto3" json:"disabled,omitempty"` MaxHtlcMsat uint64 `protobuf:"varint,6,opt,name=max_htlc_msat,json=maxHtlcMsat,proto3" json:"max_htlc_msat,omitempty"` LastUpdate uint32 `protobuf:"varint,7,opt,name=last_update,json=lastUpdate,proto3" json:"last_update,omitempty"` - // Custom channel update tlv records. + // Custom channel update tlv records. These are customized fields that are + // not defined by LND and cannot be extracted. CustomRecords map[uint64][]byte `protobuf:"bytes,8,rep,name=custom_records,json=customRecords,proto3" json:"custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` InboundFeeBaseMsat int32 `protobuf:"varint,9,opt,name=inbound_fee_base_msat,json=inboundFeeBaseMsat,proto3" json:"inbound_fee_base_msat,omitempty"` InboundFeeRateMilliMsat int32 `protobuf:"varint,10,opt,name=inbound_fee_rate_milli_msat,json=inboundFeeRateMilliMsat,proto3" json:"inbound_fee_rate_milli_msat,omitempty"` diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto index 20f5f5dab..353e314e9 100644 --- a/lnrpc/lightning.proto +++ b/lnrpc/lightning.proto @@ -3471,7 +3471,8 @@ message RoutingPolicy { uint64 max_htlc_msat = 6; uint32 last_update = 7; - // Custom channel update tlv records. + // Custom channel update tlv records. These are customized fields that are + // not defined by LND and cannot be extracted. map custom_records = 8; int32 inbound_fee_base_msat = 9; diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json index 634b32c88..c2f7a6b45 100644 --- a/lnrpc/lightning.swagger.json +++ b/lnrpc/lightning.swagger.json @@ -7350,7 +7350,7 @@ "type": "string", "format": "byte" }, - "description": "Custom channel update tlv records." + "description": "Custom channel update tlv records. These are customized fields that are\nnot defined by LND and cannot be extracted." }, "inbound_fee_base_msat": { "type": "integer",