Skip to content

Commit d1d3a82

Browse files
authored
Merge pull request #9884 from ellemouton/relaxFeatureBitCheck
multi: use relaxed feature bit `Set` method for peer features
2 parents 67880c5 + e68b882 commit d1d3a82

File tree

5 files changed

+41
-30
lines changed

5 files changed

+41
-30
lines changed

docs/release-notes/release-notes-0.20.0.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ reader of a payment request.
223223
record](https://github.com/lightningnetwork/lnd/pull/9897) on the
224224
`channel_update` message and handle it explicitly throughout the code base
225225
instead of extracting it from the TLV stream at various call-sites.
226+
* [Don't error out](https://github.com/lightningnetwork/lnd/pull/9884) if an
227+
invoice's feature vector contain both the required and optional versions of a
228+
feature bit. In those cases, just treat the feature as mandatory.
226229

227230
* [Require invoices to include a payment address or blinded paths](https://github.com/lightningnetwork/lnd/pull/9752)
228231
to comply with updated BOLT 11 specifications before sending payments.

lnrpc/routerrpc/router_backend.go

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,7 @@ func (r *RouterBackend) parseQueryRoutesRequest(in *lnrpc.QueryRoutesRequest) (
365365
}
366366

367367
// Parse destination feature bits.
368-
destinationFeatures, err = UnmarshalFeatures(in.DestFeatures)
369-
if err != nil {
370-
return nil, err
371-
}
368+
destinationFeatures = UnmarshalFeatures(in.DestFeatures)
372369
}
373370

374371
// We need to subtract the final delta before passing it into path
@@ -510,10 +507,7 @@ func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
510507
return nil, err
511508
}
512509

513-
features, err := UnmarshalFeatures(rpcPayment.Features)
514-
if err != nil {
515-
return nil, err
516-
}
510+
features := UnmarshalFeatures(rpcPayment.Features)
517511

518512
return &routing.BlindedPayment{
519513
BlindedPath: path,
@@ -1148,10 +1142,7 @@ func (r *RouterBackend) extractIntentFromSendRequest(
11481142
payIntent.Amount = reqAmt
11491143

11501144
// Parse destination feature bits.
1151-
features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
1152-
if err != nil {
1153-
return nil, err
1154-
}
1145+
features := UnmarshalFeatures(rpcPayReq.DestFeatures)
11551146

11561147
// Validate the features if any was specified.
11571148
if features != nil {
@@ -1173,10 +1164,7 @@ func (r *RouterBackend) extractIntentFromSendRequest(
11731164
lnrpc.FeatureBit_AMP_OPT,
11741165
}
11751166

1176-
features, err = UnmarshalFeatures(ampFeatures)
1177-
if err != nil {
1178-
return nil, err
1179-
}
1167+
features = UnmarshalFeatures(ampFeatures)
11801168
}
11811169

11821170
// First make sure the destination supports AMP.
@@ -1372,24 +1360,26 @@ func MarshalFeatures(feats *lnwire.FeatureVector) []lnrpc.FeatureBit {
13721360
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
13731361
// This method checks that feature bit pairs aren't assigned together, and
13741362
// validates transitive dependencies.
1375-
func UnmarshalFeatures(
1376-
rpcFeatures []lnrpc.FeatureBit) (*lnwire.FeatureVector, error) {
1377-
1363+
func UnmarshalFeatures(rpcFeatures []lnrpc.FeatureBit) *lnwire.FeatureVector {
13781364
// If no destination features are specified we'll return nil to signal
13791365
// that the router should try to use the graph as a fallback.
13801366
if rpcFeatures == nil {
1381-
return nil, nil
1367+
return nil
13821368
}
13831369

13841370
raw := lnwire.NewRawFeatureVector()
13851371
for _, bit := range rpcFeatures {
1386-
err := raw.SafeSet(lnwire.FeatureBit(bit))
1387-
if err != nil {
1388-
return nil, err
1389-
}
1372+
// Even though the spec says that the writer of a feature vector
1373+
// should never set both the required and optional bits of a
1374+
// feature, it also says that if we receive a vector with both
1375+
// bits set, then we should just treat the feature as required.
1376+
// Therefore, we don't use SafeSet here when parsing a peer's
1377+
// feature bits and just set the feature no matter what so that
1378+
// if both are set then IsRequired returns true.
1379+
raw.Set(lnwire.FeatureBit(bit))
13901380
}
13911381

1392-
return lnwire.NewFeatureVector(raw, lnwire.Features), nil
1382+
return lnwire.NewFeatureVector(raw, lnwire.Features)
13931383
}
13941384

13951385
// ValidatePayReqExpiry checks if the passed payment request has expired. In

lnrpc/routerrpc/router_backend_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,27 @@ func TestExtractIntentFromSendRequest(t *testing.T) {
881881
valid: false,
882882
expectedErrorMsg: "self-payments not allowed",
883883
},
884+
{
885+
name: "Required and optional feature bits set",
886+
backend: &RouterBackend{
887+
MaxTotalTimelock: 1000,
888+
ShouldSetExpEndorsement: func() bool {
889+
return false
890+
},
891+
},
892+
sendReq: &SendPaymentRequest{
893+
Dest: destNodeBytes,
894+
Amt: int64(paymentAmount),
895+
PaymentHash: make([]byte, 32),
896+
MaxParts: 10,
897+
MaxShardSizeMsat: 30_000_000,
898+
DestFeatures: []lnrpc.FeatureBit{
899+
lnrpc.FeatureBit_GOSSIP_QUERIES_OPT,
900+
lnrpc.FeatureBit_GOSSIP_QUERIES_REQ,
901+
},
902+
},
903+
valid: true,
904+
},
884905
{
885906
name: "Valid send req parameters, payment settled",
886907
backend: &RouterBackend{

lnwire/features.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func (fv RawFeatureVector) Equals(other *RawFeatureVector) bool {
446446
return true
447447
}
448448

449-
// Merges sets all feature bits in other on the receiver's feature vector.
449+
// Merge sets all feature bits in other on the receiver's feature vector.
450450
func (fv *RawFeatureVector) Merge(other *RawFeatureVector) error {
451451
for bit := range other.features {
452452
err := fv.SafeSet(bit)

rpcserver.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5827,12 +5827,9 @@ func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPayme
58275827
}
58285828

58295829
// Unmarshal any custom destination features.
5830-
payIntent.destFeatures, err = routerrpc.UnmarshalFeatures(
5830+
payIntent.destFeatures = routerrpc.UnmarshalFeatures(
58315831
rpcPayReq.DestFeatures,
58325832
)
5833-
if err != nil {
5834-
return payIntent, err
5835-
}
58365833

58375834
return payIntent, nil
58385835
}

0 commit comments

Comments
 (0)