select peers with desired features before connecting
This commit is contained in:
@@ -23,7 +23,7 @@ from . import bitcoin
|
|||||||
from . import ecc
|
from . import ecc
|
||||||
from .ecc import sig_string_from_r_and_s, get_r_and_s_from_sig_string, der_sig_from_sig_string
|
from .ecc import sig_string_from_r_and_s, get_r_and_s_from_sig_string, der_sig_from_sig_string
|
||||||
from . import constants
|
from . import constants
|
||||||
from .util import bh2u, bfh, log_exceptions, list_enabled_bits, ignore_exceptions, chunks, SilentTaskGroup
|
from .util import bh2u, bfh, log_exceptions, ignore_exceptions, chunks, SilentTaskGroup
|
||||||
from .transaction import Transaction, TxOutput, PartialTxOutput
|
from .transaction import Transaction, TxOutput, PartialTxOutput
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
from .lnonion import (new_onion_packet, decode_onion_error, OnionFailureCode, calc_hops_data_for_payment,
|
from .lnonion import (new_onion_packet, decode_onion_error, OnionFailureCode, calc_hops_data_for_payment,
|
||||||
@@ -36,7 +36,7 @@ from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc,
|
|||||||
funding_output_script, get_per_commitment_secret_from_seed,
|
funding_output_script, get_per_commitment_secret_from_seed,
|
||||||
secret_to_pubkey, PaymentFailure, LnLocalFeatures,
|
secret_to_pubkey, PaymentFailure, LnLocalFeatures,
|
||||||
LOCAL, REMOTE, HTLCOwner, generate_keypair, LnKeyFamily,
|
LOCAL, REMOTE, HTLCOwner, generate_keypair, LnKeyFamily,
|
||||||
get_ln_flag_pair_of_bit, privkey_to_pubkey, UnknownPaymentHash, MIN_FINAL_CLTV_EXPIRY_ACCEPTED,
|
ln_compare_features, privkey_to_pubkey, UnknownPaymentHash, MIN_FINAL_CLTV_EXPIRY_ACCEPTED,
|
||||||
LightningPeerConnectionClosed, HandshakeFailed, NotFoundChanAnnouncementForUpdate,
|
LightningPeerConnectionClosed, HandshakeFailed, NotFoundChanAnnouncementForUpdate,
|
||||||
MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED, MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED,
|
MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED, MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED,
|
||||||
MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED, RemoteMisbehaving, DEFAULT_TO_SELF_DELAY,
|
MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED, RemoteMisbehaving, DEFAULT_TO_SELF_DELAY,
|
||||||
@@ -187,21 +187,10 @@ class Peer(Logger):
|
|||||||
# if they required some even flag we don't have, they will close themselves
|
# if they required some even flag we don't have, they will close themselves
|
||||||
# but if we require an even flag they don't have, we close
|
# but if we require an even flag they don't have, we close
|
||||||
their_localfeatures = int.from_bytes(payload['localfeatures'], byteorder="big")
|
their_localfeatures = int.from_bytes(payload['localfeatures'], byteorder="big")
|
||||||
our_flags = set(list_enabled_bits(self.localfeatures))
|
try:
|
||||||
their_flags = set(list_enabled_bits(their_localfeatures))
|
self.localfeatures = ln_compare_features(self.localfeatures, their_localfeatures)
|
||||||
for flag in our_flags:
|
except ValueError as e:
|
||||||
if flag not in their_flags and get_ln_flag_pair_of_bit(flag) not in their_flags:
|
raise GracefulDisconnect(f"remote does not support {str(e)}")
|
||||||
# they don't have this feature we wanted :(
|
|
||||||
if flag % 2 == 0: # even flags are compulsory
|
|
||||||
raise GracefulDisconnect("remote does not support {}"
|
|
||||||
.format(str(LnLocalFeatures(1 << flag))))
|
|
||||||
self.localfeatures ^= 1 << flag # disable flag
|
|
||||||
else:
|
|
||||||
# They too have this flag.
|
|
||||||
# For easier feature-bit-testing, if this is an even flag, we also
|
|
||||||
# set the corresponding odd flag now.
|
|
||||||
if flag % 2 == 0 and self.localfeatures & (1 << flag):
|
|
||||||
self.localfeatures |= 1 << get_ln_flag_pair_of_bit(flag)
|
|
||||||
if isinstance(self.transport, LNTransport):
|
if isinstance(self.transport, LNTransport):
|
||||||
self.channel_db.add_recent_peer(self.transport.peer_addr)
|
self.channel_db.add_recent_peer(self.transport.peer_addr)
|
||||||
self._received_init = True
|
self._received_init = True
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import attr
|
|||||||
from aiorpcx import NetAddress
|
from aiorpcx import NetAddress
|
||||||
|
|
||||||
from .util import bfh, bh2u, inv_dict, UserFacingException
|
from .util import bfh, bh2u, inv_dict, UserFacingException
|
||||||
|
from .util import list_enabled_bits
|
||||||
from .crypto import sha256
|
from .crypto import sha256
|
||||||
from .transaction import (Transaction, PartialTransaction, PartialTxInput, TxOutpoint,
|
from .transaction import (Transaction, PartialTransaction, PartialTxInput, TxOutpoint,
|
||||||
PartialTxOutput, opcodes, TxOutput)
|
PartialTxOutput, opcodes, TxOutput)
|
||||||
@@ -655,6 +656,24 @@ class LnGlobalFeatures(IntFlag):
|
|||||||
# note that these are powers of two, not the bits themselves
|
# note that these are powers of two, not the bits themselves
|
||||||
LN_GLOBAL_FEATURES_KNOWN_SET = set(LnGlobalFeatures)
|
LN_GLOBAL_FEATURES_KNOWN_SET = set(LnGlobalFeatures)
|
||||||
|
|
||||||
|
def ln_compare_features(our_features, their_features):
|
||||||
|
"""raises ValueError if incompatible"""
|
||||||
|
our_flags = set(list_enabled_bits(our_features))
|
||||||
|
their_flags = set(list_enabled_bits(their_features))
|
||||||
|
for flag in our_flags:
|
||||||
|
if flag not in their_flags and get_ln_flag_pair_of_bit(flag) not in their_flags:
|
||||||
|
# they don't have this feature we wanted :(
|
||||||
|
if flag % 2 == 0: # even flags are compulsory
|
||||||
|
raise ValueError(LnLocalFeatures(1 << flag))
|
||||||
|
our_features ^= 1 << flag # disable flag
|
||||||
|
else:
|
||||||
|
# They too have this flag.
|
||||||
|
# For easier feature-bit-testing, if this is an even flag, we also
|
||||||
|
# set the corresponding odd flag now.
|
||||||
|
if flag % 2 == 0 and our_features & (1 << flag):
|
||||||
|
our_features |= 1 << get_ln_flag_pair_of_bit(flag)
|
||||||
|
return our_features
|
||||||
|
|
||||||
|
|
||||||
class LNPeerAddr:
|
class LNPeerAddr:
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ from .lnutil import (Outpoint, LNPeerAddr,
|
|||||||
NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner,
|
NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner,
|
||||||
UpdateAddHtlc, Direction, LnLocalFeatures,
|
UpdateAddHtlc, Direction, LnLocalFeatures,
|
||||||
ShortChannelID, PaymentAttemptLog, PaymentAttemptFailureDetails)
|
ShortChannelID, PaymentAttemptLog, PaymentAttemptFailureDetails)
|
||||||
from .lnutil import ln_dummy_address
|
from .lnutil import ln_dummy_address, ln_compare_features
|
||||||
from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput
|
from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput
|
||||||
from .lnonion import OnionFailureCode
|
from .lnonion import OnionFailureCode
|
||||||
from .lnmsg import decode_msg
|
from .lnmsg import decode_msg
|
||||||
@@ -200,6 +200,18 @@ class LNWorker(Logger):
|
|||||||
self._add_peer(host, int(port), bfh(pubkey)),
|
self._add_peer(host, int(port), bfh(pubkey)),
|
||||||
self.network.asyncio_loop)
|
self.network.asyncio_loop)
|
||||||
|
|
||||||
|
def is_good_peer(self, peer):
|
||||||
|
node_id = peer.pubkey
|
||||||
|
node = self.channel_db._nodes.get(node_id)
|
||||||
|
if not node:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
ln_compare_features(self.localfeatures, node.features)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
#self.logger.info(f'is_good {peer.host}')
|
||||||
|
return True
|
||||||
|
|
||||||
async def _get_next_peers_to_try(self) -> Sequence[LNPeerAddr]:
|
async def _get_next_peers_to_try(self) -> Sequence[LNPeerAddr]:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
await self.channel_db.data_loaded.wait()
|
await self.channel_db.data_loaded.wait()
|
||||||
@@ -215,6 +227,8 @@ class LNWorker(Logger):
|
|||||||
continue
|
continue
|
||||||
if peer in self._last_tried_peer:
|
if peer in self._last_tried_peer:
|
||||||
continue
|
continue
|
||||||
|
if not self.is_good_peer(peer):
|
||||||
|
continue
|
||||||
return [peer]
|
return [peer]
|
||||||
# try random peer from graph
|
# try random peer from graph
|
||||||
unconnected_nodes = self.channel_db.get_200_randomly_sorted_nodes_not_in(self.peers.keys())
|
unconnected_nodes = self.channel_db.get_200_randomly_sorted_nodes_not_in(self.peers.keys())
|
||||||
@@ -230,6 +244,8 @@ class LNWorker(Logger):
|
|||||||
continue
|
continue
|
||||||
if peer in self._last_tried_peer:
|
if peer in self._last_tried_peer:
|
||||||
continue
|
continue
|
||||||
|
if not self.is_good_peer(peer):
|
||||||
|
continue
|
||||||
#self.logger.info('taking random ln peer from our channel db')
|
#self.logger.info('taking random ln peer from our channel db')
|
||||||
return [peer]
|
return [peer]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user