From cc030c60e9b634cc918595b76324d4e0088086a7 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Thu, 10 Aug 2023 18:05:02 +0000 Subject: [PATCH] lnutil: make LnFeatures.supports() faster LnFeatures.supports() is became part of the hot path of LNPathFinder.find_path_for_payment() in 6b43eac6fdba2d42a36291185c3c0337e98e0b43, which made find_path_for_payment considerably slower than before. It used to take around 0.8 sec originally, then after linked commit went to ~9 sec, and now this takes it down to ~1.1 sec (on my laptop). --- electrum/lnrouter.py | 2 +- electrum/lnutil.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/electrum/lnrouter.py b/electrum/lnrouter.py index c89ba7f33..9fd6d329b 100644 --- a/electrum/lnrouter.py +++ b/electrum/lnrouter.py @@ -493,7 +493,7 @@ class LNPathFinder(Logger): # it's ok if we are missing the node_announcement (node_info) for this node, # but if we have it, we enforce that they support var_onion_optin node_features = LnFeatures(node_info.features) - if not node_features.supports(LnFeatures.VAR_ONION_OPT): + if not node_features.supports(LnFeatures.VAR_ONION_OPT): # note: this is kind of slow. could be cached. return float('inf'), 0 route_edge = RouteEdge.from_channel_policy( channel_policy=channel_policy, diff --git a/electrum/lnutil.py b/electrum/lnutil.py index 821b94537..e5fe62009 100644 --- a/electrum/lnutil.py +++ b/electrum/lnutil.py @@ -1250,13 +1250,13 @@ class LnFeatures(IntFlag): you can do: myfeatures.supports(LnFeatures.VAR_ONION_OPT) """ - enabled_bits = list_enabled_bits(feature) - if len(enabled_bits) != 1: + if (1 << (feature.bit_length() - 1)) != feature: raise ValueError(f"'feature' cannot be a combination of features: {feature}") - flag = enabled_bits[0] - our_flags = set(list_enabled_bits(self)) - return (flag in our_flags - or get_ln_flag_pair_of_bit(flag) in our_flags) + if feature.bit_length() % 2 == 0: # feature is OPT + feature_other = feature >> 1 + else: # feature is REQ + feature_other = feature << 1 + return (self & feature != 0) or (self & feature_other != 0) def get_names(self) -> Sequence[str]: r = []