mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
lnpeer: add a few sanity checks to payment-forwarding (and related)
This commit is contained in:
parent
0973b86925
commit
d2d4d19fcb
2 changed files with 47 additions and 12 deletions
|
@ -378,8 +378,8 @@ class OnionFailureCode(IntEnum):
|
|||
FEE_INSUFFICIENT = UPDATE | 12
|
||||
INCORRECT_CLTV_EXPIRY = UPDATE | 13
|
||||
EXPIRY_TOO_SOON = UPDATE | 14
|
||||
UNKNOWN_PAYMENT_HASH = PERM | 15
|
||||
INCORRECT_PAYMENT_AMOUNT = PERM | 16
|
||||
INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS = PERM | 15
|
||||
_LEGACY_INCORRECT_PAYMENT_AMOUNT = PERM | 16
|
||||
FINAL_EXPIRY_TOO_SOON = 17
|
||||
FINAL_INCORRECT_CLTV_EXPIRY = 18
|
||||
FINAL_INCORRECT_HTLC_AMOUNT = 19
|
||||
|
|
|
@ -31,6 +31,7 @@ from .lnonion import (new_onion_packet, decode_onion_error, OnionFailureCode, ca
|
|||
process_onion_packet, OnionPacket, construct_onion_error, OnionRoutingFailureMessage,
|
||||
ProcessedOnionPacket)
|
||||
from .lnchannel import Channel, RevokeAndAck, htlcsum, RemoteCtnTooFarInFuture
|
||||
from . import lnutil
|
||||
from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc,
|
||||
RemoteConfig, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore,
|
||||
funding_output_script, get_per_commitment_secret_from_seed,
|
||||
|
@ -39,7 +40,8 @@ from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc,
|
|||
get_ln_flag_pair_of_bit, privkey_to_pubkey, UnknownPaymentHash, MIN_FINAL_CLTV_EXPIRY_ACCEPTED,
|
||||
LightningPeerConnectionClosed, HandshakeFailed, NotFoundChanAnnouncementForUpdate,
|
||||
MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED, MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED,
|
||||
MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED, RemoteMisbehaving, DEFAULT_TO_SELF_DELAY)
|
||||
MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED, RemoteMisbehaving, DEFAULT_TO_SELF_DELAY,
|
||||
NBLOCK_OUR_CLTV_EXPIRY_DELTA, format_short_channel_id)
|
||||
from .lnutil import FeeUpdate
|
||||
from .lntransport import LNTransport, LNTransportBase
|
||||
from .lnmsg import encode_msg, decode_msg
|
||||
|
@ -1110,6 +1112,8 @@ class Peer(Logger):
|
|||
|
||||
async def await_remote(self, chan: Channel, ctn: int):
|
||||
self.maybe_send_commitment(chan)
|
||||
# TODO review this. I suspect some callers want updates irrevocably committed,
|
||||
# so comparision should use chan.get_oldest_unrevoked_ctn(REMOTE)
|
||||
while chan.get_latest_ctn(REMOTE) <= ctn:
|
||||
await self._remote_changed_events[chan.channel_id].wait()
|
||||
|
||||
|
@ -1200,9 +1204,11 @@ class Peer(Logger):
|
|||
onion_packet = OnionPacket.from_bytes(payload["onion_routing_packet"])
|
||||
processed_onion = process_onion_packet(onion_packet, associated_data=payment_hash, our_onion_private_key=self.privkey)
|
||||
chan = self.channels[channel_id]
|
||||
assert chan.get_state() == "OPEN"
|
||||
if chan.get_state() != "OPEN":
|
||||
raise RemoteMisbehaving(f"received update_add_htlc while chan.get_state() != OPEN. state was {chan.get_state()}")
|
||||
if cltv_expiry >= 500_000_000:
|
||||
pass # TODO fail the channel
|
||||
self.lnworker.force_close_channel(channel_id)
|
||||
raise RemoteMisbehaving(f"received update_add_htlc with cltv_expiry >= 500_000_000. value was {cltv_expiry}")
|
||||
# add htlc
|
||||
htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc,
|
||||
payment_hash=payment_hash,
|
||||
|
@ -1243,15 +1249,44 @@ class Peer(Logger):
|
|||
return
|
||||
dph = processed_onion.hop_data.per_hop
|
||||
next_chan = self.lnworker.get_channel_by_short_id(dph.short_channel_id)
|
||||
next_chan_scid = format_short_channel_id(dph.short_channel_id)
|
||||
next_peer = self.lnworker.peers[next_chan.node_id]
|
||||
if next_chan is None or next_chan.get_state() != 'OPEN':
|
||||
self.logger.info(f"cannot forward htlc {next_chan.get_state() if next_chan else None}")
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.PERMANENT_CHANNEL_FAILURE, data=b'')
|
||||
local_height = self.network.get_local_height()
|
||||
if next_chan is None:
|
||||
self.logger.info(f"cannot forward htlc. cannot find next_chan {next_chan_scid}")
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.UNKNOWN_NEXT_PEER, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
if next_chan.get_state() != 'OPEN':
|
||||
self.logger.info(f"cannot forward htlc. next_chan not OPEN: {next_chan_scid} in state {next_chan.get_state()}")
|
||||
#reason = OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_CHANNEL_FAILURE, data=) # FIXME data
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
self.logger.info(f'forwarding htlc to {next_chan.node_id}')
|
||||
next_cltv_expiry = int.from_bytes(dph.outgoing_cltv_value, 'big')
|
||||
if htlc.cltv_expiry - next_cltv_expiry < NBLOCK_OUR_CLTV_EXPIRY_DELTA:
|
||||
#reason = OnionRoutingFailureMessage(code=OnionFailureCode.INCORRECT_CLTV_EXPIRY, data=) # FIXME data
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
if htlc.cltv_expiry - lnutil.NBLOCK_DEADLINE_BEFORE_EXPIRY_FOR_RECEIVED_HTLCS <= local_height \
|
||||
or next_cltv_expiry <= local_height:
|
||||
#reason = OnionRoutingFailureMessage(code=OnionFailureCode.EXPIRY_TOO_SOON, data=) # FIXME data
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
if max(htlc.cltv_expiry, next_cltv_expiry) > local_height + lnutil.NBLOCK_CLTV_EXPIRY_TOO_FAR_INTO_FUTURE:
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.EXPIRY_TOO_FAR, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
next_amount_msat_htlc = int.from_bytes(dph.amt_to_forward, 'big')
|
||||
if htlc.amount_msat - next_amount_msat_htlc < 0: # TODO fees?
|
||||
# reason = OnionRoutingFailureMessage(code=OnionFailureCode.FEE_INSUFFICIENT, data=) # FIXME data
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
|
||||
self.logger.info(f'forwarding htlc to {next_chan.node_id}')
|
||||
next_htlc = UpdateAddHtlc(amount_msat=next_amount_msat_htlc, payment_hash=htlc.payment_hash, cltv_expiry=next_cltv_expiry, timestamp=int(time.time()))
|
||||
next_htlc = next_chan.add_htlc(next_htlc)
|
||||
next_remote_ctn = next_chan.get_latest_ctn(REMOTE)
|
||||
|
@ -1280,13 +1315,13 @@ class Peer(Logger):
|
|||
invoice = self.lnworker.get_invoice(htlc.payment_hash)
|
||||
preimage = self.lnworker.get_preimage(htlc.payment_hash)
|
||||
except UnknownPaymentHash:
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.UNKNOWN_PAYMENT_HASH, data=b'')
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
expected_received_msat = int(invoice.amount * bitcoin.COIN * 1000) if invoice.amount is not None else None
|
||||
if expected_received_msat is not None and \
|
||||
(htlc.amount_msat < expected_received_msat or htlc.amount_msat > 2 * expected_received_msat):
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.INCORRECT_PAYMENT_AMOUNT, data=b'')
|
||||
not (expected_received_msat <= htlc.amount_msat <= 2 * expected_received_msat):
|
||||
reason = OnionRoutingFailureMessage(code=OnionFailureCode.INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS, data=b'')
|
||||
await self.fail_htlc(chan, htlc.htlc_id, onion_packet, reason)
|
||||
return
|
||||
local_height = self.network.get_local_height()
|
||||
|
|
Loading…
Add table
Reference in a new issue