commit ce2b572fa5a97a4686e92d9eaca7c3a95ece02ec
parent 449ec013fec4944a8906cb396f75f319515f00e9
Author: SomberNight <somber.night@protonmail.com>
Date: Thu, 25 Oct 2018 19:53:31 +0200
lnbase: more type annotations, and minor fix
Diffstat:
2 files changed, 67 insertions(+), 66 deletions(-)
diff --git a/electrum/lnbase.py b/electrum/lnbase.py
@@ -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
@@ -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
@@ -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.
@@ -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
@@ -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`
@@ -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`
@@ -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
@@ -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))
@@ -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:
@@ -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)
@@ -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)],
@@ -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,
@@ -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,
@@ -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']
@@ -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,
@@ -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,
@@ -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:
@@ -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')
@@ -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':
@@ -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(
@@ -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.
@@ -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"
@@ -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:
@@ -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)
@@ -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
@@ -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):
@@ -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
"""
@@ -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)
@@ -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)
diff --git a/electrum/lnchan.py b/electrum/lnchan.py
@@ -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