lnpeer: obfuscate error pakets of forwarded htlcs, that we
propageate back to the sender. lnworker: in htlc_fulfilled and htlc_failed, return early if the htlc was forwarded, so that we do not trigger invoice callbacks
This commit is contained in:
@@ -396,7 +396,7 @@ class OnionRoutingFailure(Exception):
|
||||
|
||||
def construct_onion_error(
|
||||
reason: OnionRoutingFailure,
|
||||
onion_packet: OnionPacket,
|
||||
their_public_key: bytes,
|
||||
our_onion_private_key: bytes,
|
||||
) -> bytes:
|
||||
# create payload
|
||||
@@ -409,11 +409,14 @@ def construct_onion_error(
|
||||
error_packet += pad_len.to_bytes(2, byteorder="big")
|
||||
error_packet += bytes(pad_len)
|
||||
# add hmac
|
||||
shared_secret = get_ecdh(our_onion_private_key, onion_packet.public_key)
|
||||
shared_secret = get_ecdh(our_onion_private_key, their_public_key)
|
||||
um_key = get_bolt04_onion_key(b'um', shared_secret)
|
||||
hmac_ = hmac_oneshot(um_key, msg=error_packet, digest=hashlib.sha256)
|
||||
error_packet = hmac_ + error_packet
|
||||
# obfuscate
|
||||
return error_packet
|
||||
|
||||
def obfuscate_onion_error(error_packet, their_public_key, our_onion_private_key):
|
||||
shared_secret = get_ecdh(our_onion_private_key, their_public_key)
|
||||
ammag_key = get_bolt04_onion_key(b'ammag', shared_secret)
|
||||
stream_bytes = generate_cipher_stream(ammag_key, len(error_packet))
|
||||
error_packet = xor_bytes(error_packet, stream_bytes)
|
||||
|
||||
@@ -28,7 +28,7 @@ from .bitcoin import make_op_return, DummyAddress
|
||||
from .transaction import PartialTxOutput, match_script_against_template, Sighash
|
||||
from .logging import Logger
|
||||
from .lnonion import (new_onion_packet, OnionFailureCode, calc_hops_data_for_payment,
|
||||
process_onion_packet, OnionPacket, construct_onion_error, OnionRoutingFailure,
|
||||
process_onion_packet, OnionPacket, construct_onion_error, obfuscate_onion_error, OnionRoutingFailure,
|
||||
ProcessedOnionPacket, UnsupportedOnionPacketVersion, InvalidOnionMac, InvalidOnionPubkey,
|
||||
OnionFailureCodeMetaFlag)
|
||||
from .lnchannel import Channel, RevokeAndAck, RemoteCtnTooFarInFuture, ChannelState, PeerState, ChanCloseOption, CF_ANNOUNCE_CHANNEL
|
||||
@@ -2405,7 +2405,9 @@ class Peer(Logger):
|
||||
onion_packet_bytes=onion_packet_bytes,
|
||||
onion_packet=onion_packet)
|
||||
except OnionRoutingFailure as e:
|
||||
error_bytes = construct_onion_error(e, onion_packet, our_onion_private_key=self.privkey)
|
||||
error_bytes = construct_onion_error(e, onion_packet.public_key, our_onion_private_key=self.privkey)
|
||||
if error_bytes:
|
||||
error_bytes = obfuscate_onion_error(error_bytes, onion_packet.public_key, our_onion_private_key=self.privkey)
|
||||
if fw_info:
|
||||
unfulfilled[htlc_id] = local_ctn, remote_ctn, onion_packet_hex, fw_info
|
||||
self.lnworker.downstream_htlc_to_upstream_peer_map[fw_info] = self.pubkey
|
||||
|
||||
@@ -2281,23 +2281,24 @@ class LNWallet(LNWorker):
|
||||
info = info._replace(status=status)
|
||||
self.save_payment_info(info)
|
||||
|
||||
def _on_maybe_forwarded_htlc_resolved(self, chan: Channel, htlc_id: int) -> None:
|
||||
def is_forwarded_htlc_notify(self, chan: Channel, htlc_id: int) -> None:
|
||||
"""Called when an HTLC we offered on chan gets irrevocably fulfilled or failed.
|
||||
If we find this was a forwarded HTLC, the upstream peer is notified.
|
||||
"""
|
||||
fw_info = chan.short_channel_id.hex(), htlc_id
|
||||
upstream_peer_pubkey = self.downstream_htlc_to_upstream_peer_map.get(fw_info)
|
||||
if not upstream_peer_pubkey:
|
||||
return
|
||||
return False
|
||||
upstream_peer = self.peers.get(upstream_peer_pubkey)
|
||||
if not upstream_peer:
|
||||
return
|
||||
upstream_peer.downstream_htlc_resolved_event.set()
|
||||
upstream_peer.downstream_htlc_resolved_event.clear()
|
||||
if upstream_peer:
|
||||
upstream_peer.downstream_htlc_resolved_event.set()
|
||||
upstream_peer.downstream_htlc_resolved_event.clear()
|
||||
return True
|
||||
|
||||
def htlc_fulfilled(self, chan: Channel, payment_hash: bytes, htlc_id: int):
|
||||
util.trigger_callback('htlc_fulfilled', payment_hash, chan, htlc_id)
|
||||
self._on_maybe_forwarded_htlc_resolved(chan=chan, htlc_id=htlc_id)
|
||||
if self.is_forwarded_htlc_notify(chan=chan, htlc_id=htlc_id):
|
||||
return
|
||||
q = None
|
||||
if shi := self.sent_htlcs_info.get((payment_hash, chan.short_channel_id, htlc_id)):
|
||||
chan.pop_onion_key(htlc_id)
|
||||
@@ -2328,7 +2329,8 @@ class LNWallet(LNWorker):
|
||||
failure_message: Optional['OnionRoutingFailure']):
|
||||
|
||||
util.trigger_callback('htlc_failed', payment_hash, chan, htlc_id)
|
||||
self._on_maybe_forwarded_htlc_resolved(chan=chan, htlc_id=htlc_id)
|
||||
if self.is_forwarded_htlc_notify(chan=chan, htlc_id=htlc_id):
|
||||
return
|
||||
q = None
|
||||
if shi := self.sent_htlcs_info.get((payment_hash, chan.short_channel_id, htlc_id)):
|
||||
onion_key = chan.pop_onion_key(htlc_id)
|
||||
|
||||
Reference in New Issue
Block a user