URI: 
       tlnbase: more type annotations, and minor fix - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit ce2b572fa5a97a4686e92d9eaca7c3a95ece02ec
   DIR parent 449ec013fec4944a8906cb396f75f319515f00e9
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 25 Oct 2018 19:53:31 +0200
       
       lnbase: more type annotations, and minor fix
       
       Diffstat:
         M electrum/lnbase.py                  |     130 ++++++++++++++++----------------
         M electrum/lnchan.py                  |       3 ++-
       
       2 files changed, 67 insertions(+), 66 deletions(-)
       ---
   DIR diff --git a/electrum/lnbase.py b/electrum/lnbase.py
       t@@ -10,7 +10,7 @@ import asyncio
        import os
        import time
        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 sys
        
       t@@ -40,7 +40,7 @@ if TYPE_CHECKING:
            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]
            i = int.from_bytes(funding_txid_bytes, 'big') ^ funding_index
            return i.to_bytes(32, 'big'), funding_txid_bytes
       t@@ -48,7 +48,7 @@ def channel_id_from_funding_tx(funding_txid, funding_index):
        
        message_types = {}
        
       -def handlesingle(x, ma):
       +def handlesingle(x, ma: dict) -> int:
            """
            Evaluate a term of the simple language used
            to specify lightning message field lengths.
       t@@ -57,7 +57,7 @@ def handlesingle(x, ma):
            otherwise it is treated as a variable and
            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.
        
            Returns int
       t@@ -72,7 +72,7 @@ def handlesingle(x, ma):
                x = int.from_bytes(x, byteorder='big')
            return x
        
       -def calcexp(exp, ma):
       +def calcexp(exp, ma: dict) -> int:
            """
            Evaluate simple mathematical expression given
            in `exp` with variables assigned in the dict `ma`
       t@@ -88,7 +88,7 @@ def calcexp(exp, ma):
                return result
            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)
            for message type `k` with specification `v`
       t@@ -100,7 +100,7 @@ def make_handler(k, v):
        
            Returns function taking bytes
            """
       -    def handler(data):
       +    def handler(data: bytes) -> Tuple[str, dict]:
                nonlocal k, v
                ma = {}
                pos = 0
       t@@ -223,7 +223,7 @@ class Peer(PrintError):
                self.attempted_route = {}
                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
                self.print_error("Sending '%s'"%message_name.upper())
                self.transport.send_bytes(gen_msg(message_name, **kwargs))
       t@@ -350,13 +350,10 @@ class Peer(PrintError):
            @log_exceptions
            @handle_disconnect
            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()
        
            async def _main_loop(self):
       +        """This is separate from main_loop for the tests."""
                try:
                    await asyncio.wait_for(self.initialize(), 10)
                except (OSError, asyncio.TimeoutError, HandshakeFailed) as e:
       t@@ -378,7 +375,7 @@ class Peer(PrintError):
                    chan.set_state('DISCONNECTED')
                    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
                channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys()
                keypair_generator = lambda family: generate_keypair(self.lnworker.ln_keystore, family, channel_counter)
       t@@ -406,7 +403,8 @@ class Peer(PrintError):
                return local_config, per_commitment_secret_seed
        
            @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
                # 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)],
       t@@ -478,7 +476,7 @@ class Peer(PrintError):
                funding_index = funding_tx.outputs().index(funding_output)
                # remote commitment transaction
                channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_index)
       -        chan = {
       +        chan_dict = {
                        "node_id": self.peer_addr.pubkey,
                        "channel_id": channel_id,
                        "short_channel_id": None,
       t@@ -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),
                        "remote_commitment_to_be_revoked": None,
                }
       -        m = Channel(chan)
       -        m.lnwatcher = self.lnwatcher
       -        m.sweep_address = self.lnworker.sweep_address
       -        sig_64, _ = m.sign_next_commitment()
       +        chan = Channel(chan_dict)
       +        chan.lnwatcher = self.lnwatcher
       +        chan.sweep_address = self.lnworker.sweep_address
       +        sig_64, _ = chan.sign_next_commitment()
                self.send_message("funding_created",
                    temporary_channel_id=temp_channel_id,
                    funding_txid=funding_txid_bytes,
       t@@ -507,14 +505,14 @@ class Peer(PrintError):
                payload = await self.funding_signed[channel_id].get()
                self.print_error('received funding_signed')
                remote_sig = payload['signature']
       -        m.receive_new_commitment(remote_sig, [])
       +        chan.receive_new_commitment(remote_sig, [])
                # broadcast funding tx
                await self.network.broadcast_transaction(funding_tx)
       -        m.remote_commitment_to_be_revoked = m.pending_remote_commitment
       -        m.config[REMOTE] = m.config[REMOTE]._replace(ctn=0)
       -        m.config[LOCAL] = m.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
       -        m.set_state('OPENING')
       -        return m
       +        chan.remote_commitment_to_be_revoked = chan.pending_remote_commitment
       +        chan.config[REMOTE] = chan.config[REMOTE]._replace(ctn=0)
       +        chan.config[LOCAL] = chan.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
       +        chan.set_state('OPENING')
       +        return chan
        
            async def on_open_channel(self, payload):
                # payload['channel_flags']
       t@@ -555,8 +553,9 @@ class Peer(PrintError):
                channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_idx)
                their_revocation_store = RevocationStore()
                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)
       -        chan = {
       +        chan_dict = {
                        "node_id": self.peer_addr.pubkey,
                        "channel_id": channel_id,
                        "short_channel_id": None,
       t@@ -568,7 +567,7 @@ class Peer(PrintError):
                            delayed_basepoint=OnlyPubkeyKeypair(payload['delayed_payment_basepoint']),
                            revocation_basepoint=OnlyPubkeyKeypair(payload['revocation_basepoint']),
                            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_accepted_htlcs=int.from_bytes(payload['max_accepted_htlcs'], 'big'),
                            initial_msat=remote_balance_sat,
       t@@ -592,22 +591,22 @@ class Peer(PrintError):
                        "constraints": ChannelConstraints(capacity=funding_sat, is_initiator=False, funding_txn_minimum_depth=min_depth, feerate=feerate),
                        "remote_commitment_to_be_revoked": None,
                }
       -        m = Channel(chan)
       -        m.lnwatcher = self.lnwatcher
       -        m.sweep_address = self.lnworker.sweep_address
       +        chan = Channel(chan_dict)
       +        chan.lnwatcher = self.lnwatcher
       +        chan.sweep_address = self.lnworker.sweep_address
                remote_sig = funding_created['signature']
       -        m.receive_new_commitment(remote_sig, [])
       -        sig_64, _ = m.sign_next_commitment()
       +        chan.receive_new_commitment(remote_sig, [])
       +        sig_64, _ = chan.sign_next_commitment()
                self.send_message('funding_signed',
                    channel_id=channel_id,
                    signature=sig_64,
                )
       -        m.set_state('OPENING')
       -        m.remote_commitment_to_be_revoked = m.pending_remote_commitment
       -        m.config[REMOTE] = m.config[REMOTE]._replace(ctn=0)
       -        m.config[LOCAL] = m.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
       -        self.lnworker.save_channel(m)
       -        self.lnwatcher.watch_channel(m.get_funding_address(), m.funding_outpoint.to_str())
       +        chan.set_state('OPENING')
       +        chan.remote_commitment_to_be_revoked = chan.pending_remote_commitment
       +        chan.config[REMOTE] = chan.config[REMOTE]._replace(ctn=0)
       +        chan.config[LOCAL] = chan.config[LOCAL]._replace(ctn=0, current_commitment_signature=remote_sig)
       +        self.lnworker.save_channel(chan)
       +        self.lnwatcher.watch_channel(chan.get_funding_address(), chan.funding_outpoint.to_str())
                self.lnworker.on_channels_updated()
                while True:
                    try:
       t@@ -618,13 +617,13 @@ class Peer(PrintError):
                    else:
                        break
                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)
                if outp != TxOutput(bitcoin.TYPE_ADDRESS, funding_address, funding_sat):
       -            m.set_state('DISCONNECTED')
       +            chan.set_state('DISCONNECTED')
                    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')
                if remote_reserve_sat < dust_limit:
                    raise Exception('protocol violation: reserve < dust_limit')
       t@@ -633,7 +632,7 @@ class Peer(PrintError):
                return remote_reserve_sat
        
            @log_exceptions
       -    async def reestablish_channel(self, chan):
       +    async def reestablish_channel(self, chan: Channel):
                await self.initialized
                chan_id = chan.channel_id
                if chan.get_state() != 'DISCONNECTED':
       t@@ -712,7 +711,7 @@ class Peer(PrintError):
                # checks done
                self.channel_reestablished[chan_id].set_result(True)
        
       -    def funding_locked(self, chan):
       +    def funding_locked(self, chan: Channel):
                channel_id = chan.channel_id
                per_commitment_secret_index = RevocationStore.START_INDEX - 1
                per_commitment_point_second = secret_to_pubkey(int.from_bytes(
       t@@ -739,7 +738,7 @@ class Peer(PrintError):
                if chan.short_channel_id:
                    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.
        
       t@@ -794,7 +793,7 @@ class Peer(PrintError):
        
                print("SENT CHANNEL ANNOUNCEMENT")
        
       -    def mark_open(self, chan):
       +    def mark_open(self, chan: Channel):
                if chan.get_state() == "OPEN":
                    return
                # NOTE: even closed channels will be temporarily marked "OPEN"
       t@@ -841,13 +840,13 @@ class Peer(PrintError):
        
                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,
                                chan.config[LOCAL].multisig_key.pubkey]
        
                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
                    bitcoin_keys.reverse()
                else:
       t@@ -944,12 +943,12 @@ class Peer(PrintError):
                    else:
                        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()
                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)
        
       -    async def update_channel(self, chan, message_name, **kwargs):
       +    async def update_channel(self, chan: Channel, message_name: str, **kwargs):
                """ generic channel update flow """
                self.send_message(message_name, **kwargs)
                self.send_commitment(chan)
       t@@ -957,7 +956,8 @@ class Peer(PrintError):
                await self.receive_commitment(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 amount_msat > 0, "amount_msat is not greater zero"
                # create onion packet
       t@@ -974,25 +974,25 @@ class Peer(PrintError):
                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())
        
       -    async def receive_revoke(self, m):
       -        revoke_and_ack_msg = await self.revoke_and_ack[m.channel_id].get()
       -        m.receive_revocation(RevokeAndAck(revoke_and_ack_msg["per_commitment_secret"], revoke_and_ack_msg["next_per_commitment_point"]))
       -        self.lnworker.save_channel(m)
       +    async def receive_revoke(self, chan: Channel):
       +        revoke_and_ack_msg = await self.revoke_and_ack[chan.channel_id].get()
       +        chan.receive_revocation(RevokeAndAck(revoke_and_ack_msg["per_commitment_secret"], revoke_and_ack_msg["next_per_commitment_point"]))
       +        self.lnworker.save_channel(chan)
        
       -    def revoke(self, m):
       -        rev, _ = m.revoke_current_commitment()
       -        self.lnworker.save_channel(m)
       +    def revoke(self, chan: Channel):
       +        rev, _ = chan.revoke_current_commitment()
       +        self.lnworker.save_channel(chan)
                self.send_message("revoke_and_ack",
       -            channel_id=m.channel_id,
       +            channel_id=chan.channel_id,
                    per_commitment_secret=rev.per_commitment_secret,
                    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:
       -            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"]
                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)
        
            def on_commitment_signed(self, payload):
       t@@ -1109,7 +1109,7 @@ class Peer(PrintError):
                channel_id = payload["channel_id"]
                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
                """
       t@@ -1144,7 +1144,7 @@ class Peer(PrintError):
                self.closing_signed[chan_id].put_nowait(payload)
        
            @log_exceptions
       -    async def close_channel(self, chan_id):
       +    async def close_channel(self, chan_id: bytes):
                chan = self.channels[chan_id]
                self.shutdown_received[chan_id] = asyncio.Future()
                self.send_shutdown(chan)
       t@@ -1167,12 +1167,12 @@ class Peer(PrintError):
                    txid = await self._shutdown(chan, payload)
                    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))
                self.send_message('shutdown', channel_id=chan.channel_id, len=len(scriptpubkey), scriptpubkey=scriptpubkey)
        
            @log_exceptions
       -    async def _shutdown(self, chan, payload):
       +    async def _shutdown(self, chan: Channel, payload):
                scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address))
                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)
   DIR diff --git a/electrum/lnchan.py b/electrum/lnchan.py
       t@@ -781,7 +781,8 @@ class Channel(PrintError):
                    ),
                    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:
                    fee_sat = self.pending_local_fee