Skip to content

Commit 00fa74d

Browse files
committed
lnchannel: split determine_htlc_constraints from _assert_can_add_htlc
1 parent d855199 commit 00fa74d

File tree

1 file changed

+45
-14
lines changed

1 file changed

+45
-14
lines changed

electrum/lnchannel.py

+45-14
Original file line numberDiff line numberDiff line change
@@ -1068,18 +1068,14 @@ def _assert_can_add_htlc(self, *, htlc_proposer: HTLCOwner, amount_msat: int,
10681068
"""Raises PaymentFailure if the htlc_proposer cannot add this new HTLC.
10691069
(this is relevant both for forwarding and endpoint)
10701070
"""
1071+
# NOTE: ignore_min_htlc_value never used?
10711072
htlc_receiver = htlc_proposer.inverted()
10721073
# note: all these tests are about the *receiver's* *next* commitment transaction,
10731074
# and the constraints are the ones imposed by their config
10741075
ctn = self.get_next_ctn(htlc_receiver)
10751076
chan_config = self.config[htlc_receiver]
1076-
if self.get_state() != ChannelState.OPEN:
1077-
raise PaymentFailure('Channel not open', self.get_state())
1078-
if htlc_proposer == LOCAL:
1079-
if not self.can_send_ctx_updates():
1080-
raise PaymentFailure('Channel cannot send ctx updates')
1081-
if not self.can_send_update_add_htlc():
1082-
raise PaymentFailure('Channel cannot add htlc')
1077+
1078+
htlc_min, htlc_max, num_htlcs = self.determine_htlc_constraints(htlc_proposer)
10831079

10841080
# If proposer is LOCAL we apply stricter checks as that is behaviour we can control.
10851081
# This should lead to fewer disagreements (i.e. channels failing).
@@ -1089,32 +1085,67 @@ def _assert_can_add_htlc(self, *, htlc_proposer: HTLCOwner, amount_msat: int,
10891085
if not ignore_min_htlc_value:
10901086
if amount_msat <= 0:
10911087
raise PaymentFailure("HTLC value must be positive")
1092-
if amount_msat < chan_config.htlc_minimum_msat:
1088+
if amount_msat < htlc_min:
10931089
raise PaymentFailure(f'HTLC value too small: {amount_msat} msat')
10941090

10951091
# check proposer can afford htlc
10961092
max_can_send_msat = self.available_to_spend(htlc_proposer, strict=strict)
10971093
if max_can_send_msat < amount_msat:
10981094
raise PaymentFailure(f'Not enough balance. can send: {max_can_send_msat}, tried: {amount_msat}')
10991095

1096+
# check "max_htlc_value_in_flight_msat"
1097+
current_htlc_sum = htlcsum(self.hm.htlcs_by_direction(htlc_receiver, direction=RECEIVED, ctn=ctn).values())
1098+
if current_htlc_sum + amount_msat > chan_config.max_htlc_value_in_flight_msat:
1099+
raise PaymentFailure(f'HTLC value sum (sum of pending htlcs: {current_htlc_sum/1000} sat '
1100+
f'plus new htlc: {amount_msat/1000} sat) '
1101+
f'would exceed max allowed: {chan_config.max_htlc_value_in_flight_msat/1000} sat')
1102+
1103+
def determine_htlc_constraints(self, htlc_proposer: HTLCOwner) -> Tuple[int, int, int]:
1104+
"""Raises PaymentFailure if no valid amount range can be determined, or if no HTLCs can be added.
1105+
(this is relevant both for forwarding and endpoint)
1106+
"""
1107+
htlc_receiver = htlc_proposer.inverted()
1108+
ctn = self.get_next_ctn(htlc_receiver)
1109+
chan_config = self.config[htlc_receiver]
1110+
if self.get_state() != ChannelState.OPEN:
1111+
raise PaymentFailure('Channel not open', self.get_state())
1112+
if htlc_proposer == LOCAL:
1113+
if not self.can_send_ctx_updates():
1114+
raise PaymentFailure('Channel cannot send ctx updates')
1115+
if not self.can_send_update_add_htlc():
1116+
raise PaymentFailure('Channel cannot add htlc')
1117+
1118+
# If proposer is LOCAL we apply stricter checks as that is behaviour we can control.
1119+
# This should lead to fewer disagreements (i.e. channels failing).
1120+
strict = (htlc_proposer == LOCAL)
1121+
11001122
# check "max_accepted_htlcs"
11011123
# this is the loose check BOLT-02 specifies:
1102-
if len(self.hm.htlcs_by_direction(htlc_receiver, direction=RECEIVED, ctn=ctn)) + 1 > chan_config.max_accepted_htlcs:
1124+
remaining_num_htlcs = (chan_config.max_accepted_htlcs
1125+
- len(self.hm.htlcs_by_direction(htlc_receiver, direction=RECEIVED, ctn=ctn)))
1126+
if remaining_num_htlcs < 1:
11031127
raise PaymentFailure('Too many HTLCs already in channel')
11041128
# however, c-lightning is a lot stricter, so extra checks:
11051129
# https://github.com/ElementsProject/lightning/blob/4dcd4ca1556b13b6964a10040ba1d5ef82de4788/channeld/full_channel.c#L581
11061130
if strict:
11071131
max_concurrent_htlcs = min(self.config[htlc_proposer].max_accepted_htlcs,
11081132
self.config[htlc_receiver].max_accepted_htlcs)
1109-
if len(self.hm.htlcs(htlc_receiver, ctn=ctn)) + 1 > max_concurrent_htlcs:
1133+
remaining_num_htlcs = max_concurrent_htlcs - len(self.hm.htlcs(htlc_receiver, ctn=ctn))
1134+
if remaining_num_htlcs < 1:
11101135
raise PaymentFailure('Too many HTLCs already in channel')
11111136

11121137
# check "max_htlc_value_in_flight_msat"
11131138
current_htlc_sum = htlcsum(self.hm.htlcs_by_direction(htlc_receiver, direction=RECEIVED, ctn=ctn).values())
1114-
if current_htlc_sum + amount_msat > chan_config.max_htlc_value_in_flight_msat:
1115-
raise PaymentFailure(f'HTLC value sum (sum of pending htlcs: {current_htlc_sum/1000} sat '
1116-
f'plus new htlc: {amount_msat/1000} sat) '
1117-
f'would exceed max allowed: {chan_config.max_htlc_value_in_flight_msat/1000} sat')
1139+
remaining_max_inflight = chan_config.max_htlc_value_in_flight_msat - current_htlc_sum
1140+
1141+
max_can_send_msat = min(self.available_to_spend(htlc_proposer, strict=strict), remaining_max_inflight)
1142+
1143+
if max_can_send_msat <= chan_config.htlc_minimum_msat:
1144+
raise PaymentFailure(f'Remaining allowed inflight HTLC amount '
1145+
f'(max: {chan_config.max_htlc_value_in_flight_msat/1000} sat, '
1146+
f'sum of pending htlcs: {current_htlc_sum/1000} sat) '
1147+
f'does not exceed min HTLC amount (min: {chan_config.htlc_minimum_msat/1000} sat). ')
1148+
return chan_config.htlc_minimum_msat, max_can_send_msat, remaining_num_htlcs
11181149

11191150
def can_pay(self, amount_msat: int, *, check_frozen=False) -> bool:
11201151
"""Returns whether we can add an HTLC of given value."""

0 commit comments

Comments
 (0)