Browse Source

lnbase: more type annotations, and minor fix

dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
SomberNight 6 years ago
committed by ThomasV
parent
commit
ce2b572fa5
  1. 130
      electrum/lnbase.py
  2. 3
      electrum/lnchan.py

130
electrum/lnbase.py

@ -10,7 +10,7 @@ import asyncio
import os import os
import time import time
from functools import partial from functools import partial
from typing import List, Tuple, Dict, TYPE_CHECKING from typing import List, Tuple, Dict, TYPE_CHECKING, Optional, Callable
import traceback import traceback
import sys import sys
@ -40,7 +40,7 @@ if TYPE_CHECKING:
from .lnworker import LNWorker from .lnworker import LNWorker
def channel_id_from_funding_tx(funding_txid, funding_index): def channel_id_from_funding_tx(funding_txid: str, funding_index: int) -> Tuple[bytes, bytes]:
funding_txid_bytes = bytes.fromhex(funding_txid)[::-1] funding_txid_bytes = bytes.fromhex(funding_txid)[::-1]
i = int.from_bytes(funding_txid_bytes, 'big') ^ funding_index i = int.from_bytes(funding_txid_bytes, 'big') ^ funding_index
return i.to_bytes(32, 'big'), funding_txid_bytes return i.to_bytes(32, 'big'), funding_txid_bytes
@ -48,7 +48,7 @@ def channel_id_from_funding_tx(funding_txid, funding_index):
message_types = {} message_types = {}
def handlesingle(x, ma): def handlesingle(x, ma: dict) -> int:
""" """
Evaluate a term of the simple language used Evaluate a term of the simple language used
to specify lightning message field lengths. to specify lightning message field lengths.
@ -57,7 +57,7 @@ def handlesingle(x, ma):
otherwise it is treated as a variable and otherwise it is treated as a variable and
looked up in `ma`. looked up in `ma`.
It the value in `ma` was no integer, it is If the value in `ma` was no integer, it is
assumed big-endian bytes and decoded. assumed big-endian bytes and decoded.
Returns int Returns int
@ -72,7 +72,7 @@ def handlesingle(x, ma):
x = int.from_bytes(x, byteorder='big') x = int.from_bytes(x, byteorder='big')
return x return x
def calcexp(exp, ma): def calcexp(exp, ma: dict) -> int:
""" """
Evaluate simple mathematical expression given Evaluate simple mathematical expression given
in `exp` with variables assigned in the dict `ma` in `exp` with variables assigned in the dict `ma`
@ -88,7 +88,7 @@ def calcexp(exp, ma):
return result return result
return sum(handlesingle(x, ma) for x in exp.split("+")) return sum(handlesingle(x, ma) for x in exp.split("+"))
def make_handler(k, v): def make_handler(k: str, v: dict) -> Callable[[bytes], Tuple[str, dict]]:
""" """
Generate a message handler function (taking bytes) Generate a message handler function (taking bytes)
for message type `k` with specification `v` for message type `k` with specification `v`
@ -100,7 +100,7 @@ def make_handler(k, v):
Returns function taking bytes Returns function taking bytes
""" """
def handler(data): def handler(data: bytes) -> Tuple[str, dict]:
nonlocal k, v nonlocal k, v
ma = {} ma = {}
pos = 0 pos = 0
@ -223,7 +223,7 @@ class Peer(PrintError):
self.attempted_route = {} self.attempted_route = {}
self.orphan_channel_updates = OrderedDict() self.orphan_channel_updates = OrderedDict()
def send_message(self, message_name, **kwargs): def send_message(self, message_name: str, **kwargs):
assert type(message_name) is str assert type(message_name) is str
self.print_error("Sending '%s'"%message_name.upper()) self.print_error("Sending '%s'"%message_name.upper())
self.transport.send_bytes(gen_msg(message_name, **kwargs)) self.transport.send_bytes(gen_msg(message_name, **kwargs))
@ -350,13 +350,10 @@ class Peer(PrintError):
@log_exceptions @log_exceptions
@handle_disconnect @handle_disconnect
async def main_loop(self): async def main_loop(self):
"""
This is used from the GUI. It is not merged with the other function,
so that we can test if the correct exceptions are getting thrown.
"""
await self._main_loop() await self._main_loop()
async def _main_loop(self): async def _main_loop(self):
"""This is separate from main_loop for the tests."""
try: try:
await asyncio.wait_for(self.initialize(), 10) await asyncio.wait_for(self.initialize(), 10)
except (OSError, asyncio.TimeoutError, HandshakeFailed) as e: except (OSError, asyncio.TimeoutError, HandshakeFailed) as e:
@ -378,7 +375,7 @@ class Peer(PrintError):
chan.set_state('DISCONNECTED') chan.set_state('DISCONNECTED')
self.network.trigger_callback('channel', chan) self.network.trigger_callback('channel', chan)
def make_local_config(self, funding_sat, push_msat, initiator: HTLCOwner): def make_local_config(self, funding_sat: int, push_msat: int, initiator: HTLCOwner) -> Tuple[ChannelConfig, bytes]:
# key derivation # key derivation
channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys() channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys()
keypair_generator = lambda family: generate_keypair(self.lnworker.ln_keystore, family, channel_counter) keypair_generator = lambda family: generate_keypair(self.lnworker.ln_keystore, family, channel_counter)
@ -406,7 +403,8 @@ class Peer(PrintError):
return local_config, per_commitment_secret_seed return local_config, per_commitment_secret_seed
@log_exceptions @log_exceptions
async def channel_establishment_flow(self, password, funding_sat, push_msat, temp_channel_id): async def channel_establishment_flow(self, password: Optional[str], funding_sat: int,
push_msat: int, temp_channel_id: bytes) -> Channel:
wallet = self.lnworker.wallet wallet = self.lnworker.wallet
# dry run creating funding tx to see if we even have enough funds # dry run creating funding tx to see if we even have enough funds
funding_tx_test = wallet.mktx([TxOutput(bitcoin.TYPE_ADDRESS, wallet.dummy_address(), funding_sat)], funding_tx_test = wallet.mktx([TxOutput(bitcoin.TYPE_ADDRESS, wallet.dummy_address(), funding_sat)],
@ -478,7 +476,7 @@ class Peer(PrintError):
funding_index = funding_tx.outputs().index(funding_output) funding_index = funding_tx.outputs().index(funding_output)
# remote commitment transaction # remote commitment transaction
channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_index) channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_index)
chan = { chan_dict = {
"node_id": self.peer_addr.pubkey, "node_id": self.peer_addr.pubkey,
"channel_id": channel_id, "channel_id": channel_id,
"short_channel_id": None, "short_channel_id": None,
@ -495,10 +493,10 @@ class Peer(PrintError):
"constraints": ChannelConstraints(capacity=funding_sat, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth, feerate=feerate), "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth, feerate=feerate),
"remote_commitment_to_be_revoked": None, "remote_commitment_to_be_revoked": None,
} }
m = Channel(chan) chan = Channel(chan_dict)
m.lnwatcher = self.lnwatcher chan.lnwatcher = self.lnwatcher
m.sweep_address = self.lnworker.sweep_address chan.sweep_address = self.lnworker.sweep_address
sig_64, _ = m.sign_next_commitment() sig_64, _ = chan.sign_next_commitment()
self.send_message("funding_created", self.send_message("funding_created",
temporary_channel_id=temp_channel_id, temporary_channel_id=temp_channel_id,
funding_txid=funding_txid_bytes, funding_txid=funding_txid_bytes,
@ -507,14 +505,14 @@ class Peer(PrintError):
payload = await self.funding_signed[channel_id].get() payload = await self.funding_signed[channel_id].get()
self.print_error('received funding_signed') self.print_error('received funding_signed')
remote_sig = payload['signature'] remote_sig = payload['signature']
m.receive_new_commitment(remote_sig, []) chan.receive_new_commitment(remote_sig, [])
# broadcast funding tx # broadcast funding tx
await self.network.broadcast_transaction(funding_tx) await self.network.broadcast_transaction(funding_tx)
m.remote_commitment_to_be_revoked = m.pending_remote_commitment chan.remote_commitment_to_be_revoked = chan.pending_remote_commitment
m.config[REMOTE] = m.config[REMOTE]._replace(ctn=0) chan.config[REMOTE] = chan.config[REMOTE]._replace(ctn=0)
m.config[LOCAL] = m.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig) chan.config[LOCAL] = chan.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
m.set_state('OPENING') chan.set_state('OPENING')
return m return chan
async def on_open_channel(self, payload): async def on_open_channel(self, payload):
# payload['channel_flags'] # payload['channel_flags']
@ -555,8 +553,9 @@ class Peer(PrintError):
channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_idx) channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_idx)
their_revocation_store = RevocationStore() their_revocation_store = RevocationStore()
remote_balance_sat = funding_sat * 1000 - push_msat remote_balance_sat = funding_sat * 1000 - push_msat
remote_dust_limit_sat = int.from_bytes(payload['dust_limit_satoshis'], byteorder='big')
remote_reserve_sat = self.validate_remote_reserve(payload['channel_reserve_satoshis'], remote_dust_limit_sat, funding_sat) remote_reserve_sat = self.validate_remote_reserve(payload['channel_reserve_satoshis'], remote_dust_limit_sat, funding_sat)
chan = { chan_dict = {
"node_id": self.peer_addr.pubkey, "node_id": self.peer_addr.pubkey,
"channel_id": channel_id, "channel_id": channel_id,
"short_channel_id": None, "short_channel_id": None,
@ -568,7 +567,7 @@ class Peer(PrintError):
delayed_basepoint=OnlyPubkeyKeypair(payload['delayed_payment_basepoint']), delayed_basepoint=OnlyPubkeyKeypair(payload['delayed_payment_basepoint']),
revocation_basepoint=OnlyPubkeyKeypair(payload['revocation_basepoint']), revocation_basepoint=OnlyPubkeyKeypair(payload['revocation_basepoint']),
to_self_delay=int.from_bytes(payload['to_self_delay'], 'big'), to_self_delay=int.from_bytes(payload['to_self_delay'], 'big'),
dust_limit_sat=int.from_bytes(payload['dust_limit_satoshis'], 'big'), dust_limit_sat=remote_dust_limit_sat,
max_htlc_value_in_flight_msat=int.from_bytes(payload['max_htlc_value_in_flight_msat'], 'big'), max_htlc_value_in_flight_msat=int.from_bytes(payload['max_htlc_value_in_flight_msat'], 'big'),
max_accepted_htlcs=int.from_bytes(payload['max_accepted_htlcs'], 'big'), max_accepted_htlcs=int.from_bytes(payload['max_accepted_htlcs'], 'big'),
initial_msat=remote_balance_sat, initial_msat=remote_balance_sat,
@ -592,22 +591,22 @@ class Peer(PrintError):
"constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth, feerate=feerate), "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth, feerate=feerate),
"remote_commitment_to_be_revoked": None, "remote_commitment_to_be_revoked": None,
} }
m = Channel(chan) chan = Channel(chan_dict)
m.lnwatcher = self.lnwatcher chan.lnwatcher = self.lnwatcher
m.sweep_address = self.lnworker.sweep_address chan.sweep_address = self.lnworker.sweep_address
remote_sig = funding_created['signature'] remote_sig = funding_created['signature']
m.receive_new_commitment(remote_sig, []) chan.receive_new_commitment(remote_sig, [])
sig_64, _ = m.sign_next_commitment() sig_64, _ = chan.sign_next_commitment()
self.send_message('funding_signed', self.send_message('funding_signed',
channel_id=channel_id, channel_id=channel_id,
signature=sig_64, signature=sig_64,
) )
m.set_state('OPENING') chan.set_state('OPENING')
m.remote_commitment_to_be_revoked = m.pending_remote_commitment chan.remote_commitment_to_be_revoked = chan.pending_remote_commitment
m.config[REMOTE] = m.config[REMOTE]._replace(ctn=0) chan.config[REMOTE] = chan.config[REMOTE]._replace(ctn=0)
m.config[LOCAL] = m.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig) chan.config[LOCAL] = chan.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
self.lnworker.save_channel(m) self.lnworker.save_channel(chan)
self.lnwatcher.watch_channel(m.get_funding_address(), m.funding_outpoint.to_str()) self.lnwatcher.watch_channel(chan.get_funding_address(), chan.funding_outpoint.to_str())
self.lnworker.on_channels_updated() self.lnworker.on_channels_updated()
while True: while True:
try: try:
@ -618,13 +617,13 @@ class Peer(PrintError):
else: else:
break break
outp = funding_tx.outputs()[funding_idx] outp = funding_tx.outputs()[funding_idx]
redeem_script = funding_output_script(m.config[REMOTE], m.config[LOCAL]) redeem_script = funding_output_script(chan.config[REMOTE], chan.config[LOCAL])
funding_address = bitcoin.redeem_script_to_address('p2wsh', redeem_script) funding_address = bitcoin.redeem_script_to_address('p2wsh', redeem_script)
if outp != TxOutput(bitcoin.TYPE_ADDRESS, funding_address, funding_sat): if outp != TxOutput(bitcoin.TYPE_ADDRESS, funding_address, funding_sat):
m.set_state('DISCONNECTED') chan.set_state('DISCONNECTED')
raise Exception('funding outpoint mismatch') raise Exception('funding outpoint mismatch')
def validate_remote_reserve(self, payload_field, dust_limit, funding_sat): def validate_remote_reserve(self, payload_field: bytes, dust_limit: int, funding_sat: int) -> int:
remote_reserve_sat = int.from_bytes(payload_field, 'big') remote_reserve_sat = int.from_bytes(payload_field, 'big')
if remote_reserve_sat < dust_limit: if remote_reserve_sat < dust_limit:
raise Exception('protocol violation: reserve < dust_limit') raise Exception('protocol violation: reserve < dust_limit')
@ -633,7 +632,7 @@ class Peer(PrintError):
return remote_reserve_sat return remote_reserve_sat
@log_exceptions @log_exceptions
async def reestablish_channel(self, chan): async def reestablish_channel(self, chan: Channel):
await self.initialized await self.initialized
chan_id = chan.channel_id chan_id = chan.channel_id
if chan.get_state() != 'DISCONNECTED': if chan.get_state() != 'DISCONNECTED':
@ -712,7 +711,7 @@ class Peer(PrintError):
# checks done # checks done
self.channel_reestablished[chan_id].set_result(True) self.channel_reestablished[chan_id].set_result(True)
def funding_locked(self, chan): def funding_locked(self, chan: Channel):
channel_id = chan.channel_id channel_id = chan.channel_id
per_commitment_secret_index = RevocationStore.START_INDEX - 1 per_commitment_secret_index = RevocationStore.START_INDEX - 1
per_commitment_point_second = secret_to_pubkey(int.from_bytes( per_commitment_point_second = secret_to_pubkey(int.from_bytes(
@ -739,7 +738,7 @@ class Peer(PrintError):
if chan.short_channel_id: if chan.short_channel_id:
self.mark_open(chan) self.mark_open(chan)
def on_network_update(self, chan, funding_tx_depth): def on_network_update(self, chan: Channel, funding_tx_depth: int):
""" """
Only called when the channel is OPEN. Only called when the channel is OPEN.
@ -794,7 +793,7 @@ class Peer(PrintError):
print("SENT CHANNEL ANNOUNCEMENT") print("SENT CHANNEL ANNOUNCEMENT")
def mark_open(self, chan): def mark_open(self, chan: Channel):
if chan.get_state() == "OPEN": if chan.get_state() == "OPEN":
return return
# NOTE: even closed channels will be temporarily marked "OPEN" # NOTE: even closed channels will be temporarily marked "OPEN"
@ -841,13 +840,13 @@ class Peer(PrintError):
self.print_error("CHANNEL OPENING COMPLETED") self.print_error("CHANNEL OPENING COMPLETED")
def send_announcement_signatures(self, chan): def send_announcement_signatures(self, chan: Channel):
bitcoin_keys = [chan.config[REMOTE].multisig_key.pubkey, bitcoin_keys = [chan.config[REMOTE].multisig_key.pubkey,
chan.config[LOCAL].multisig_key.pubkey] chan.config[LOCAL].multisig_key.pubkey]
sorted_node_ids = list(sorted(self.node_ids)) sorted_node_ids = list(sorted(self.node_ids))
if sorted_node_ids != node_ids: if sorted_node_ids != self.node_ids:
node_ids = sorted_node_ids node_ids = sorted_node_ids
bitcoin_keys.reverse() bitcoin_keys.reverse()
else: else:
@ -944,12 +943,12 @@ class Peer(PrintError):
else: else:
self.network.path_finder.blacklist.add(short_chan_id) self.network.path_finder.blacklist.add(short_chan_id)
def send_commitment(self, chan): def send_commitment(self, chan: Channel):
sig_64, htlc_sigs = chan.sign_next_commitment() sig_64, htlc_sigs = chan.sign_next_commitment()
self.send_message("commitment_signed", channel_id=chan.channel_id, signature=sig_64, num_htlcs=len(htlc_sigs), htlc_signature=b"".join(htlc_sigs)) self.send_message("commitment_signed", channel_id=chan.channel_id, signature=sig_64, num_htlcs=len(htlc_sigs), htlc_signature=b"".join(htlc_sigs))
return len(htlc_sigs) return len(htlc_sigs)
async def update_channel(self, chan, message_name, **kwargs): async def update_channel(self, chan: Channel, message_name: str, **kwargs):
""" generic channel update flow """ """ generic channel update flow """
self.send_message(message_name, **kwargs) self.send_message(message_name, **kwargs)
self.send_commitment(chan) self.send_commitment(chan)
@ -957,7 +956,8 @@ class Peer(PrintError):
await self.receive_commitment(chan) await self.receive_commitment(chan)
self.revoke(chan) self.revoke(chan)
async def pay(self, route: List[RouteEdge], chan, amount_msat, payment_hash, min_final_cltv_expiry): async def pay(self, route: List[RouteEdge], chan: Channel, amount_msat: int,
payment_hash: bytes, min_final_cltv_expiry: int):
assert chan.get_state() == "OPEN", chan.get_state() assert chan.get_state() == "OPEN", chan.get_state()
assert amount_msat > 0, "amount_msat is not greater zero" assert amount_msat > 0, "amount_msat is not greater zero"
# create onion packet # create onion packet
@ -974,25 +974,25 @@ class Peer(PrintError):
self.print_error(f"starting payment. route: {route}") self.print_error(f"starting payment. route: {route}")
await self.update_channel(chan, "update_add_htlc", channel_id=chan.channel_id, id=htlc_id, cltv_expiry=cltv, amount_msat=amount_msat, payment_hash=payment_hash, onion_routing_packet=onion.to_bytes()) await self.update_channel(chan, "update_add_htlc", channel_id=chan.channel_id, id=htlc_id, cltv_expiry=cltv, amount_msat=amount_msat, payment_hash=payment_hash, onion_routing_packet=onion.to_bytes())
async def receive_revoke(self, m): async def receive_revoke(self, chan: Channel):
revoke_and_ack_msg = await self.revoke_and_ack[m.channel_id].get() revoke_and_ack_msg = await self.revoke_and_ack[chan.channel_id].get()
m.receive_revocation(RevokeAndAck(revoke_and_ack_msg["per_commitment_secret"], revoke_and_ack_msg["next_per_commitment_point"])) chan.receive_revocation(RevokeAndAck(revoke_and_ack_msg["per_commitment_secret"], revoke_and_ack_msg["next_per_commitment_point"]))
self.lnworker.save_channel(m) self.lnworker.save_channel(chan)
def revoke(self, m): def revoke(self, chan: Channel):
rev, _ = m.revoke_current_commitment() rev, _ = chan.revoke_current_commitment()
self.lnworker.save_channel(m) self.lnworker.save_channel(chan)
self.send_message("revoke_and_ack", self.send_message("revoke_and_ack",
channel_id=m.channel_id, channel_id=chan.channel_id,
per_commitment_secret=rev.per_commitment_secret, per_commitment_secret=rev.per_commitment_secret,
next_per_commitment_point=rev.next_per_commitment_point) next_per_commitment_point=rev.next_per_commitment_point)
async def receive_commitment(self, m, commitment_signed_msg=None): async def receive_commitment(self, chan: Channel, commitment_signed_msg=None):
if commitment_signed_msg is None: if commitment_signed_msg is None:
commitment_signed_msg = await self.commitment_signed[m.channel_id].get() commitment_signed_msg = await self.commitment_signed[chan.channel_id].get()
data = commitment_signed_msg["htlc_signature"] data = commitment_signed_msg["htlc_signature"]
htlc_sigs = [data[i:i+64] for i in range(0, len(data), 64)] htlc_sigs = [data[i:i+64] for i in range(0, len(data), 64)]
m.receive_new_commitment(commitment_signed_msg["signature"], htlc_sigs) chan.receive_new_commitment(commitment_signed_msg["signature"], htlc_sigs)
return len(htlc_sigs) return len(htlc_sigs)
def on_commitment_signed(self, payload): def on_commitment_signed(self, payload):
@ -1109,7 +1109,7 @@ class Peer(PrintError):
channel_id = payload["channel_id"] channel_id = payload["channel_id"]
self.channels[channel_id].receive_update_fee(int.from_bytes(payload["feerate_per_kw"], "big")) self.channels[channel_id].receive_update_fee(int.from_bytes(payload["feerate_per_kw"], "big"))
async def bitcoin_fee_update(self, chan): async def bitcoin_fee_update(self, chan: Channel):
""" """
called when our fee estimates change called when our fee estimates change
""" """
@ -1144,7 +1144,7 @@ class Peer(PrintError):
self.closing_signed[chan_id].put_nowait(payload) self.closing_signed[chan_id].put_nowait(payload)
@log_exceptions @log_exceptions
async def close_channel(self, chan_id): async def close_channel(self, chan_id: bytes):
chan = self.channels[chan_id] chan = self.channels[chan_id]
self.shutdown_received[chan_id] = asyncio.Future() self.shutdown_received[chan_id] = asyncio.Future()
self.send_shutdown(chan) self.send_shutdown(chan)
@ -1167,12 +1167,12 @@ class Peer(PrintError):
txid = await self._shutdown(chan, payload) txid = await self._shutdown(chan, payload)
self.print_error('Channel closed by remote peer', txid) self.print_error('Channel closed by remote peer', txid)
def send_shutdown(self, chan): def send_shutdown(self, chan: Channel):
scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address)) scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address))
self.send_message('shutdown', channel_id=chan.channel_id, len=len(scriptpubkey), scriptpubkey=scriptpubkey) self.send_message('shutdown', channel_id=chan.channel_id, len=len(scriptpubkey), scriptpubkey=scriptpubkey)
@log_exceptions @log_exceptions
async def _shutdown(self, chan, payload): async def _shutdown(self, chan: Channel, payload):
scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address)) scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address))
signature, fee, txid = chan.make_closing_tx(scriptpubkey, payload['scriptpubkey']) signature, fee, txid = chan.make_closing_tx(scriptpubkey, payload['scriptpubkey'])
self.send_message('closing_signed', channel_id=chan.channel_id, fee_satoshis=fee, signature=signature) self.send_message('closing_signed', channel_id=chan.channel_id, fee_satoshis=fee, signature=signature)

3
electrum/lnchan.py

@ -781,7 +781,8 @@ class Channel(PrintError):
), ),
htlcs=htlcs) htlcs=htlcs)
def make_closing_tx(self, local_script: bytes, remote_script: bytes, fee_sat: Optional[int] = None) -> (bytes, int): def make_closing_tx(self, local_script: bytes, remote_script: bytes,
fee_sat: Optional[int]=None) -> Tuple[bytes, int, str]:
if fee_sat is None: if fee_sat is None:
fee_sat = self.pending_local_fee fee_sat = self.pending_local_fee

Loading…
Cancel
Save