2121import aiorpcx
2222from aiorpcx import ignore_after
2323
24- from .crypto import sha256 , sha256d , privkey_to_pubkey
24+ from .crypto import sha256 , sha256d , privkey_to_pubkey , get_ecdh
2525from . import bitcoin , util
2626from . import constants
27+ from .onion_message import blinding_privkey
2728from .util import (log_exceptions , ignore_exceptions , chunks , OldTaskGroup ,
2829 UnrelatedTransactionException , error_text_bytes_to_safe_str , AsyncHangDetector ,
2930 NoDynamicFeeEstimates , event_listener , EventListener )
3536from .lnonion import (new_onion_packet , OnionFailureCode , calc_hops_data_for_payment , process_onion_packet ,
3637 OnionPacket , construct_onion_error , obfuscate_onion_error , OnionRoutingFailure ,
3738 ProcessedOnionPacket , UnsupportedOnionPacketVersion , InvalidOnionMac , InvalidOnionPubkey ,
38- OnionFailureCodeMetaFlag , calc_hops_data_for_blinded_payment )
39+ OnionFailureCodeMetaFlag , calc_hops_data_for_blinded_payment , decrypt_onionmsg_data_tlv )
3940from .lnchannel import Channel , RevokeAndAck , RemoteCtnTooFarInFuture , ChannelState , PeerState , ChanCloseOption , CF_ANNOUNCE_CHANNEL
4041from . import lnutil
4142from .lnutil import (Outpoint , LocalConfig , RECEIVED , UpdateAddHtlc , ChannelConfig ,
@@ -2063,12 +2064,14 @@ def on_update_add_htlc(self, chan: Channel, payload):
20632064 cltv_abs = payload ["cltv_expiry" ]
20642065 amount_msat_htlc = payload ["amount_msat" ]
20652066 onion_packet = payload ["onion_routing_packet" ]
2067+ blinding = payload .get ("update_add_htlc_tlvs" , {}).get ("blinded_path" , {}).get ("path_key" )
20662068 htlc = UpdateAddHtlc (
20672069 amount_msat = amount_msat_htlc ,
20682070 payment_hash = payment_hash ,
20692071 cltv_abs = cltv_abs ,
20702072 timestamp = int (time .time ()),
2071- htlc_id = htlc_id )
2073+ htlc_id = htlc_id ,
2074+ blinding = blinding )
20722075 self .logger .info (f"on_update_add_htlc. chan { chan .short_channel_id } . htlc={ str (htlc )} " )
20732076 if chan .get_state () != ChannelState .OPEN :
20742077 raise RemoteMisbehaving (f"received update_add_htlc while chan.get_state() != OPEN. state was { chan .get_state ()!r} " )
@@ -2115,11 +2118,29 @@ def check_accepted_htlc(
21152118 raise OnionRoutingFailure (
21162119 code = OnionFailureCode .FINAL_INCORRECT_CLTV_EXPIRY ,
21172120 data = htlc .cltv_abs .to_bytes (4 , byteorder = "big" ))
2118- try :
2119- total_msat = processed_onion .hop_data .payload ["payment_data" ]["total_msat" ] # type: int
2120- except Exception :
2121- log_fail_reason (f"'total_msat' missing from onion" )
2122- raise exc_incorrect_or_unknown_pd
2121+
2122+ if htlc .blinding : # payment over blinded path
2123+ # spec: MUST return an error if the payload contains other tlv fields than encrypted_recipient_data,
2124+ # current_path_key, amt_to_forward, outgoing_cltv_value and total_amount_msat.
2125+ assert all (x in ['encrypted_recipient_data' , 'current_blinding_point' , 'amt_to_forward' , 'outgoing_cltv_value' , 'total_amount_msat' ]
2126+ for x in processed_onion .hop_data .payload .keys ())
2127+ shared_secret = get_ecdh (self .privkey , htlc .blinding )
2128+ recipient_data = decrypt_onionmsg_data_tlv (
2129+ shared_secret = shared_secret ,
2130+ encrypted_recipient_data = processed_onion .hop_data .payload ['encrypted_recipient_data' ]['encrypted_data' ]
2131+ )
2132+ payment_secret_from_onion = recipient_data ['path_id' ]['data' ]
2133+ try :
2134+ total_msat = processed_onion .hop_data .payload ['total_amount_msat' ]['total_msat' ]
2135+ except Exception as e :
2136+ log_fail_reason (f"'total_msat' missing from onion" )
2137+ raise exc_incorrect_or_unknown_pd
2138+ else :
2139+ try :
2140+ total_msat = processed_onion .hop_data .payload ["payment_data" ]["total_msat" ] # type: int
2141+ except Exception :
2142+ log_fail_reason (f"'total_msat' missing from onion" )
2143+ raise exc_incorrect_or_unknown_pd
21232144
21242145 if chan .opening_fee :
21252146 channel_opening_fee = chan .opening_fee ['channel_opening_fee' ] # type: int
@@ -2134,11 +2155,12 @@ def check_accepted_htlc(
21342155 code = OnionFailureCode .FINAL_INCORRECT_HTLC_AMOUNT ,
21352156 data = htlc .amount_msat .to_bytes (8 , byteorder = "big" ))
21362157
2137- try :
2138- payment_secret_from_onion = processed_onion .hop_data .payload ["payment_data" ]["payment_secret" ] # type: bytes
2139- except Exception :
2140- log_fail_reason (f"'payment_secret' missing from onion" )
2141- raise exc_incorrect_or_unknown_pd
2158+ if not htlc .blinding :
2159+ try :
2160+ payment_secret_from_onion = processed_onion .hop_data .payload ["payment_data" ]["payment_secret" ] # type: bytes
2161+ except Exception :
2162+ log_fail_reason (f"'payment_secret' missing from onion" )
2163+ raise exc_incorrect_or_unknown_pd
21422164
21432165 return payment_secret_from_onion , total_msat , channel_opening_fee , exc_incorrect_or_unknown_pd
21442166
@@ -2794,7 +2816,7 @@ async def htlc_switch(self):
27942816 onion_packet = None
27952817 try :
27962818 onion_packet = OnionPacket .from_bytes (onion_packet_bytes )
2797- except OnionRoutingFailure as e :
2819+ except OnionRoutingFailure as e : # NOTE: never reached?
27982820 error_reason = e
27992821 else :
28002822 try :
@@ -2808,6 +2830,7 @@ async def htlc_switch(self):
28082830 assert forwarding_key is None
28092831 unfulfilled [htlc_id ] = onion_packet_hex , _forwarding_key
28102832 except OnionRoutingFailure as e :
2833+ self .logger .debug (f'OnionRoutingFailure: { e .code !r} ' )
28112834 error_bytes = construct_onion_error (e , onion_packet .public_key , self .privkey , self .network .get_local_height ())
28122835 if error_bytes :
28132836 error_bytes = obfuscate_onion_error (error_bytes , onion_packet .public_key , our_onion_private_key = self .privkey )
@@ -2874,6 +2897,7 @@ def process_unfulfilled_htlc(
28742897 processed_onion = self .process_onion_packet (
28752898 onion_packet ,
28762899 payment_hash = payment_hash ,
2900+ blinding = htlc .blinding ,
28772901 onion_packet_bytes = onion_packet_bytes )
28782902
28792903 preimage , forwarding_info = self .maybe_fulfill_htlc (
@@ -2940,13 +2964,16 @@ def process_onion_packet(
29402964 onion_packet : OnionPacket , * ,
29412965 payment_hash : bytes ,
29422966 onion_packet_bytes : bytes ,
2967+ blinding : bytes = None ,
29432968 is_trampoline : bool = False ) -> ProcessedOnionPacket :
29442969
29452970 failure_data = sha256 (onion_packet_bytes )
2971+ privkey = blinding_privkey (privkey = self .privkey , blinding = blinding ) if blinding else self .privkey
2972+
29462973 try :
29472974 processed_onion = process_onion_packet (
29482975 onion_packet ,
2949- our_onion_private_key = self . privkey ,
2976+ our_onion_private_key = privkey ,
29502977 associated_data = payment_hash ,
29512978 is_trampoline = is_trampoline )
29522979 except UnsupportedOnionPacketVersion :
0 commit comments