Skip to content

Commit b41a079

Browse files
committed
multi: use relaxed feature bit Set method for peer features
The spec says: `The origin node MUST NOT set both the optional and mandatory bits`. and so this is why we have the SafeSet method which prevents us from accidentally setting both optional and required bits for any of our own feature bits. But the spec then also says `if both the optional and the mandatory feature bits in a pair are set, the feature should be treated as mandatory.` which means that when we read the feature vectors of our peers or from a payment request, we should be a bit less strict and not error out. We should just set both bits which will result in "IsRequired" returning true. Update the `TestExtractIntentFromSendRequest` test to show the new behaviour.
1 parent 9ee3beb commit b41a079

File tree

4 files changed

+18
-32
lines changed

4 files changed

+18
-32
lines changed

lnrpc/routerrpc/router_backend.go

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

362362
// Parse destination feature bits.
363-
destinationFeatures, err = UnmarshalFeatures(in.DestFeatures)
364-
if err != nil {
365-
return nil, err
366-
}
363+
destinationFeatures = UnmarshalFeatures(in.DestFeatures)
367364
}
368365

369366
// We need to subtract the final delta before passing it into path
@@ -495,10 +492,7 @@ func unmarshalBlindedPayment(rpcPayment *lnrpc.BlindedPaymentPath) (
495492
return nil, err
496493
}
497494

498-
features, err := UnmarshalFeatures(rpcPayment.Features)
499-
if err != nil {
500-
return nil, err
501-
}
495+
features := UnmarshalFeatures(rpcPayment.Features)
502496

503497
return &routing.BlindedPayment{
504498
BlindedPath: path,
@@ -1124,10 +1118,7 @@ func (r *RouterBackend) extractIntentFromSendRequest(
11241118
payIntent.Amount = reqAmt
11251119

11261120
// Parse destination feature bits.
1127-
features, err := UnmarshalFeatures(rpcPayReq.DestFeatures)
1128-
if err != nil {
1129-
return nil, err
1130-
}
1121+
features := UnmarshalFeatures(rpcPayReq.DestFeatures)
11311122

11321123
// Validate the features if any was specified.
11331124
if features != nil {
@@ -1149,10 +1140,7 @@ func (r *RouterBackend) extractIntentFromSendRequest(
11491140
lnrpc.FeatureBit_AMP_OPT,
11501141
}
11511142

1152-
features, err = UnmarshalFeatures(ampFeatures)
1153-
if err != nil {
1154-
return nil, err
1155-
}
1143+
features = UnmarshalFeatures(ampFeatures)
11561144
}
11571145

11581146
// First make sure the destination supports AMP.
@@ -1348,24 +1336,26 @@ func MarshalFeatures(feats *lnwire.FeatureVector) []lnrpc.FeatureBit {
13481336
// UnmarshalFeatures converts a list of uint32's into a valid feature vector.
13491337
// This method checks that feature bit pairs aren't assigned together, and
13501338
// validates transitive dependencies.
1351-
func UnmarshalFeatures(
1352-
rpcFeatures []lnrpc.FeatureBit) (*lnwire.FeatureVector, error) {
1353-
1339+
func UnmarshalFeatures(rpcFeatures []lnrpc.FeatureBit) *lnwire.FeatureVector {
13541340
// If no destination features are specified we'll return nil to signal
13551341
// that the router should try to use the graph as a fallback.
13561342
if rpcFeatures == nil {
1357-
return nil, nil
1343+
return nil
13581344
}
13591345

13601346
raw := lnwire.NewRawFeatureVector()
13611347
for _, bit := range rpcFeatures {
1362-
err := raw.SafeSet(lnwire.FeatureBit(bit))
1363-
if err != nil {
1364-
return nil, err
1365-
}
1348+
// Even though the spec says that the writer of a feature vector
1349+
// should never set both the required and optional bits of a
1350+
// feature, it also says that if we receive a vector with both
1351+
// bits set, then we should just treat the feature as required.
1352+
// Therefore, we don't use SafeSet here when parsing a peer's
1353+
// feature bits and just set the feature no matter what so that
1354+
// if both are set then IsRequired returns true.
1355+
raw.Set(lnwire.FeatureBit(bit))
13661356
}
13671357

1368-
return lnwire.NewFeatureVector(raw, lnwire.Features), nil
1358+
return lnwire.NewFeatureVector(raw, lnwire.Features)
13691359
}
13701360

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

lnrpc/routerrpc/router_backend_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -828,8 +828,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) {
828828
lnrpc.FeatureBit_GOSSIP_QUERIES_REQ,
829829
},
830830
},
831-
valid: false,
832-
expectedErrorMsg: "feature pair exists",
831+
valid: true,
833832
},
834833
{
835834
name: "Valid send req parameters, payment settled",

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
@@ -5782,12 +5782,9 @@ func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPayme
57825782
}
57835783

57845784
// Unmarshal any custom destination features.
5785-
payIntent.destFeatures, err = routerrpc.UnmarshalFeatures(
5785+
payIntent.destFeatures = routerrpc.UnmarshalFeatures(
57865786
rpcPayReq.DestFeatures,
57875787
)
5788-
if err != nil {
5789-
return payIntent, err
5790-
}
57915788

57925789
return payIntent, nil
57935790
}

0 commit comments

Comments
 (0)