diff --git a/electrum/lnonion.py b/electrum/lnonion.py index 7760fd445..10fb2291f 100644 --- a/electrum/lnonion.py +++ b/electrum/lnonion.py @@ -47,7 +47,6 @@ if TYPE_CHECKING: HOPS_DATA_SIZE = 1300 # also sometimes called routingInfoSize in bolt-04 -TRAMPOLINE_HOPS_DATA_SIZE = 400 PER_HOP_HMAC_SIZE = 32 ONION_MESSAGE_LARGE_SIZE = 32768 @@ -134,7 +133,6 @@ class OnionPacket: def __post_init__(self): assert len(self.public_key) == 33 - assert len(self.hops_data) in [HOPS_DATA_SIZE, TRAMPOLINE_HOPS_DATA_SIZE, ONION_MESSAGE_LARGE_SIZE] assert len(self.hmac) == PER_HOP_HMAC_SIZE if not ecc.ECPubkey.is_pubkey_bytes(self.public_key): raise InvalidOnionPubkey() @@ -144,14 +142,10 @@ class OnionPacket: ret += self.public_key ret += self.hops_data ret += self.hmac - if len(ret) - 66 not in [HOPS_DATA_SIZE, TRAMPOLINE_HOPS_DATA_SIZE, ONION_MESSAGE_LARGE_SIZE]: - raise Exception('unexpected length {}'.format(len(ret))) return ret @classmethod def from_bytes(cls, b: bytes) -> 'OnionPacket': - if len(b) - 66 not in [HOPS_DATA_SIZE, TRAMPOLINE_HOPS_DATA_SIZE, ONION_MESSAGE_LARGE_SIZE]: - raise Exception('unexpected length {}'.format(len(b))) return OnionPacket( public_key=b[1:34], hops_data=b[34:-32], @@ -217,7 +211,7 @@ def new_onion_packet( # FIXME: serializing here and again below. cache bytes in OnionHopsDataSingle? _raw_bytes_payload? payload_size += PER_HOP_HMAC_SIZE + len(hops_data[i].to_bytes()) if trampoline: - data_size = TRAMPOLINE_HOPS_DATA_SIZE + data_size = payload_size elif onion_message: if payload_size <= HOPS_DATA_SIZE: data_size = HOPS_DATA_SIZE @@ -446,7 +440,7 @@ def process_onion_packet( raise InvalidOnionMac() # peel an onion layer off rho_key = get_bolt04_onion_key(b'rho', shared_secret) - data_size = TRAMPOLINE_HOPS_DATA_SIZE if is_trampoline else HOPS_DATA_SIZE + data_size = len(onion_packet.hops_data) if is_trampoline else HOPS_DATA_SIZE if is_onion_message and len(onion_packet.hops_data) > HOPS_DATA_SIZE: data_size = ONION_MESSAGE_LARGE_SIZE stream_bytes = generate_cipher_stream(rho_key, 2 * data_size) @@ -459,15 +453,8 @@ def process_onion_packet( if trampoline_onion_packet: if is_trampoline: raise Exception("found nested trampoline inside trampoline") - top_version = trampoline_onion_packet.get('version') - top_public_key = trampoline_onion_packet.get('public_key') - top_hops_data = trampoline_onion_packet.get('hops_data') - top_hops_data_fd = io.BytesIO(top_hops_data) - top_hmac = trampoline_onion_packet.get('hmac') - trampoline_onion_packet = OnionPacket( - public_key=top_public_key, - hops_data=top_hops_data_fd.read(TRAMPOLINE_HOPS_DATA_SIZE), - hmac=top_hmac) + trampoline_onion_packet = trampoline_onion_packet['trampoline_onion_packet'] + trampoline_onion_packet = OnionPacket.from_bytes(trampoline_onion_packet) # calc next ephemeral key blinding_factor = sha256(onion_packet.public_key + shared_secret) blinding_factor_int = int.from_bytes(blinding_factor, byteorder="big") diff --git a/electrum/lnwire/onion_wire.csv b/electrum/lnwire/onion_wire.csv index 08e40399a..06b55da1b 100644 --- a/electrum/lnwire/onion_wire.csv +++ b/electrum/lnwire/onion_wire.csv @@ -22,10 +22,7 @@ tlvdata,payload,outgoing_node_id,outgoing_node_id,byte,33 tlvtype,payload,invoice_routing_info,66099 tlvdata,payload,invoice_routing_info,invoice_routing_info,byte,... tlvtype,payload,trampoline_onion_packet,66100 -tlvdata,payload,trampoline_onion_packet,version,byte,1 -tlvdata,payload,trampoline_onion_packet,public_key,byte,33 -tlvdata,payload,trampoline_onion_packet,hops_data,byte,400 -tlvdata,payload,trampoline_onion_packet,hmac,byte,32 +tlvdata,payload,trampoline_onion_packet,trampoline_onion_packet,byte,... tlvtype,encrypted_data_tlv,padding,1 tlvdata,encrypted_data_tlv,padding,padding,byte,... tlvtype,encrypted_data_tlv,short_channel_id,2 diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 079702380..01b86f738 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -4093,10 +4093,7 @@ class LNWallet(Logger): self.logger.info(f'adding trampoline onion to final payload') trampoline_payload = dict(hops_data[-1].payload) trampoline_payload["trampoline_onion_packet"] = { - "version": trampoline_onion.version, - "public_key": trampoline_onion.public_key, - "hops_data": trampoline_onion.hops_data, - "hmac": trampoline_onion.hmac + "trampoline_onion_packet": trampoline_onion.to_bytes() } hops_data[-1] = dataclasses.replace(hops_data[-1], payload=trampoline_payload) if t_hops_data := trampoline_onion._debug_hops_data: # None if trampoline-forwarding diff --git a/electrum/trampoline.py b/electrum/trampoline.py index 53365fc0e..78f13c551 100644 --- a/electrum/trampoline.py +++ b/electrum/trampoline.py @@ -7,7 +7,7 @@ from types import MappingProxyType from .lnutil import LnFeatures, PaymentFeeBudget, FeeBudgetExceeded from .lnonion import ( - calc_hops_data_for_payment, new_onion_packet, OnionPacket, TRAMPOLINE_HOPS_DATA_SIZE, PER_HOP_HMAC_SIZE + calc_hops_data_for_payment, new_onion_packet, OnionPacket, PER_HOP_HMAC_SIZE ) from .lnrouter import TrampolineEdge, is_route_within_budget, LNPaymentTRoute from .lnutil import NoPathFound @@ -40,6 +40,8 @@ TRAMPOLINE_NODES_SIGNET = { _TRAMPOLINE_NODES_UNITTESTS = {} # used in unit tests +TRAMPOLINE_HOPS_MAX_DATA_SIZE = 500 + def hardcoded_trampoline_nodes() -> Mapping[str, LNPeerAddr]: if _TRAMPOLINE_NODES_UNITTESTS: @@ -332,7 +334,7 @@ def create_trampoline_onion( payload = dict(hops_data[index].payload) # try different r_tag order on each attempt invoice_routing_info = random_shuffled_copy(route[index].invoice_routing_info) - remaining_payload_space = TRAMPOLINE_HOPS_DATA_SIZE \ + remaining_payload_space = TRAMPOLINE_HOPS_MAX_DATA_SIZE \ - sum(len(hop.to_bytes()) + PER_HOP_HMAC_SIZE for hop in hops_data) routing_info_to_use = [] for encoded_r_tag in invoice_routing_info: diff --git a/tests/test_lnpeer.py b/tests/test_lnpeer.py index 6fdb6c0f1..8669931c2 100644 --- a/tests/test_lnpeer.py +++ b/tests/test_lnpeer.py @@ -2742,10 +2742,7 @@ class TestPeerForwarding(TestPeer): assert len(hops_data) == 1 new_payload = dict(hops_data[0].payload) new_payload['trampoline_onion_packet'] = { - "version": modified_trampoline_onion.version, - "public_key": modified_trampoline_onion.public_key, - "hops_data": modified_trampoline_onion.hops_data, - "hmac": modified_trampoline_onion.hmac, + "trampoline_onion_packet": modified_trampoline_onion.to_bytes() } hops_data[0] = dataclasses.replace(hops_data[0], payload=MappingProxyType(new_payload)) modified_trampoline_onion = None