@@ -495,6 +495,9 @@ def close_and_cleanup(self):
495
495
self .lnworker .peer_closed (self )
496
496
self .got_disconnected .set ()
497
497
498
+ def is_shutdown_anysegwit (self ):
499
+ return self .features .supports (LnFeatures .OPTION_SHUTDOWN_ANYSEGWIT_OPT )
500
+
498
501
def is_static_remotekey (self ):
499
502
return self .features .supports (LnFeatures .OPTION_STATIC_REMOTEKEY_OPT )
500
503
@@ -531,7 +534,7 @@ def make_local_config(self, funding_sat: int, push_msat: int, initiator: HTLCOwn
531
534
static_remotekey = bfh (wallet .get_public_key (addr ))
532
535
else :
533
536
static_remotekey = None
534
- dust_limit_sat = bitcoin .DUST_LIMIT_DEFAULT_SAT_LEGACY
537
+ dust_limit_sat = bitcoin .DUST_LIMIT_P2PKH
535
538
reserve_sat = max (funding_sat // 100 , dust_limit_sat )
536
539
# for comparison of defaults, see
537
540
# https://github.com/ACINQ/eclair/blob/afa378fbb73c265da44856b4ad0f2128a88ae6c6/eclair-core/src/main/resources/reference.conf#L66
@@ -1343,6 +1346,8 @@ def maybe_forward_htlc(
1343
1346
# - for example; atm we forward first and then persist "forwarding_info",
1344
1347
# so if we segfault in-between and restart, we might forward an HTLC twice...
1345
1348
# (same for trampoline forwarding)
1349
+ # - we could check for the exposure to dust HTLCs, see:
1350
+ # https://github.com/ACINQ/eclair/pull/1985
1346
1351
forwarding_enabled = self .network .config .get ('lightning_forward_payments' , False )
1347
1352
if not forwarding_enabled :
1348
1353
self .logger .info (f"forwarding is disabled. failing htlc." )
@@ -1692,11 +1697,15 @@ async def on_shutdown(self, chan: Channel, payload):
1692
1697
if their_upfront_scriptpubkey :
1693
1698
if not (their_scriptpubkey == their_upfront_scriptpubkey ):
1694
1699
raise UpfrontShutdownScriptViolation ("remote didn't use upfront shutdown script it commited to in channel opening" )
1695
- # BOLT-02 restrict the scriptpubkey to some templates:
1696
- if not (match_script_against_template (their_scriptpubkey , transaction .SCRIPTPUBKEY_TEMPLATE_WITNESS_V0 )
1697
- or match_script_against_template (their_scriptpubkey , transaction .SCRIPTPUBKEY_TEMPLATE_P2SH )
1698
- or match_script_against_template (their_scriptpubkey , transaction .SCRIPTPUBKEY_TEMPLATE_P2PKH )):
1699
- raise Exception (f'scriptpubkey in received shutdown message does not conform to any template: { their_scriptpubkey .hex ()} ' )
1700
+ else :
1701
+ # BOLT-02 restrict the scriptpubkey to some templates:
1702
+ if self .is_shutdown_anysegwit () and match_script_against_template (their_scriptpubkey , transaction .SCRIPTPUBKEY_TEMPLATE_ANYSEGWIT ):
1703
+ pass
1704
+ elif match_script_against_template (their_scriptpubkey , transaction .SCRIPTPUBKEY_TEMPLATE_WITNESS_V0 ):
1705
+ pass
1706
+ else :
1707
+ raise Exception (f'scriptpubkey in received shutdown message does not conform to any template: { their_scriptpubkey .hex ()} ' )
1708
+
1700
1709
chan_id = chan .channel_id
1701
1710
if chan_id in self .shutdown_received :
1702
1711
self .shutdown_received [chan_id ].set_result (payload )
@@ -1753,9 +1762,9 @@ async def _shutdown(self, chan: Channel, payload, *, is_local: bool):
1753
1762
# BOLT2: The sending node MUST set fee less than or equal to the base fee of the final ctx
1754
1763
max_fee = chan .get_latest_fee (LOCAL if is_local else REMOTE )
1755
1764
our_fee = min (our_fee , max_fee )
1756
- drop_remote = False
1765
+ drop_to_remote = False
1757
1766
def send_closing_signed ():
1758
- our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = our_fee , drop_remote = drop_remote )
1767
+ our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = our_fee , drop_remote = drop_to_remote )
1759
1768
self .send_message ('closing_signed' , channel_id = chan .channel_id , fee_satoshis = our_fee , signature = our_sig )
1760
1769
def verify_signature (tx , sig ):
1761
1770
their_pubkey = chan .config [REMOTE ].multisig_key .pubkey
@@ -1776,13 +1785,22 @@ def verify_signature(tx, sig):
1776
1785
# verify their sig: they might have dropped their output
1777
1786
our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = their_fee , drop_remote = False )
1778
1787
if verify_signature (closing_tx , their_sig ):
1779
- drop_remote = False
1788
+ drop_to_remote = False
1780
1789
else :
1781
1790
our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = their_fee , drop_remote = True )
1782
1791
if verify_signature (closing_tx , their_sig ):
1783
- drop_remote = True
1792
+ drop_to_remote = True
1784
1793
else :
1794
+ # this can happen if we consider our output too valuable to drop,
1795
+ # but the remote drops it because it violates their dust limit
1785
1796
raise Exception ('failed to verify their signature' )
1797
+ # at this point we know how the closing tx looks like
1798
+ # check that their output is above their scriptpubkey's network dust limit
1799
+ if not drop_to_remote :
1800
+ to_remote_idx = closing_tx .get_output_idxs_from_scriptpubkey (their_scriptpubkey .hex ()).pop ()
1801
+ to_remote_amount = closing_tx .outputs ()[to_remote_idx ].value
1802
+ transaction .check_scriptpubkey_template_and_dust (their_scriptpubkey , to_remote_amount )
1803
+
1786
1804
# Agree if difference is lower or equal to one (see below)
1787
1805
if abs (our_fee - their_fee ) < 2 :
1788
1806
our_fee = their_fee
0 commit comments