diff --git a/electrum/lnonion.py b/electrum/lnonion.py index 3e8814c9b..7dc6d73ea 100644 --- a/electrum/lnonion.py +++ b/electrum/lnonion.py @@ -484,6 +484,7 @@ class OnionFailureCode(IntEnum): FINAL_INCORRECT_HTLC_AMOUNT = 19 CHANNEL_DISABLED = UPDATE | 20 EXPIRY_TOO_FAR = 21 + INVALID_ONION_PAYLOAD = PERM | 22 # don't use these elsewhere, the names are ambiguous without context diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py index fffc1e5fd..0b770b0ef 100644 --- a/electrum/lnpeer.py +++ b/electrum/lnpeer.py @@ -1149,7 +1149,10 @@ class Peer(Logger): if not forwarding_enabled: self.logger.info(f"forwarding is disabled. failing htlc.") return OnionRoutingFailureMessage(code=OnionFailureCode.PERMANENT_CHANNEL_FAILURE, data=b'') - next_chan_scid = processed_onion.hop_data.payload["short_channel_id"]["short_channel_id"] + try: + next_chan_scid = processed_onion.hop_data.payload["short_channel_id"]["short_channel_id"] + except: + return OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_PAYLOAD, data=b'\x00\x00\x00') next_chan = self.lnworker.get_channel_by_short_id(next_chan_scid) local_height = self.network.get_local_height() if next_chan is None: @@ -1162,7 +1165,10 @@ class Peer(Logger): f"chan state {next_chan.get_state()}, peer state: {next_chan.peer_state}") data = outgoing_chan_upd_len + outgoing_chan_upd return OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_CHANNEL_FAILURE, data=data) - next_cltv_expiry = processed_onion.hop_data.payload["outgoing_cltv_value"]["outgoing_cltv_value"] + try: + next_cltv_expiry = processed_onion.hop_data.payload["outgoing_cltv_value"]["outgoing_cltv_value"] + except: + return OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_PAYLOAD, data=b'\x00\x00\x00') if htlc.cltv_expiry - next_cltv_expiry < NBLOCK_OUR_CLTV_EXPIRY_DELTA: data = htlc.cltv_expiry.to_bytes(4, byteorder="big") + outgoing_chan_upd_len + outgoing_chan_upd return OnionRoutingFailureMessage(code=OnionFailureCode.INCORRECT_CLTV_EXPIRY, data=data) @@ -1172,7 +1178,10 @@ class Peer(Logger): return OnionRoutingFailureMessage(code=OnionFailureCode.EXPIRY_TOO_SOON, data=data) if max(htlc.cltv_expiry, next_cltv_expiry) > local_height + lnutil.NBLOCK_CLTV_EXPIRY_TOO_FAR_INTO_FUTURE: return OnionRoutingFailureMessage(code=OnionFailureCode.EXPIRY_TOO_FAR, data=b'') - next_amount_msat_htlc = processed_onion.hop_data.payload["amt_to_forward"]["amt_to_forward"] + try: + next_amount_msat_htlc = processed_onion.hop_data.payload["amt_to_forward"]["amt_to_forward"] + except: + return OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_PAYLOAD, data=b'\x00\x00\x00') forwarding_fees = fee_for_edge_msat( forwarded_amount_msat=next_amount_msat_htlc, fee_base_msat=lnutil.OUR_FEE_BASE_MSAT, @@ -1221,12 +1230,20 @@ class Peer(Logger): if local_height + MIN_FINAL_CLTV_EXPIRY_ACCEPTED > htlc.cltv_expiry: reason = OnionRoutingFailureMessage(code=OnionFailureCode.FINAL_EXPIRY_TOO_SOON, data=b'') return False, reason - cltv_from_onion = processed_onion.hop_data.payload["outgoing_cltv_value"]["outgoing_cltv_value"] + try: + cltv_from_onion = processed_onion.hop_data.payload["outgoing_cltv_value"]["outgoing_cltv_value"] + except: + reason = OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_PAYLOAD, data=b'\x00\x00\x00') + return False, reason if cltv_from_onion != htlc.cltv_expiry: reason = OnionRoutingFailureMessage(code=OnionFailureCode.FINAL_INCORRECT_CLTV_EXPIRY, data=htlc.cltv_expiry.to_bytes(4, byteorder="big")) return False, reason - amount_from_onion = processed_onion.hop_data.payload["amt_to_forward"]["amt_to_forward"] + try: + amount_from_onion = processed_onion.hop_data.payload["amt_to_forward"]["amt_to_forward"] + except: + reason = OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_PAYLOAD, data=b'\x00\x00\x00') + return False, reason if amount_from_onion > htlc.amount_msat: reason = OnionRoutingFailureMessage(code=OnionFailureCode.FINAL_INCORRECT_HTLC_AMOUNT, data=htlc.amount_msat.to_bytes(8, byteorder="big")) @@ -1463,6 +1480,9 @@ class Peer(Logger): error_reason = OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_KEY, data=sha256(onion_packet_bytes)) except InvalidOnionMac: error_reason = OnionRoutingFailureMessage(code=OnionFailureCode.INVALID_ONION_HMAC, data=sha256(onion_packet_bytes)) + except Exception as e: + self.logger.info(f"error processing onion packet: {e!r}") + error_reason = OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'') else: if processed_onion.are_we_final: preimage, error_reason = self.maybe_fulfill_htlc(