5151from .lnutil import ln_dummy_address
5252from .json_db import StoredDict
5353from .invoices import PR_PAID
54+ from .simple_config import FEE_LN_ETA_TARGET
5455
5556if TYPE_CHECKING :
5657 from .lnworker import LNGossip , LNWallet
@@ -1840,30 +1841,68 @@ async def _shutdown(self, chan: Channel, payload, *, is_local: bool):
18401841 assert our_scriptpubkey
18411842 # estimate fee of closing tx
18421843 our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = 0 )
1843- fee_rate = self .network .config .fee_per_kb ()
1844- our_fee = fee_rate * closing_tx .estimated_size () // 1000
1844+ fee_rate_per_kb = self .network .config .eta_target_to_fee (FEE_LN_ETA_TARGET )
1845+ if not fee_rate_per_kb : # fallback
1846+ fee_rate_per_kb = self .network .config .fee_per_kb ()
1847+ our_fee = fee_rate_per_kb * closing_tx .estimated_size () // 1000
1848+ # TODO: anchors: remove this, as commitment fee rate can be below chain head fee rate?
18451849 # BOLT2: The sending node MUST set fee less than or equal to the base fee of the final ctx
18461850 max_fee = chan .get_latest_fee (LOCAL if is_local else REMOTE )
18471851 our_fee = min (our_fee , max_fee )
1848- drop_to_remote = False
1852+
1853+ drop_to_remote = False # does the peer drop its to_local output or not?
18491854 def send_closing_signed ():
1855+ MODERN_FEE = True
1856+ if MODERN_FEE :
1857+ nonlocal fee_range_sent # we change fee_range_sent in outer scope
1858+ fee_range_sent = fee_range
1859+ closing_signed_tlvs = {'fee_range' : fee_range }
1860+ else :
1861+ closing_signed_tlvs = {}
1862+
18501863 our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = our_fee , drop_remote = drop_to_remote )
1851- self .send_message ('closing_signed' , channel_id = chan .channel_id , fee_satoshis = our_fee , signature = our_sig )
1864+ self .logger .info (f"Sending fee range: { closing_signed_tlvs } and fee: { our_fee } " )
1865+ self .send_message (
1866+ 'closing_signed' ,
1867+ channel_id = chan .channel_id ,
1868+ fee_satoshis = our_fee ,
1869+ signature = our_sig ,
1870+ closing_signed_tlvs = closing_signed_tlvs ,
1871+ )
18521872 def verify_signature (tx , sig ):
18531873 their_pubkey = chan .config [REMOTE ].multisig_key .pubkey
18541874 preimage_hex = tx .serialize_preimage (0 )
18551875 pre_hash = sha256d (bfh (preimage_hex ))
18561876 return ecc .verify_signature (their_pubkey , sig , pre_hash )
1877+
1878+ # this is the fee range we initially try to enforce
1879+ # we aim at a fee between next block inclusion and some lower value
1880+ fee_range = {'min_fee_satoshis' : our_fee // 2 , 'max_fee_satoshis' : our_fee * 2 }
1881+ their_fee = None
1882+ fee_range_sent = {}
1883+ is_initiator = chan .constraints .is_initiator
18571884 # the funder sends the first 'closing_signed' message
1858- if chan . constraints . is_initiator :
1885+ if is_initiator :
18591886 send_closing_signed ()
1887+
18601888 # negotiate fee
18611889 while True :
1862- # FIXME: the remote SHOULD send closing_signed, but some don't.
1863- cs_payload = await self .wait_for_message ('closing_signed' , chan .channel_id )
1890+ try :
1891+ cs_payload = await self .wait_for_message ('closing_signed' , chan .channel_id )
1892+ except asyncio .exceptions .TimeoutError :
1893+ if not is_initiator and not their_fee : # we only force close if a peer doesn't reply
1894+ self .lnworker .schedule_force_closing (chan .channel_id )
1895+ raise Exception ("Peer didn't reply with closing signed, force closed." )
1896+ else :
1897+ # situation when we as an initiator send a fee and the recipient
1898+ # already agrees with that fee, but doens't tell us
1899+ raise Exception ("Peer didn't reply, probably already closed." )
1900+
1901+ their_previous_fee = their_fee
18641902 their_fee = cs_payload ['fee_satoshis' ]
1865- if their_fee > max_fee :
1866- raise Exception (f'the proposed fee exceeds the base fee of the latest commitment transaction { is_local , their_fee , max_fee } ' )
1903+
1904+ # 0. integrity checks
1905+ # determine their closing transaction
18671906 their_sig = cs_payload ['signature' ]
18681907 # verify their sig: they might have dropped their output
18691908 our_sig , closing_tx = chan .make_closing_tx (our_scriptpubkey , their_scriptpubkey , fee_sat = their_fee , drop_remote = False )
@@ -1885,17 +1924,98 @@ def verify_signature(tx, sig):
18851924 to_remote_amount = closing_tx .outputs ()[to_remote_idx ].value
18861925 transaction .check_scriptpubkey_template_and_dust (their_scriptpubkey , to_remote_amount )
18871926
1888- # Agree if difference is lower or equal to one (see below)
1889- if abs (our_fee - their_fee ) < 2 :
1927+ # 1. check fees
1928+ # if fee_satoshis is equal to its previously sent fee_satoshis:
1929+ if our_fee == their_fee :
1930+ # SHOULD sign and broadcast the final closing transaction.
1931+ break # we publish
1932+
1933+ # 2. at start, adapt our fee range if we are not the channel initiator
1934+ fee_range_received = cs_payload ['closing_signed_tlvs' ].get ('fee_range' )
1935+ self .logger .info (f"Received fee range: { fee_range_received } and fee: { their_fee } " )
1936+ # The sending node: if it is not the funder:
1937+ if fee_range_received and not is_initiator and not fee_range_sent :
1938+ # SHOULD set max_fee_satoshis to at least the max_fee_satoshis received
1939+ fee_range ['max_fee_satoshis' ] = max (fee_range_received ['max_fee_satoshis' ], fee_range ['max_fee_satoshis' ])
1940+ # SHOULD set min_fee_satoshis to a fairly low value
1941+ # TODO: what's fairly low value? allows the initiator to go to low values
1942+ fee_range ['min_fee_satoshis' ] = fee_range ['max_fee_satoshis' ] // 2
1943+
1944+ # 3. if fee_satoshis matches its previously sent fee_range:
1945+ if fee_range_sent and (fee_range_sent ['min_fee_satoshis' ] <= their_fee <= fee_range_sent ['max_fee_satoshis' ]):
1946+ # SHOULD reply with a closing_signed with the same fee_satoshis value if it is different from its previously sent fee_satoshis
1947+ if our_fee != their_fee :
1948+ our_fee = their_fee
1949+ send_closing_signed () # peer publishes
1950+ break
1951+ # SHOULD use `fee_satoshis` to sign and broadcast the final closing transaction
1952+ else :
1953+ our_fee = their_fee
1954+ break # we publish
1955+
1956+ # 4. if the message contains a fee_range
1957+ if fee_range_received :
1958+ overlap_min = max (fee_range ['min_fee_satoshis' ], fee_range_received ['min_fee_satoshis' ])
1959+ overlap_max = min (fee_range ['max_fee_satoshis' ], fee_range_received ['max_fee_satoshis' ])
1960+ # if there is no overlap between that and its own fee_range
1961+ if overlap_min > overlap_max :
1962+ raise Exception ("There is no overlap between between their and our fee range." )
1963+ # TODO: MUST fail the channel if it doesn't receive a satisfying fee_range after a reasonable amount of time
1964+ # otherwise:
1965+ else :
1966+ if is_initiator :
1967+ # if fee_satoshis is not in the overlap between the sent and received fee_range:
1968+ if not (overlap_min <= their_fee <= overlap_max ):
1969+ # MUST fail the channel
1970+ self .lnworker .schedule_force_closing (chan .channel_id )
1971+ raise Exception ("Their fee is not in the overlap region, we force closed." )
1972+ # otherwise:
1973+ else :
1974+ our_fee = their_fee
1975+ # MUST reply with the same fee_satoshis.
1976+ send_closing_signed () # peer publishes
1977+ break
1978+ # otherwise (it is not the funder):
1979+ else :
1980+ # if it has already sent a closing_signed:
1981+ if fee_range_sent :
1982+ # if fee_satoshis is not the same as the value it sent:
1983+ if their_fee != our_fee :
1984+ # MUST fail the channel
1985+ self .lnworker .schedule_force_closing (chan .channel_id )
1986+ raise Exception ("Expected the same fee as ours, we force closed." )
1987+ # otherwise:
1988+ else :
1989+ # MUST propose a fee_satoshis in the overlap between received and (about-to-be) sent fee_range.
1990+ our_fee = (overlap_min + overlap_max ) // 2
1991+ send_closing_signed ()
1992+ continue
1993+ # otherwise, if fee_satoshis is not strictly between its last-sent fee_satoshis
1994+ # and its previously-received fee_satoshis, UNLESS it has since reconnected:
1995+ elif their_previous_fee and not (min (our_fee , their_previous_fee ) < their_fee < max (our_fee , their_previous_fee )):
1996+ # SHOULD fail the connection.
1997+ raise Exception ('Their fee is not between our last sent and their last sent fee.' )
1998+ # otherwise, if the receiver agrees with the fee:
1999+ elif abs (their_fee - our_fee ) <= 1 : # we cannot have another strictly in-between value
2000+ # SHOULD reply with a closing_signed with the same fee_satoshis value.
18902001 our_fee = their_fee
2002+ send_closing_signed () # peer publishes
18912003 break
1892- # this will be "strictly between" (as in BOLT2) previous values because of the above
1893- our_fee = (our_fee + their_fee ) // 2
1894- # another round
1895- send_closing_signed ()
1896- # the non-funder replies
1897- if not chan .constraints .is_initiator :
2004+ # otherwise:
2005+ else :
2006+ # MUST propose a value "strictly between" the received fee_satoshis and its previously-sent fee_satoshis.
2007+ our_fee_proposed = (our_fee + their_fee ) // 2
2008+ if not (min (our_fee , their_fee ) < our_fee_proposed < max (our_fee , their_fee )):
2009+ our_fee_proposed += (their_fee - our_fee ) // 2
2010+ else :
2011+ our_fee = our_fee_proposed
2012+ send_closing_signed ()
2013+
2014+ # reaching this part of the code means that we have reached agreement; to make
2015+ # sure the peer doesn't force close, send a last closing_signed
2016+ if not is_initiator :
18982017 send_closing_signed ()
2018+
18992019 # add signatures
19002020 closing_tx .add_signature_to_txin (
19012021 txin_idx = 0 ,
0 commit comments