mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-29 08:21:27 +00:00
ln feature bits: validate transitive feature deps everywhere
This commit is contained in:
parent
94e3c078f8
commit
71635216df
4 changed files with 30 additions and 17 deletions
|
@ -39,7 +39,7 @@ from . import constants
|
||||||
from .util import bh2u, profiler, get_headers_dir, bfh, is_ip_address, list_enabled_bits
|
from .util import bh2u, profiler, get_headers_dir, bfh, is_ip_address, list_enabled_bits
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
from .lnutil import (LNPeerAddr, format_short_channel_id, ShortChannelID,
|
from .lnutil import (LNPeerAddr, format_short_channel_id, ShortChannelID,
|
||||||
UnknownEvenFeatureBits, validate_features)
|
validate_features, IncompatibleOrInsaneFeatures)
|
||||||
from .lnverifier import LNChannelVerifier, verify_sig_for_channel_update
|
from .lnverifier import LNChannelVerifier, verify_sig_for_channel_update
|
||||||
from .lnmsg import decode_msg
|
from .lnmsg import decode_msg
|
||||||
|
|
||||||
|
@ -331,8 +331,8 @@ class ChannelDB(SqlDB):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
channel_info = ChannelInfo.from_msg(msg)
|
channel_info = ChannelInfo.from_msg(msg)
|
||||||
except UnknownEvenFeatureBits:
|
except IncompatibleOrInsaneFeatures as e:
|
||||||
self.logger.info("unknown feature bits")
|
self.logger.info(f"unknown or insane feature bits: {e!r}")
|
||||||
continue
|
continue
|
||||||
if trusted:
|
if trusted:
|
||||||
added += 1
|
added += 1
|
||||||
|
@ -346,7 +346,7 @@ class ChannelDB(SqlDB):
|
||||||
def add_verified_channel_info(self, msg: dict, *, capacity_sat: int = None) -> None:
|
def add_verified_channel_info(self, msg: dict, *, capacity_sat: int = None) -> None:
|
||||||
try:
|
try:
|
||||||
channel_info = ChannelInfo.from_msg(msg)
|
channel_info = ChannelInfo.from_msg(msg)
|
||||||
except UnknownEvenFeatureBits:
|
except IncompatibleOrInsaneFeatures:
|
||||||
return
|
return
|
||||||
channel_info = channel_info._replace(capacity_sat=capacity_sat)
|
channel_info = channel_info._replace(capacity_sat=capacity_sat)
|
||||||
with self.lock:
|
with self.lock:
|
||||||
|
@ -499,7 +499,7 @@ class ChannelDB(SqlDB):
|
||||||
for msg_payload in msg_payloads:
|
for msg_payload in msg_payloads:
|
||||||
try:
|
try:
|
||||||
node_info, node_addresses = NodeInfo.from_msg(msg_payload)
|
node_info, node_addresses = NodeInfo.from_msg(msg_payload)
|
||||||
except UnknownEvenFeatureBits:
|
except IncompatibleOrInsaneFeatures:
|
||||||
continue
|
continue
|
||||||
node_id = node_info.node_id
|
node_id = node_info.node_id
|
||||||
# Ignore node if it has no associated channel (DoS protection)
|
# Ignore node if it has no associated channel (DoS protection)
|
||||||
|
@ -593,11 +593,17 @@ class ChannelDB(SqlDB):
|
||||||
self._recent_peers = sorted_node_ids[:self.NUM_MAX_RECENT_PEERS]
|
self._recent_peers = sorted_node_ids[:self.NUM_MAX_RECENT_PEERS]
|
||||||
c.execute("""SELECT * FROM channel_info""")
|
c.execute("""SELECT * FROM channel_info""")
|
||||||
for short_channel_id, msg in c:
|
for short_channel_id, msg in c:
|
||||||
ci = ChannelInfo.from_raw_msg(msg)
|
try:
|
||||||
|
ci = ChannelInfo.from_raw_msg(msg)
|
||||||
|
except IncompatibleOrInsaneFeatures:
|
||||||
|
continue
|
||||||
self._channels[ShortChannelID.normalize(short_channel_id)] = ci
|
self._channels[ShortChannelID.normalize(short_channel_id)] = ci
|
||||||
c.execute("""SELECT * FROM node_info""")
|
c.execute("""SELECT * FROM node_info""")
|
||||||
for node_id, msg in c:
|
for node_id, msg in c:
|
||||||
node_info, node_addresses = NodeInfo.from_raw_msg(msg)
|
try:
|
||||||
|
node_info, node_addresses = NodeInfo.from_raw_msg(msg)
|
||||||
|
except IncompatibleOrInsaneFeatures:
|
||||||
|
continue
|
||||||
# don't load node_addresses because they dont have timestamps
|
# don't load node_addresses because they dont have timestamps
|
||||||
self._nodes[node_id] = node_info
|
self._nodes[node_id] = node_info
|
||||||
c.execute("""SELECT * FROM policy""")
|
c.execute("""SELECT * FROM policy""")
|
||||||
|
|
|
@ -170,7 +170,7 @@ def pull_tagged(stream):
|
||||||
length = stream.read(5).uint * 32 + stream.read(5).uint
|
length = stream.read(5).uint * 32 + stream.read(5).uint
|
||||||
return (CHARSET[tag], stream.read(length * 5), stream)
|
return (CHARSET[tag], stream.read(length * 5), stream)
|
||||||
|
|
||||||
def lnencode(addr: 'LnAddr', privkey):
|
def lnencode(addr: 'LnAddr', privkey) -> str:
|
||||||
if addr.amount:
|
if addr.amount:
|
||||||
amount = Decimal(str(addr.amount))
|
amount = Decimal(str(addr.amount))
|
||||||
# We can only send down to millisatoshi.
|
# We can only send down to millisatoshi.
|
||||||
|
|
|
@ -165,7 +165,6 @@ class HandshakeFailed(LightningError): pass
|
||||||
class ConnStringFormatError(LightningError): pass
|
class ConnStringFormatError(LightningError): pass
|
||||||
class UnknownPaymentHash(LightningError): pass
|
class UnknownPaymentHash(LightningError): pass
|
||||||
class RemoteMisbehaving(LightningError): pass
|
class RemoteMisbehaving(LightningError): pass
|
||||||
class UnknownEvenFeatureBits(Exception): pass
|
|
||||||
|
|
||||||
class NotFoundChanAnnouncementForUpdate(Exception): pass
|
class NotFoundChanAnnouncementForUpdate(Exception): pass
|
||||||
|
|
||||||
|
@ -855,7 +854,11 @@ def get_ln_flag_pair_of_bit(flag_bit: int) -> int:
|
||||||
return flag_bit - 1
|
return flag_bit - 1
|
||||||
|
|
||||||
|
|
||||||
class IncompatibleLightningFeatures(ValueError): pass
|
|
||||||
|
class IncompatibleOrInsaneFeatures(Exception): pass
|
||||||
|
class UnknownEvenFeatureBits(IncompatibleOrInsaneFeatures): pass
|
||||||
|
class IncompatibleLightningFeatures(IncompatibleOrInsaneFeatures): pass
|
||||||
|
|
||||||
|
|
||||||
def ln_compare_features(our_features: 'LnFeatures', their_features: int) -> 'LnFeatures':
|
def ln_compare_features(our_features: 'LnFeatures', their_features: int) -> 'LnFeatures':
|
||||||
"""Returns negotiated features.
|
"""Returns negotiated features.
|
||||||
|
@ -886,13 +889,17 @@ def ln_compare_features(our_features: 'LnFeatures', their_features: int) -> 'LnF
|
||||||
|
|
||||||
|
|
||||||
def validate_features(features: int) -> None:
|
def validate_features(features: int) -> None:
|
||||||
"""Raises UnknownEvenFeatureBits if there is an unimplemented
|
"""Raises IncompatibleOrInsaneFeatures if
|
||||||
mandatory feature.
|
- a mandatory feature is listed that we don't recognize, or
|
||||||
|
- the features are inconsistent
|
||||||
"""
|
"""
|
||||||
|
features = LnFeatures(features)
|
||||||
enabled_features = list_enabled_bits(features)
|
enabled_features = list_enabled_bits(features)
|
||||||
for fbit in enabled_features:
|
for fbit in enabled_features:
|
||||||
if (1 << fbit) & LN_FEATURES_IMPLEMENTED == 0 and fbit % 2 == 0:
|
if (1 << fbit) & LN_FEATURES_IMPLEMENTED == 0 and fbit % 2 == 0:
|
||||||
raise UnknownEvenFeatureBits(fbit)
|
raise UnknownEvenFeatureBits(fbit)
|
||||||
|
if not features.validate_transitive_dependecies():
|
||||||
|
raise IncompatibleOrInsaneFeatures("not all transitive dependencies are set")
|
||||||
|
|
||||||
|
|
||||||
def derive_payment_secret_from_payment_preimage(payment_preimage: bytes) -> bytes:
|
def derive_payment_secret_from_payment_preimage(payment_preimage: bytes) -> bytes:
|
||||||
|
|
|
@ -78,11 +78,11 @@ class TestBolt11(ElectrumTestCase):
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 514)]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 514)]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 8))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 8))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 11))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 7) + (1 << 11))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 12))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 12))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 13))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 13))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 14))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 14))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 15))]),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 15))]),
|
||||||
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 33282)], payment_secret=b"\x11" * 32),
|
LnAddr(paymenthash=RHASH, amount=24, tags=[('h', longdescription), ('9', 33282)], payment_secret=b"\x11" * 32),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -128,8 +128,8 @@ class TestBolt11(ElectrumTestCase):
|
||||||
lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7")
|
lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7")
|
||||||
|
|
||||||
def test_payment_secret(self):
|
def test_payment_secret(self):
|
||||||
lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sqdkcy8h")
|
lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l")
|
||||||
self.assertEqual((1 << 15) + (1 << 99) , lnaddr.get_tag('9'))
|
self.assertEqual((1 << 9) + (1 << 15) + (1 << 99), lnaddr.get_tag('9'))
|
||||||
self.assertEqual(b"\x11" * 32, lnaddr.payment_secret)
|
self.assertEqual(b"\x11" * 32, lnaddr.payment_secret)
|
||||||
|
|
||||||
def test_derive_payment_secret_from_payment_preimage(self):
|
def test_derive_payment_secret_from_payment_preimage(self):
|
||||||
|
|
Loading…
Add table
Reference in a new issue