Browse Source

lnchannel: make AbstractChannel inherit ABC

and add some type annotations, clean up method signatures
master
SomberNight 6 years ago
parent
commit
8e8ab775eb
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 148
      electrum/lnchannel.py
  2. 4
      electrum/lnsweep.py
  3. 1
      electrum/lntransport.py
  4. 8
      electrum/lnutil.py
  5. 42
      electrum/lnwatcher.py
  6. 2
      electrum/lnworker.py

148
electrum/lnchannel.py

@ -27,13 +27,14 @@ from typing import (Optional, Dict, List, Tuple, NamedTuple, Set, Callable,
Iterable, Sequence, TYPE_CHECKING, Iterator, Union) Iterable, Sequence, TYPE_CHECKING, Iterator, Union)
import time import time
import threading import threading
from abc import ABC, abstractmethod
from aiorpcx import NetAddress from aiorpcx import NetAddress
import attr import attr
from . import ecc from . import ecc
from . import constants from . import constants
from .util import bfh, bh2u, chunks from .util import bfh, bh2u, chunks, TxMinedInfo
from .bitcoin import redeem_script_to_address from .bitcoin import redeem_script_to_address
from .crypto import sha256, sha256d from .crypto import sha256, sha256d
from .transaction import Transaction, PartialTransaction from .transaction import Transaction, PartialTransaction
@ -113,7 +114,9 @@ state_transitions = [
del cs # delete as name is ambiguous without context del cs # delete as name is ambiguous without context
RevokeAndAck = namedtuple("RevokeAndAck", ["per_commitment_secret", "next_per_commitment_point"]) class RevokeAndAck(NamedTuple):
per_commitment_secret: bytes
next_per_commitment_point: bytes
class RemoteCtnTooFarInFuture(Exception): pass class RemoteCtnTooFarInFuture(Exception): pass
@ -123,7 +126,16 @@ def htlcsum(htlcs):
return sum([x.amount_msat for x in htlcs]) return sum([x.amount_msat for x in htlcs])
class AbstractChannel(Logger): class AbstractChannel(Logger, ABC):
storage: Union['StoredDict', dict]
config: Dict[HTLCOwner, Union[LocalConfig, RemoteConfig]]
_sweep_info: Dict[str, Dict[str, 'SweepInfo']]
lnworker: Optional['LNWallet']
sweep_address: str
channel_id: bytes
funding_outpoint: Outpoint
node_id: bytes
_state: channel_states
def set_short_channel_id(self, short_id: ShortChannelID) -> None: def set_short_channel_id(self, short_id: ShortChannelID) -> None:
self.short_channel_id = short_id self.short_channel_id = short_id
@ -168,7 +180,7 @@ class AbstractChannel(Logger):
def is_redeemed(self): def is_redeemed(self):
return self.get_state() == channel_states.REDEEMED return self.get_state() == channel_states.REDEEMED
def save_funding_height(self, txid, height, timestamp): def save_funding_height(self, *, txid: str, height: int, timestamp: Optional[int]) -> None:
self.storage['funding_height'] = txid, height, timestamp self.storage['funding_height'] = txid, height, timestamp
def get_funding_height(self): def get_funding_height(self):
@ -177,7 +189,7 @@ class AbstractChannel(Logger):
def delete_funding_height(self): def delete_funding_height(self):
self.storage.pop('funding_height', None) self.storage.pop('funding_height', None)
def save_closing_height(self, txid, height, timestamp): def save_closing_height(self, *, txid: str, height: int, timestamp: Optional[int]) -> None:
self.storage['closing_height'] = txid, height, timestamp self.storage['closing_height'] = txid, height, timestamp
def get_closing_height(self): def get_closing_height(self):
@ -197,30 +209,34 @@ class AbstractChannel(Logger):
def sweep_ctx(self, ctx: Transaction) -> Dict[str, SweepInfo]: def sweep_ctx(self, ctx: Transaction) -> Dict[str, SweepInfo]:
txid = ctx.txid() txid = ctx.txid()
if self.sweep_info.get(txid) is None: if self._sweep_info.get(txid) is None:
our_sweep_info = self.create_sweeptxs_for_our_ctx(ctx) our_sweep_info = self.create_sweeptxs_for_our_ctx(ctx)
their_sweep_info = self.create_sweeptxs_for_their_ctx(ctx) their_sweep_info = self.create_sweeptxs_for_their_ctx(ctx)
if our_sweep_info is not None: if our_sweep_info is not None:
self.sweep_info[txid] = our_sweep_info self._sweep_info[txid] = our_sweep_info
self.logger.info(f'we force closed') self.logger.info(f'we force closed')
elif their_sweep_info is not None: elif their_sweep_info is not None:
self.sweep_info[txid] = their_sweep_info self._sweep_info[txid] = their_sweep_info
self.logger.info(f'they force closed.') self.logger.info(f'they force closed.')
else: else:
self.sweep_info[txid] = {} self._sweep_info[txid] = {}
self.logger.info(f'not sure who closed.') self.logger.info(f'not sure who closed.')
return self.sweep_info[txid] return self._sweep_info[txid]
# ancestor for Channel and ChannelBackup def update_onchain_state(self, *, funding_txid: str, funding_height: TxMinedInfo,
def update_onchain_state(self, funding_txid, funding_height, closing_txid, closing_height, keep_watching): closing_txid: str, closing_height: TxMinedInfo, keep_watching: bool) -> None:
# note: state transitions are irreversible, but # note: state transitions are irreversible, but
# save_funding_height, save_closing_height are reversible # save_funding_height, save_closing_height are reversible
if funding_height.height == TX_HEIGHT_LOCAL: if funding_height.height == TX_HEIGHT_LOCAL:
self.update_unfunded_state() self.update_unfunded_state()
elif closing_height.height == TX_HEIGHT_LOCAL: elif closing_height.height == TX_HEIGHT_LOCAL:
self.update_funded_state(funding_txid, funding_height) self.update_funded_state(funding_txid=funding_txid, funding_height=funding_height)
else: else:
self.update_closed_state(funding_txid, funding_height, closing_txid, closing_height, keep_watching) self.update_closed_state(funding_txid=funding_txid,
funding_height=funding_height,
closing_txid=closing_txid,
closing_height=closing_height,
keep_watching=keep_watching)
def update_unfunded_state(self): def update_unfunded_state(self):
self.delete_funding_height() self.delete_funding_height()
@ -249,8 +265,8 @@ class AbstractChannel(Logger):
if now - self.storage.get('init_timestamp', 0) > CHANNEL_OPENING_TIMEOUT: if now - self.storage.get('init_timestamp', 0) > CHANNEL_OPENING_TIMEOUT:
self.lnworker.remove_channel(self.channel_id) self.lnworker.remove_channel(self.channel_id)
def update_funded_state(self, funding_txid, funding_height): def update_funded_state(self, *, funding_txid: str, funding_height: TxMinedInfo) -> None:
self.save_funding_height(funding_txid, funding_height.height, funding_height.timestamp) self.save_funding_height(txid=funding_txid, height=funding_height.height, timestamp=funding_height.timestamp)
self.delete_closing_height() self.delete_closing_height()
if funding_height.conf>0: if funding_height.conf>0:
self.set_short_channel_id(ShortChannelID.from_components( self.set_short_channel_id(ShortChannelID.from_components(
@ -259,9 +275,10 @@ class AbstractChannel(Logger):
if self.is_funding_tx_mined(funding_height): if self.is_funding_tx_mined(funding_height):
self.set_state(channel_states.FUNDED) self.set_state(channel_states.FUNDED)
def update_closed_state(self, funding_txid, funding_height, closing_txid, closing_height, keep_watching): def update_closed_state(self, *, funding_txid: str, funding_height: TxMinedInfo,
self.save_funding_height(funding_txid, funding_height.height, funding_height.timestamp) closing_txid: str, closing_height: TxMinedInfo, keep_watching: bool) -> None:
self.save_closing_height(closing_txid, closing_height.height, closing_height.timestamp) self.save_funding_height(txid=funding_txid, height=funding_height.height, timestamp=funding_height.timestamp)
self.save_closing_height(txid=closing_txid, height=closing_height.height, timestamp=closing_height.timestamp)
if self.get_state() < channel_states.CLOSED: if self.get_state() < channel_states.CLOSED:
conf = closing_height.conf conf = closing_height.conf
if conf > 0: if conf > 0:
@ -273,6 +290,66 @@ class AbstractChannel(Logger):
if self.get_state() == channel_states.CLOSED and not keep_watching: if self.get_state() == channel_states.CLOSED and not keep_watching:
self.set_state(channel_states.REDEEMED) self.set_state(channel_states.REDEEMED)
@abstractmethod
def is_initiator(self) -> bool:
pass
@abstractmethod
def is_funding_tx_mined(self, funding_height: TxMinedInfo) -> bool:
pass
@abstractmethod
def get_funding_address(self) -> str:
pass
@abstractmethod
def get_state_for_GUI(self) -> str:
pass
@abstractmethod
def get_oldest_unrevoked_ctn(self, subject: HTLCOwner) -> int:
pass
@abstractmethod
def included_htlcs(self, subject: HTLCOwner, direction: Direction, ctn: int = None) -> Sequence[UpdateAddHtlc]:
pass
@abstractmethod
def funding_txn_minimum_depth(self) -> int:
pass
@abstractmethod
def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
"""This balance (in msat) only considers HTLCs that have been settled by ctn.
It disregards reserve, fees, and pending HTLCs (in both directions).
"""
pass
@abstractmethod
def balance_minus_outgoing_htlcs(self, whose: HTLCOwner, *,
ctx_owner: HTLCOwner = HTLCOwner.LOCAL,
ctn: int = None) -> int:
"""This balance (in msat), which includes the value of
pending outgoing HTLCs, is used in the UI.
"""
pass
@abstractmethod
def is_frozen_for_sending(self) -> bool:
"""Whether the user has marked this channel as frozen for sending.
Frozen channels are not supposed to be used for new outgoing payments.
(note that payment-forwarding ignores this option)
"""
pass
@abstractmethod
def is_frozen_for_receiving(self) -> bool:
"""Whether the user has marked this channel as frozen for receiving.
Frozen channels are not supposed to be used for new incoming payments.
(note that payment-forwarding ignores this option)
"""
pass
class ChannelBackup(AbstractChannel): class ChannelBackup(AbstractChannel):
""" """
@ -288,7 +365,7 @@ class ChannelBackup(AbstractChannel):
self.name = None self.name = None
Logger.__init__(self) Logger.__init__(self)
self.cb = cb self.cb = cb
self.sweep_info = {} # type: Dict[str, Dict[str, SweepInfo]] self._sweep_info = {}
self.sweep_address = sweep_address self.sweep_address = sweep_address
self.storage = {} # dummy storage self.storage = {} # dummy storage
self._state = channel_states.OPENING self._state = channel_states.OPENING
@ -351,7 +428,7 @@ class ChannelBackup(AbstractChannel):
def get_oldest_unrevoked_ctn(self, who): def get_oldest_unrevoked_ctn(self, who):
return -1 return -1
def included_htlcs(self, subject, direction, ctn): def included_htlcs(self, subject, direction, ctn=None):
return [] return []
def funding_txn_minimum_depth(self): def funding_txn_minimum_depth(self):
@ -381,16 +458,16 @@ class Channel(AbstractChannel):
def __init__(self, state: 'StoredDict', *, sweep_address=None, name=None, lnworker=None, initial_feerate=None): def __init__(self, state: 'StoredDict', *, sweep_address=None, name=None, lnworker=None, initial_feerate=None):
self.name = name self.name = name
Logger.__init__(self) Logger.__init__(self)
self.lnworker = lnworker # type: Optional[LNWallet] self.lnworker = lnworker
self.sweep_address = sweep_address self.sweep_address = sweep_address
self.storage = state self.storage = state
self.db_lock = self.storage.db.lock if self.storage.db else threading.RLock() self.db_lock = self.storage.db.lock if self.storage.db else threading.RLock()
self.config = {} # type: Dict[HTLCOwner, Union[LocalConfig, RemoteConfig]] self.config = {}
self.config[LOCAL] = state["local_config"] self.config[LOCAL] = state["local_config"]
self.config[REMOTE] = state["remote_config"] self.config[REMOTE] = state["remote_config"]
self.channel_id = bfh(state["channel_id"]) self.channel_id = bfh(state["channel_id"])
self.constraints = state["constraints"] # type: ChannelConstraints self.constraints = state["constraints"] # type: ChannelConstraints
self.funding_outpoint = state["funding_outpoint"] # type: Outpoint self.funding_outpoint = state["funding_outpoint"]
self.node_id = bfh(state["node_id"]) self.node_id = bfh(state["node_id"])
self.short_channel_id = ShortChannelID.normalize(state["short_channel_id"]) self.short_channel_id = ShortChannelID.normalize(state["short_channel_id"])
self.onion_keys = state['onion_keys'] # type: Dict[int, bytes] self.onion_keys = state['onion_keys'] # type: Dict[int, bytes]
@ -398,7 +475,7 @@ class Channel(AbstractChannel):
self.hm = HTLCManager(log=state['log'], initial_feerate=initial_feerate) self.hm = HTLCManager(log=state['log'], initial_feerate=initial_feerate)
self._state = channel_states[state['state']] self._state = channel_states[state['state']]
self.peer_state = peer_states.DISCONNECTED self.peer_state = peer_states.DISCONNECTED
self.sweep_info = {} # type: Dict[str, Dict[str, SweepInfo]] self._sweep_info = {}
self._outgoing_channel_update = None # type: Optional[bytes] self._outgoing_channel_update = None # type: Optional[bytes]
self._chan_ann_without_sigs = None # type: Optional[bytes] self._chan_ann_without_sigs = None # type: Optional[bytes]
self.revocation_store = RevocationStore(state["revocation_store"]) self.revocation_store = RevocationStore(state["revocation_store"])
@ -596,10 +673,6 @@ class Channel(AbstractChannel):
return self.can_send_ctx_updates() and not self.is_closing() return self.can_send_ctx_updates() and not self.is_closing()
def is_frozen_for_sending(self) -> bool: def is_frozen_for_sending(self) -> bool:
"""Whether the user has marked this channel as frozen for sending.
Frozen channels are not supposed to be used for new outgoing payments.
(note that payment-forwarding ignores this option)
"""
return self.storage.get('frozen_for_sending', False) return self.storage.get('frozen_for_sending', False)
def set_frozen_for_sending(self, b: bool) -> None: def set_frozen_for_sending(self, b: bool) -> None:
@ -608,10 +681,6 @@ class Channel(AbstractChannel):
self.lnworker.network.trigger_callback('channel', self) self.lnworker.network.trigger_callback('channel', self)
def is_frozen_for_receiving(self) -> bool: def is_frozen_for_receiving(self) -> bool:
"""Whether the user has marked this channel as frozen for receiving.
Frozen channels are not supposed to be used for new incoming payments.
(note that payment-forwarding ignores this option)
"""
return self.storage.get('frozen_for_receiving', False) return self.storage.get('frozen_for_receiving', False)
def set_frozen_for_receiving(self, b: bool) -> None: def set_frozen_for_receiving(self, b: bool) -> None:
@ -880,9 +949,6 @@ class Channel(AbstractChannel):
self.lnworker.payment_failed(self, htlc.payment_hash, payment_attempt) self.lnworker.payment_failed(self, htlc.payment_hash, payment_attempt)
def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int: def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
"""This balance (in msat) only considers HTLCs that have been settled by ctn.
It disregards reserve, fees, and pending HTLCs (in both directions).
"""
assert type(whose) is HTLCOwner assert type(whose) is HTLCOwner
initial = self.config[whose].initial_msat initial = self.config[whose].initial_msat
return self.hm.get_balance_msat(whose=whose, return self.hm.get_balance_msat(whose=whose,
@ -891,10 +957,7 @@ class Channel(AbstractChannel):
initial_balance_msat=initial) initial_balance_msat=initial)
def balance_minus_outgoing_htlcs(self, whose: HTLCOwner, *, ctx_owner: HTLCOwner = HTLCOwner.LOCAL, def balance_minus_outgoing_htlcs(self, whose: HTLCOwner, *, ctx_owner: HTLCOwner = HTLCOwner.LOCAL,
ctn: int = None): ctn: int = None) -> int:
"""This balance (in msat), which includes the value of
pending outgoing HTLCs, is used in the UI.
"""
assert type(whose) is HTLCOwner assert type(whose) is HTLCOwner
if ctn is None: if ctn is None:
ctn = self.get_next_ctn(ctx_owner) ctn = self.get_next_ctn(ctx_owner)
@ -1282,11 +1345,6 @@ class Channel(AbstractChannel):
return total_value_sat > min_value_worth_closing_channel_over_sat return total_value_sat > min_value_worth_closing_channel_over_sat
def is_funding_tx_mined(self, funding_height): def is_funding_tx_mined(self, funding_height):
"""
Checks if Funding TX has been mined. If it has, save the short channel ID in chan;
if it's also deep enough, also save to disk.
Returns tuple (mined_deep_enough, num_confirmations).
"""
funding_txid = self.funding_outpoint.txid funding_txid = self.funding_outpoint.txid
funding_idx = self.funding_outpoint.output_index funding_idx = self.funding_outpoint.output_index
conf = funding_height.conf conf = funding_height.conf

4
electrum/lnsweep.py

@ -21,7 +21,7 @@ from .simple_config import SimpleConfig
from .logging import get_logger, Logger from .logging import get_logger, Logger
if TYPE_CHECKING: if TYPE_CHECKING:
from .lnchannel import Channel from .lnchannel import Channel, AbstractChannel
_logger = get_logger(__name__) _logger = get_logger(__name__)
@ -169,7 +169,7 @@ def create_sweeptx_for_their_revoked_htlc(chan: 'Channel', ctx: Transaction, htl
def create_sweeptxs_for_our_ctx(*, chan: 'Channel', ctx: Transaction, def create_sweeptxs_for_our_ctx(*, chan: 'AbstractChannel', ctx: Transaction,
sweep_address: str) -> Optional[Dict[str, SweepInfo]]: sweep_address: str) -> Optional[Dict[str, SweepInfo]]:
"""Handle the case where we force close unilaterally with our latest ctx. """Handle the case where we force close unilaterally with our latest ctx.
Construct sweep txns for 'to_local', and for all HTLCs (2 txns each). Construct sweep txns for 'to_local', and for all HTLCs (2 txns each).

1
electrum/lntransport.py

@ -89,6 +89,7 @@ def create_ephemeral_key() -> (bytes, bytes):
class LNTransportBase: class LNTransportBase:
reader: StreamReader reader: StreamReader
writer: StreamWriter writer: StreamWriter
privkey: bytes
def name(self) -> str: def name(self) -> str:
raise NotImplementedError() raise NotImplementedError()

8
electrum/lnutil.py

@ -27,7 +27,7 @@ from .bip32 import BIP32Node, BIP32_PRIME
from .transaction import BCDataStream from .transaction import BCDataStream
if TYPE_CHECKING: if TYPE_CHECKING:
from .lnchannel import Channel from .lnchannel import Channel, AbstractChannel
from .lnrouter import LNPaymentRoute from .lnrouter import LNPaymentRoute
from .lnonion import OnionRoutingFailureMessage from .lnonion import OnionRoutingFailureMessage
@ -504,8 +504,8 @@ def make_htlc_output_witness_script(is_received_htlc: bool, remote_revocation_pu
payment_hash=payment_hash) payment_hash=payment_hash)
def get_ordered_channel_configs(chan: 'Channel', for_us: bool) -> Tuple[Union[LocalConfig, RemoteConfig], def get_ordered_channel_configs(chan: 'AbstractChannel', for_us: bool) -> Tuple[Union[LocalConfig, RemoteConfig],
Union[LocalConfig, RemoteConfig]]: Union[LocalConfig, RemoteConfig]]:
conf = chan.config[LOCAL] if for_us else chan.config[REMOTE] conf = chan.config[LOCAL] if for_us else chan.config[REMOTE]
other_conf = chan.config[LOCAL] if not for_us else chan.config[REMOTE] other_conf = chan.config[LOCAL] if not for_us else chan.config[REMOTE]
return conf, other_conf return conf, other_conf
@ -781,7 +781,7 @@ def extract_ctn_from_tx(tx: Transaction, txin_index: int, funder_payment_basepoi
obs = ((sequence & 0xffffff) << 24) + (locktime & 0xffffff) obs = ((sequence & 0xffffff) << 24) + (locktime & 0xffffff)
return get_obscured_ctn(obs, funder_payment_basepoint, fundee_payment_basepoint) return get_obscured_ctn(obs, funder_payment_basepoint, fundee_payment_basepoint)
def extract_ctn_from_tx_and_chan(tx: Transaction, chan: 'Channel') -> int: def extract_ctn_from_tx_and_chan(tx: Transaction, chan: 'AbstractChannel') -> int:
funder_conf = chan.config[LOCAL] if chan.is_initiator() else chan.config[REMOTE] funder_conf = chan.config[LOCAL] if chan.is_initiator() else chan.config[REMOTE]
fundee_conf = chan.config[LOCAL] if not chan.is_initiator() else chan.config[REMOTE] fundee_conf = chan.config[LOCAL] if not chan.is_initiator() else chan.config[REMOTE]
return extract_ctn_from_tx(tx, txin_index=0, return extract_ctn_from_tx(tx, txin_index=0,

42
electrum/lnwatcher.py

@ -4,20 +4,13 @@
from typing import NamedTuple, Iterable, TYPE_CHECKING from typing import NamedTuple, Iterable, TYPE_CHECKING
import os import os
import queue
import threading
import concurrent
from collections import defaultdict
import asyncio import asyncio
from enum import IntEnum, auto from enum import IntEnum, auto
from typing import NamedTuple, Dict from typing import NamedTuple, Dict
from .sql_db import SqlDB, sql from .sql_db import SqlDB, sql
from .wallet_db import WalletDB from .wallet_db import WalletDB
from .util import bh2u, bfh, log_exceptions, ignore_exceptions from .util import bh2u, bfh, log_exceptions, ignore_exceptions, TxMinedInfo
from .lnutil import Outpoint
from . import wallet
from .storage import WalletStorage
from .address_synchronizer import AddressSynchronizer, TX_HEIGHT_LOCAL, TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED from .address_synchronizer import AddressSynchronizer, TX_HEIGHT_LOCAL, TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED
from .transaction import Transaction from .transaction import Transaction
@ -199,17 +192,22 @@ class LNWatcher(AddressSynchronizer):
else: else:
keep_watching = True keep_watching = True
await self.update_channel_state( await self.update_channel_state(
funding_outpoint, funding_txid, funding_outpoint=funding_outpoint,
funding_height, closing_txid, funding_txid=funding_txid,
closing_height, keep_watching) funding_height=funding_height,
closing_txid=closing_txid,
closing_height=closing_height,
keep_watching=keep_watching)
if not keep_watching: if not keep_watching:
await self.unwatch_channel(address, funding_outpoint) await self.unwatch_channel(address, funding_outpoint)
async def do_breach_remedy(self, funding_outpoint, closing_tx, spenders): async def do_breach_remedy(self, funding_outpoint, closing_tx, spenders) -> bool:
raise NotImplementedError() # implemented by subclasses raise NotImplementedError() # implemented by subclasses
async def update_channel_state(self, *args): async def update_channel_state(self, *, funding_outpoint: str, funding_txid: str,
raise NotImplementedError() # implemented by subclasses funding_height: TxMinedInfo, closing_txid: str,
closing_height: TxMinedInfo, keep_watching: bool) -> None:
raise NotImplementedError() # implemented by subclasses
def inspect_tx_candidate(self, outpoint, n): def inspect_tx_candidate(self, outpoint, n):
prev_txid, index = outpoint.split(':') prev_txid, index = outpoint.split(':')
@ -325,7 +323,7 @@ class WatchTower(LNWatcher):
if funding_outpoint in self.tx_progress: if funding_outpoint in self.tx_progress:
self.tx_progress[funding_outpoint].all_done.set() self.tx_progress[funding_outpoint].all_done.set()
async def update_channel_state(self, *args): async def update_channel_state(self, *args, **kwargs):
pass pass
@ -340,17 +338,23 @@ class LNWalletWatcher(LNWatcher):
@ignore_exceptions @ignore_exceptions
@log_exceptions @log_exceptions
async def update_channel_state(self, funding_outpoint, funding_txid, funding_height, closing_txid, closing_height, keep_watching): async def update_channel_state(self, *, funding_outpoint: str, funding_txid: str,
funding_height: TxMinedInfo, closing_txid: str,
closing_height: TxMinedInfo, keep_watching: bool) -> None:
chan = self.lnworker.channel_by_txo(funding_outpoint) chan = self.lnworker.channel_by_txo(funding_outpoint)
if not chan: if not chan:
return return
chan.update_onchain_state(funding_txid, funding_height, closing_txid, closing_height, keep_watching) chan.update_onchain_state(funding_txid=funding_txid,
funding_height=funding_height,
closing_txid=closing_txid,
closing_height=closing_height,
keep_watching=keep_watching)
await self.lnworker.on_channel_update(chan) await self.lnworker.on_channel_update(chan)
async def do_breach_remedy(self, funding_outpoint, closing_tx, spenders): async def do_breach_remedy(self, funding_outpoint, closing_tx, spenders):
chan = self.lnworker.channel_by_txo(funding_outpoint) chan = self.lnworker.channel_by_txo(funding_outpoint)
if not chan: if not chan:
return return False
# detect who closed and set sweep_info # detect who closed and set sweep_info
sweep_info_dict = chan.sweep_ctx(closing_tx) sweep_info_dict = chan.sweep_ctx(closing_tx)
keep_watching = False if sweep_info_dict else not self.is_deeply_mined(closing_tx.txid()) keep_watching = False if sweep_info_dict else not self.is_deeply_mined(closing_tx.txid())

2
electrum/lnworker.py

@ -432,7 +432,7 @@ class LNWallet(LNWorker):
self.preimages = self.db.get_dict('lightning_preimages') # RHASH -> preimage self.preimages = self.db.get_dict('lightning_preimages') # RHASH -> preimage
self.sweep_address = wallet.get_receiving_address() self.sweep_address = wallet.get_receiving_address()
self.lock = threading.RLock() self.lock = threading.RLock()
self.logs = defaultdict(list) # (not persisted) type: Dict[str, List[PaymentAttemptLog]] # key is RHASH self.logs = defaultdict(list) # type: Dict[str, List[PaymentAttemptLog]] # key is RHASH # (not persisted)
self.is_routing = set() # (not persisted) keys of invoices that are in PR_ROUTING state self.is_routing = set() # (not persisted) keys of invoices that are in PR_ROUTING state
# used in tests # used in tests
self.enable_htlc_settle = asyncio.Event() self.enable_htlc_settle = asyncio.Event()

Loading…
Cancel
Save