• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

spesmilo / electrum / 6028015529885696

28 Oct 2025 10:43AM UTC coverage: 61.447% (-0.008%) from 61.455%
6028015529885696

push

CirrusCI

ecdsa
notary plugin

22938 of 37330 relevant lines covered (61.45%)

0.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.62
/electrum/lnchannel.py
1
# Copyright (C) 2018 The Electrum developers
2
#
3
# Permission is hereby granted, free of charge, to any person obtaining a copy
4
# of this software and associated documentation files (the "Software"), to deal
5
# in the Software without restriction, including without limitation the rights
6
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
# copies of the Software, and to permit persons to whom the Software is
8
# furnished to do so, subject to the following conditions:
9
#
10
# The above copyright notice and this permission notice shall be included in
11
# all copies or substantial portions of the Software.
12
#
13
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
# THE SOFTWARE.
20
import dataclasses
1✔
21
import enum
1✔
22
from collections import defaultdict
1✔
23
from enum import IntEnum, Enum
1✔
24
from typing import (
1✔
25
    Optional, Dict, List, Tuple, NamedTuple,
26
    Iterable, Sequence, TYPE_CHECKING, Iterator, Union, Mapping)
27
import time
1✔
28
import threading
1✔
29
from abc import ABC, abstractmethod
1✔
30
import itertools
1✔
31

32
from aiorpcx import NetAddress
1✔
33
import attr
1✔
34

35
import electrum_ecc as ecc
1✔
36
from electrum_ecc import ECPubkey
1✔
37

38
from . import constants, util
1✔
39
from .util import bfh, chunks, TxMinedInfo, error_text_bytes_to_safe_str
1✔
40
from .bitcoin import redeem_script_to_address
1✔
41
from .crypto import sha256, sha256d
1✔
42
from .transaction import Transaction, PartialTransaction, TxInput, Sighash
1✔
43
from .logging import Logger
1✔
44
from .lntransport import LNPeerAddr
1✔
45
from .lnonion import OnionRoutingFailure
1✔
46
from . import lnutil
1✔
47
from .lnutil import (Outpoint, LocalConfig, RemoteConfig, Keypair, OnlyPubkeyKeypair, ChannelConstraints,
1✔
48
                     get_per_commitment_secret_from_seed, secret_to_pubkey, derive_privkey, make_closing_tx,
49
                     sign_and_get_sig_string, RevocationStore, derive_blinded_pubkey, Direction, derive_pubkey,
50
                     make_htlc_tx_with_open_channel, make_commitment, UpdateAddHtlc,
51
                     funding_output_script, SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, make_commitment_outputs,
52
                     ScriptHtlc, PaymentFailure, calc_fees_for_commitment_tx, RemoteMisbehaving, make_htlc_output_witness_script,
53
                     ShortChannelID, map_htlcs_to_ctx_output_idxs,
54
                     fee_for_htlc_output, offered_htlc_trim_threshold_sat,
55
                     received_htlc_trim_threshold_sat, make_commitment_output_to_remote_address, FIXED_ANCHOR_SAT,
56
                     ChannelType, LNProtocolWarning, ZEROCONF_TIMEOUT)
57
from .lnsweep import sweep_our_ctx, sweep_their_ctx
1✔
58
from .lnsweep import sweep_their_htlctx_justice, sweep_our_htlctx, SweepInfo
1✔
59
from .lnsweep import sweep_their_ctx_to_remote_backup
1✔
60
from .lnhtlc import HTLCManager
1✔
61
from .lnmsg import encode_msg, decode_msg
1✔
62
from .address_synchronizer import TX_HEIGHT_LOCAL
1✔
63
from .lnutil import CHANNEL_OPENING_TIMEOUT
1✔
64
from .lnutil import ChannelBackupStorage, ImportedChannelBackupStorage, OnchainChannelBackupStorage
1✔
65
from .lnutil import format_short_channel_id
1✔
66
from .fee_policy import FEERATE_PER_KW_MIN_RELAY_LIGHTNING
1✔
67

68
if TYPE_CHECKING:
69
    from .lnworker import LNWallet
70
    from .json_db import StoredDict
71

72

73
# channel flags
74
CF_ANNOUNCE_CHANNEL = 0x01
1✔
75

76
# lightning channel states
77
# Note: these states are persisted by name (for a given channel) in the wallet file,
78
#       so consider doing a wallet db upgrade when changing them.
79
class ChannelState(IntEnum):
1✔
80
    PREOPENING      = 0  # Initial negotiation. Channel will not be reestablished
1✔
81
    OPENING         = 1  # Channel will be reestablished. (per BOLT2)
1✔
82
                         #  - Funding node: has received funding_signed (can broadcast the funding tx)
83
                         #  - Non-funding node: has sent the funding_signed message.
84
    FUNDED          = 2  # Funding tx was mined (requires min_depth and tx verification)
1✔
85
    OPEN            = 3  # both parties have sent funding_locked
1✔
86
    SHUTDOWN        = 4  # shutdown has been sent.
1✔
87
    CLOSING         = 5  # closing negotiation done. we have a fully signed tx.
1✔
88
    FORCE_CLOSING   = 6  # *we* force-closed, and closing tx is unconfirmed. Note that if the
1✔
89
                         # remote force-closes then we remain OPEN until it gets mined -
90
                         # the server could be lying to us with a fake tx.
91
    REQUESTED_FCLOSE = 7   # Chan is open, but we have tried to request the *remote* to force-close
1✔
92
    WE_ARE_TOXIC     = 8   # Chan is open, but we have lost state and the remote proved this.
1✔
93
                           # The remote must force-close, it is *not* safe for us to do so.
94
    CLOSED           = 9   # closing tx has been mined
1✔
95
    REDEEMED         = 10  # we can stop watching
1✔
96

97

98
class PeerState(IntEnum):
1✔
99
    DISCONNECTED   = 0
1✔
100
    REESTABLISHING = 1
1✔
101
    GOOD           = 2
1✔
102
    BAD            = 3
1✔
103

104

105
cs = ChannelState
1✔
106
state_transitions = [
1✔
107
    (cs.PREOPENING, cs.OPENING),
108
    (cs.OPENING, cs.FUNDED),
109
    (cs.FUNDED, cs.OPEN),
110
    (cs.OPENING, cs.SHUTDOWN),
111
    (cs.FUNDED, cs.SHUTDOWN),
112
    (cs.OPEN, cs.SHUTDOWN),
113
    (cs.SHUTDOWN, cs.SHUTDOWN),  # if we reestablish
114
    (cs.SHUTDOWN, cs.CLOSING),
115
    (cs.CLOSING, cs.CLOSING),
116
    # we can force close almost any time
117
    (cs.OPENING,  cs.FORCE_CLOSING),
118
    (cs.FUNDED,   cs.FORCE_CLOSING),
119
    (cs.OPEN,     cs.FORCE_CLOSING),
120
    (cs.SHUTDOWN, cs.FORCE_CLOSING),
121
    (cs.CLOSING,  cs.FORCE_CLOSING),
122
    (cs.REQUESTED_FCLOSE, cs.FORCE_CLOSING),
123
    # we can request a force-close almost any time
124
    (cs.OPENING,  cs.REQUESTED_FCLOSE),
125
    (cs.FUNDED,   cs.REQUESTED_FCLOSE),
126
    (cs.OPEN,     cs.REQUESTED_FCLOSE),
127
    (cs.SHUTDOWN, cs.REQUESTED_FCLOSE),
128
    (cs.CLOSING,  cs.REQUESTED_FCLOSE),
129
    (cs.REQUESTED_FCLOSE,  cs.REQUESTED_FCLOSE),
130
    # we can get force closed almost any time
131
    (cs.OPENING,  cs.CLOSED),
132
    (cs.FUNDED,   cs.CLOSED),
133
    (cs.OPEN,     cs.CLOSED),
134
    (cs.SHUTDOWN, cs.CLOSED),
135
    (cs.CLOSING,  cs.CLOSED),
136
    (cs.REQUESTED_FCLOSE, cs.CLOSED),
137
    (cs.WE_ARE_TOXIC,          cs.CLOSED),
138
    # during channel_reestablish, we might realise we have lost state
139
    (cs.OPENING,  cs.WE_ARE_TOXIC),
140
    (cs.FUNDED,   cs.WE_ARE_TOXIC),
141
    (cs.OPEN,     cs.WE_ARE_TOXIC),
142
    (cs.SHUTDOWN, cs.WE_ARE_TOXIC),
143
    (cs.REQUESTED_FCLOSE, cs.WE_ARE_TOXIC),
144
    (cs.WE_ARE_TOXIC, cs.WE_ARE_TOXIC),
145
    #
146
    (cs.FORCE_CLOSING, cs.FORCE_CLOSING),  # allow multiple attempts
147
    (cs.FORCE_CLOSING, cs.CLOSED),
148
    (cs.FORCE_CLOSING, cs.REDEEMED),
149
    (cs.CLOSED, cs.REDEEMED),
150
    (cs.OPENING, cs.REDEEMED),  # channel never funded (dropped from mempool)
151
    (cs.PREOPENING, cs.REDEEMED),  # channel never funded
152
]
153
del cs  # delete as name is ambiguous without context
1✔
154

155

156
class ChanCloseOption(Enum):
1✔
157
    COOP_CLOSE = enum.auto()
1✔
158
    LOCAL_FCLOSE = enum.auto()
1✔
159
    REQUEST_REMOTE_FCLOSE = enum.auto()
1✔
160

161

162
class RevokeAndAck(NamedTuple):
1✔
163
    per_commitment_secret: bytes
1✔
164
    next_per_commitment_point: bytes
1✔
165

166

167
class RemoteCtnTooFarInFuture(Exception): pass
1✔
168

169

170
def htlcsum(htlcs: Iterable[UpdateAddHtlc]):
1✔
171
    return sum([x.amount_msat for x in htlcs])
1✔
172

173
def now():
1✔
174
    return int(time.time())
1✔
175

176
class HTLCWithStatus(NamedTuple):
1✔
177
    channel_id: bytes
1✔
178
    htlc: UpdateAddHtlc
1✔
179
    direction: Direction
1✔
180
    status: str
1✔
181

182

183
class AbstractChannel(Logger, ABC):
1✔
184
    storage: Union['StoredDict', dict]
1✔
185
    config: Dict[HTLCOwner, Union[LocalConfig, RemoteConfig]]
1✔
186
    lnworker: Optional['LNWallet']
1✔
187
    channel_id: bytes
1✔
188
    short_channel_id: Optional[ShortChannelID] = None
1✔
189
    funding_outpoint: Outpoint
1✔
190
    node_id: bytes  # note that it might not be the full 33 bytes; for OCB it is only the prefix
1✔
191
    should_request_force_close: bool = False
1✔
192
    _state: ChannelState
1✔
193
    _who_closed: Optional[int] = None  # HTLCOwner (1 or -1).  0 means "unknown"
1✔
194

195
    def set_short_channel_id(self, short_id: ShortChannelID) -> None:
1✔
196
        self.short_channel_id = short_id
×
197
        self.storage["short_channel_id"] = short_id
×
198

199
    def get_id_for_log(self) -> str:
1✔
200
        scid = self.short_channel_id
1✔
201
        if scid:
1✔
202
            return str(scid)
1✔
203
        return self.channel_id.hex()
×
204

205
    def short_id_for_GUI(self) -> str:
1✔
206
        return format_short_channel_id(self.short_channel_id)
×
207

208
    def diagnostic_name(self):
1✔
209
        return self.get_id_for_log()
1✔
210

211
    def set_state(self, state: ChannelState, *, force: bool = False) -> None:
1✔
212
        """Set on-chain state.
213
        `force` can be set while debugging from the console to allow illegal transitions.
214
        """
215
        old_state = self._state
1✔
216
        if not force and (old_state, state) not in state_transitions:
1✔
217
            raise Exception(f"Transition not allowed: {old_state.name} -> {state.name}")
×
218
        self.logger.debug(f'Setting channel state: {old_state.name} -> {state.name}')
1✔
219
        self._state = state
1✔
220
        self.storage['state'] = self._state.name
1✔
221
        if self.lnworker:
1✔
222
            self.lnworker.channel_state_changed(self)
1✔
223

224
    def get_state(self) -> ChannelState:
1✔
225
        return self._state
1✔
226

227
    def is_funded(self) -> bool:
1✔
228
        return self.get_state() >= ChannelState.FUNDED
1✔
229

230
    def is_open(self) -> bool:
1✔
231
        return self.get_state() == ChannelState.OPEN
1✔
232

233
    def is_closed(self) -> bool:
1✔
234
        # the closing txid has been saved
235
        return self.get_state() >= ChannelState.CLOSING
1✔
236

237
    def is_closed_or_closing(self):
1✔
238
        # related: self.get_state_for_GUI
239
        return self.is_closed() or self.unconfirmed_closing_txid is not None
×
240

241
    def is_redeemed(self) -> bool:
1✔
242
        return self.get_state() == ChannelState.REDEEMED
1✔
243

244
    def need_to_subscribe(self) -> bool:
1✔
245
        """Whether lnwatcher/synchronizer need to be watching this channel."""
246
        if not self.is_redeemed():
1✔
247
            return True
1✔
248
        # Chan already deeply closed. Still, if some txs are missing, we should sub.
249
        # check we have funding tx
250
        # note: tx might not be directly related to the wallet, e.g. chan opened by remote
251
        if (funding_item := self.get_funding_height()) is None:
1✔
252
            return True
×
253
        if self.lnworker:
1✔
254
            funding_txid, funding_height, funding_timestamp = funding_item
1✔
255
            if self.lnworker.wallet.adb.get_transaction(funding_txid) is None:
1✔
256
                return True
×
257
        # check we have closing tx
258
        # note: tx might not be directly related to the wallet, e.g. local-fclose
259
        if (closing_item := self.get_closing_height()) is None:
1✔
260
            return True
×
261
        if self.lnworker:
1✔
262
            closing_txid, closing_height, closing_timestamp = closing_item
1✔
263
            if self.lnworker.wallet.adb.get_transaction(closing_txid) is None:
1✔
264
                return True
×
265
        return False
1✔
266

267
    @abstractmethod
1✔
268
    def get_close_options(self) -> Sequence[ChanCloseOption]:
1✔
269
        pass
×
270

271
    def save_funding_height(self, *, txid: str, height: int, timestamp: Optional[int]) -> None:
1✔
272
        self.storage['funding_height'] = txid, height, timestamp
×
273

274
    def get_funding_height(self) -> Optional[Tuple[str, int, Optional[int]]]:
1✔
275
        return self.storage.get('funding_height')
1✔
276

277
    def delete_funding_height(self):
1✔
278
        self.storage.pop('funding_height', None)
×
279

280
    def save_closing_height(self, *, txid: str, height: int, timestamp: Optional[int]) -> None:
1✔
281
        self.storage['closing_height'] = txid, height, timestamp
×
282

283
    def get_closing_height(self) -> Optional[Tuple[str, int, Optional[int]]]:
1✔
284
        return self.storage.get('closing_height')
1✔
285

286
    def delete_closing_height(self):
1✔
287
        self.storage.pop('closing_height', None)
×
288

289
    def create_sweeptxs_for_our_ctx(self, ctx: Transaction) -> Dict[str, SweepInfo]:
1✔
290
        return sweep_our_ctx(chan=self, ctx=ctx)
×
291

292
    def create_sweeptxs_for_their_ctx(self, ctx: Transaction) -> Dict[str, SweepInfo]:
1✔
293
        return sweep_their_ctx(chan=self, ctx=ctx)
×
294

295
    def is_backup(self) -> bool:
1✔
296
        return False
×
297

298
    def get_local_scid_alias(self, *, create_new_if_needed: bool = False) -> Optional[bytes]:
1✔
299
        return None
×
300

301
    def get_remote_scid_alias(self) -> Optional[bytes]:
1✔
302
        return None
×
303

304
    def get_remote_peer_sent_error(self) -> Optional[str]:
1✔
305
        return None
×
306

307
    def get_ctx_sweep_info(self, ctx: Transaction) -> Tuple[bool, Dict[str, SweepInfo]]:
1✔
308
        our_sweep_info = self.create_sweeptxs_for_our_ctx(ctx)
×
309
        their_sweep_info = self.create_sweeptxs_for_their_ctx(ctx)
×
310
        if our_sweep_info:
×
311
            sweep_info = our_sweep_info
×
312
            who_closed = LOCAL
×
313
        elif their_sweep_info:
×
314
            sweep_info = their_sweep_info
×
315
            who_closed = REMOTE
×
316
        else:
317
            sweep_info = {}
×
318
            who_closed = 0
×
319
        if self._who_closed != who_closed:  # mostly here to limit log spam
×
320
            self._who_closed = who_closed
×
321
            if who_closed == LOCAL:
×
322
                self.logger.info(f'we (local) force closed')
×
323
            elif who_closed == REMOTE:
×
324
                self.logger.info(f'they (remote) force closed.')
×
325
            else:
326
                self.logger.info(f'not sure who closed. maybe co-op close?')
×
327
        is_local_ctx = who_closed == LOCAL
×
328
        return is_local_ctx, sweep_info
×
329

330
    def maybe_sweep_htlcs(self, ctx: Transaction, htlc_tx: Transaction) -> Dict[str, SweepInfo]:
1✔
331
        return {}
×
332

333
    def extract_preimage_from_htlc_txin(self, txin: TxInput, *, is_deeply_mined: bool) -> None:
1✔
334
        return
×
335

336
    def update_onchain_state(self, *, funding_txid: str, funding_height: TxMinedInfo,
1✔
337
                             closing_txid: str, closing_height: TxMinedInfo, keep_watching: bool) -> None:
338
        # note: state transitions are irreversible, but
339
        # save_funding_height, save_closing_height are reversible
340
        if funding_height.height() == TX_HEIGHT_LOCAL:
×
341
            self.update_unfunded_state()
×
342
        elif closing_height.height() == TX_HEIGHT_LOCAL:
×
343
            self.update_funded_state(
×
344
                funding_txid=funding_txid,
345
                funding_height=funding_height)
346
        else:
347
            self.update_closed_state(
×
348
                funding_txid=funding_txid,
349
                funding_height=funding_height,
350
                closing_txid=closing_txid,
351
                closing_height=closing_height,
352
                keep_watching=keep_watching)
353

354
    def update_unfunded_state(self) -> None:
1✔
355
        self.delete_funding_height()
×
356
        self.delete_closing_height()
×
357
        if not self.lnworker:
×
358
            return
×
359
        chan_age = now() - self.storage.get('init_timestamp', 0)
×
360
        state = self.get_state()
×
361
        if state in [ChannelState.PREOPENING, ChannelState.OPENING, ChannelState.FORCE_CLOSING]:
×
362
            if self.is_initiator():
×
363
                # set channel state to REDEEMED so that it can be removed manually
364
                # to protect ourselves against a server lying by omission,
365
                # we check that funding_inputs have been double spent and deeply mined
366
                inputs = self.storage.get('funding_inputs', [])
×
367
                if not inputs:
×
368
                    self.logger.info(f'channel funding inputs are not provided')
×
369
                    self.set_state(ChannelState.REDEEMED)
×
370
                for i in inputs:
×
371
                    spender_txid = self.lnworker.wallet.db.get_spent_outpoint(*i)
×
372
                    if spender_txid is None:
×
373
                        continue
×
374
                    if spender_txid != self.funding_outpoint.txid:
×
375
                        tx_mined_height = self.lnworker.wallet.adb.get_tx_height(spender_txid)
×
376
                        if tx_mined_height.conf > lnutil.REDEEM_AFTER_DOUBLE_SPENT_DELAY:
×
377
                            self.logger.info(f'channel is double spent {inputs}')
×
378
                            self.set_state(ChannelState.REDEEMED)
×
379
                            break
×
380
            else:
381
                if chan_age > CHANNEL_OPENING_TIMEOUT:
×
382
                    self.lnworker.remove_channel(self.channel_id)
×
383
        elif self.is_zeroconf() and state in [ChannelState.OPEN, ChannelState.CLOSING, ChannelState.FORCE_CLOSING]:
×
384
            assert self.storage.get('init_timestamp') is not None, "init_timestamp not set for zeroconf channel"
×
385
            # handling zeroconf channels with no funding tx, can happen if broadcasting fails on LSP side
386
            # or if the LSP did double spent the funding tx/never published it intentionally
387
            # only remove a timed out OPEN channel if we are connected to the network to prevent removing it if we went
388
            # offline before seeing the funding tx
389
            if state != ChannelState.OPEN or chan_age > ZEROCONF_TIMEOUT and self.lnworker.network.is_connected():
×
390
                # we delete the channel if its in closing state (either initiated manually by client or by LSP on failure)
391
                # or if the channel is not seeing any funding tx after 10 minutes to prevent further usage (limit damage)
392
                self.set_state(ChannelState.REDEEMED, force=True)
×
393
                local_balance_sat = int(self.balance(LOCAL) // 1000)
×
394
                if local_balance_sat > 0:
×
395
                    self.logger.warning(
×
396
                        f"we may have been scammed out of {local_balance_sat} sat by our "
397
                        f"JIT provider: {self.lnworker.config.ZEROCONF_TRUSTED_NODE} or he didn't use our preimage")
398
                    self.lnworker.config.ZEROCONF_TRUSTED_NODE = ''
×
399
                self.lnworker.lnwatcher.unwatch_channel(self.get_funding_address(), self.funding_outpoint.to_str())
×
400
                # remove remaining local transactions from the wallet, this will also remove child transactions (closing tx)
401
                self.lnworker.lnwatcher.adb.remove_transaction(self.funding_outpoint.txid)
×
402
                self.lnworker.remove_channel(self.channel_id)
×
403

404
    def update_funded_state(self, *, funding_txid: str, funding_height: TxMinedInfo) -> None:
1✔
405
        self.save_funding_height(txid=funding_txid, height=funding_height.height(), timestamp=funding_height.timestamp)
×
406
        self.delete_closing_height()
×
407
        if funding_height.conf>0:
×
408
            self.set_short_channel_id(ShortChannelID.from_components(
×
409
                funding_height.height(), funding_height.txpos, self.funding_outpoint.output_index))
410
        if self.get_state() == ChannelState.OPENING:
×
411
            if self.is_funding_tx_mined(funding_height):
×
412
                self.set_state(ChannelState.FUNDED)
×
413
        elif self.is_zeroconf() and funding_height.conf >= 3 and not self.should_request_force_close:
×
414
            if not self.is_funding_tx_mined(funding_height):
×
415
                # funding tx is invalid (invalid amount or address) we need to get rid of the channel again
416
                self.should_request_force_close = True
×
417
                if self.lnworker and self.node_id in self.lnworker.peers:
×
418
                    # reconnect to trigger force close request
419
                    self.lnworker.peers[self.node_id].close_and_cleanup()
×
420
            else:
421
                # remove zeroconf flag as we are now confirmed, this is to prevent an electrum server causing
422
                # us to remove a channel later in update_unfunded_state by omitting its funding tx
423
                self.remove_zeroconf_flag()
×
424

425
    def update_closed_state(self, *, funding_txid: str, funding_height: TxMinedInfo,
1✔
426
                            closing_txid: str, closing_height: TxMinedInfo, keep_watching: bool) -> None:
427
        self.save_funding_height(txid=funding_txid, height=funding_height.height(), timestamp=funding_height.timestamp)
×
428
        self.save_closing_height(txid=closing_txid, height=closing_height.height(), timestamp=closing_height.timestamp)
×
429
        if funding_height.conf>0:
×
430
            self.set_short_channel_id(ShortChannelID.from_components(
×
431
                funding_height.height(), funding_height.txpos, self.funding_outpoint.output_index))
432
        if self.get_state() < ChannelState.CLOSED:
×
433
            conf = closing_height.conf
×
434
            if conf > 0:
×
435
                self.set_state(ChannelState.CLOSED)
×
436
                if self.lnworker:
×
437
                    self.lnworker.wallet.txbatcher.set_password_future(None)
×
438
            else:
439
                # we must not trust the server with unconfirmed transactions,
440
                # because the state transition is irreversible. if the remote
441
                # force closed, we remain OPEN until the closing tx is confirmed
442
                self.unconfirmed_closing_txid = closing_txid
×
443
                if self.lnworker:
×
444
                    util.trigger_callback('channel', self.lnworker.wallet, self)
×
445

446
        if self.get_state() == ChannelState.CLOSED and not keep_watching:
×
447
            self.set_state(ChannelState.REDEEMED)
×
448
            if self.lnworker and self.is_backup():
×
449
                # auto-remove redeemed backups
450
                self.lnworker.remove_channel_backup(self.channel_id)
×
451

452
    @abstractmethod
1✔
453
    def is_initiator(self) -> bool:
1✔
454
        pass
×
455

456
    @abstractmethod
1✔
457
    def is_public(self) -> bool:
1✔
458
        pass
×
459

460
    @abstractmethod
1✔
461
    def is_zeroconf(self) -> bool:
1✔
462
        pass
×
463

464
    @abstractmethod
1✔
465
    def remove_zeroconf_flag(self) -> None:
1✔
466
        pass
×
467

468
    @abstractmethod
1✔
469
    def is_funding_tx_mined(self, funding_height: TxMinedInfo) -> bool:
1✔
470
        pass
×
471

472
    @abstractmethod
1✔
473
    def get_funding_address(self) -> str:
1✔
474
        pass
×
475

476
    def get_funding_tx(self) -> Optional[Transaction]:
1✔
477
        funding_txid = self.funding_outpoint.txid
×
478
        return self.lnworker.lnwatcher.adb.get_transaction(funding_txid)
×
479

480
    @abstractmethod
1✔
481
    def get_sweep_address(self) -> str:
1✔
482
        """Returns a wallet address we can use to sweep coins to.
483
        It could be something static to the channel (fixed for its lifecycle),
484
        or it might just ask the wallet now for an unused address.
485
        """
486
        pass
×
487

488
    def get_state_for_GUI(self) -> str:
1✔
489
        cs = self.get_state()
×
490
        if cs <= ChannelState.OPEN and self.unconfirmed_closing_txid:
×
491
            return 'FORCE-CLOSING'
×
492
        return cs.name
×
493

494
    @abstractmethod
1✔
495
    def get_oldest_unrevoked_ctn(self, subject: HTLCOwner) -> int:
1✔
496
        pass
×
497

498
    @abstractmethod
1✔
499
    def included_htlcs(self, subject: HTLCOwner, direction: Direction, ctn: int = None) -> Sequence[UpdateAddHtlc]:
1✔
500
        pass
×
501

502
    @abstractmethod
1✔
503
    def funding_txn_minimum_depth(self) -> int:
1✔
504
        pass
×
505

506
    @abstractmethod
1✔
507
    def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
1✔
508
        """This balance (in msat) only considers HTLCs that have been settled by ctn.
509
        It disregards reserve, fees, and pending HTLCs (in both directions).
510
        """
511
        pass
×
512

513
    @abstractmethod
1✔
514
    def balance_minus_outgoing_htlcs(self, whose: HTLCOwner, *,
1✔
515
                                     ctx_owner: HTLCOwner = HTLCOwner.LOCAL,
516
                                     ctn: int = None) -> int:
517
        """This balance (in msat), which includes the value of
518
        pending outgoing HTLCs, is used in the UI.
519
        """
520
        pass
×
521

522
    @abstractmethod
1✔
523
    def is_frozen_for_sending(self) -> bool:
1✔
524
        """Whether the user has marked this channel as frozen for sending.
525
        Frozen channels are not supposed to be used for new outgoing payments.
526
        (note that payment-forwarding ignores this option)
527
        """
528
        pass
×
529

530
    @abstractmethod
1✔
531
    def is_frozen_for_receiving(self) -> bool:
1✔
532
        """Whether the user has marked this channel as frozen for receiving.
533
        Frozen channels are not supposed to be used for new incoming payments.
534
        (note that payment-forwarding ignores this option)
535
        """
536
        pass
×
537

538
    @abstractmethod
1✔
539
    def get_local_pubkey(self) -> bytes:
1✔
540
        """Returns our node ID."""
541
        pass
×
542

543
    @abstractmethod
1✔
544
    def get_capacity(self) -> Optional[int]:
1✔
545
        """Returns channel capacity in satoshis, or None if unknown."""
546
        pass
×
547

548
    @abstractmethod
1✔
549
    def can_be_deleted(self) -> bool:
1✔
550
        pass
×
551

552
    @abstractmethod
1✔
553
    def get_wallet_addresses_channel_might_want_reserved(self) -> Sequence[str]:
1✔
554
        """Returns a list of addrs that the wallet should not use, to avoid address-reuse.
555
        Typically, these addresses are wallet.is_mine, but that is not guaranteed,
556
        in which case the wallet can just ignore those.
557
        """
558
        pass
×
559

560
    def has_anchors(self) -> bool:
1✔
561
        pass
×
562

563

564
class ChannelBackup(AbstractChannel):
1✔
565
    """
566
    current capabilities:
567
      - detect force close
568
      - request force close
569
      - sweep my ctx to_local
570
    future:
571
      - will need to sweep their ctx to_remote
572
    """
573

574
    def __init__(self, cb: ChannelBackupStorage, *, lnworker=None):
1✔
575
        self.name = None
×
576
        self.cb = cb
×
577
        self.is_imported = isinstance(self.cb, ImportedChannelBackupStorage)
×
578
        self.storage = {} # dummy storage
×
579
        self._state = ChannelState.OPENING
×
580
        self.node_id = cb.node_id if self.is_imported else cb.node_id_prefix
×
581
        self.channel_id = cb.channel_id()
×
582
        self.funding_outpoint = cb.funding_outpoint()
×
583
        self.lnworker = lnworker
×
584
        self.short_channel_id = None
×
585
        Logger.__init__(self)
×
586
        self.config = {}
×
587
        if self.is_imported:
×
588
            assert isinstance(cb, ImportedChannelBackupStorage)
×
589
            self.init_config(cb)
×
590
        self.unconfirmed_closing_txid = None # not a state, only for GUI
×
591

592
    def init_config(self, cb: ImportedChannelBackupStorage):
1✔
593
        local_payment_pubkey = cb.local_payment_pubkey
×
594
        if local_payment_pubkey is None:
×
595
            self.logger.warning(
×
596
                f"local_payment_pubkey missing from (old-type) channel backup. "
597
                f"You should export and re-import a newer backup.")
598
        multisig_funding_keypair = None
×
599
        if multisig_funding_secret := cb.multisig_funding_privkey:
×
600
            multisig_funding_keypair = Keypair(
×
601
                privkey=multisig_funding_secret,
602
                pubkey=ecc.ECPrivkey(multisig_funding_secret).get_public_key_bytes(),
603
            )
604
        self.config[LOCAL] = LocalConfig.from_seed(
×
605
            channel_seed=cb.channel_seed,
606
            to_self_delay=cb.local_delay,
607
            # there are three cases of backups:
608
            # 1. legacy: payment_basepoint will be derived
609
            # 2. static_remotekey: to_remote sweep not necessary due to wallet address
610
            # 3. anchor outputs: sweep to_remote by deriving the key from the funding pubkeys
611
            static_remotekey=local_payment_pubkey,
612
            multisig_key=multisig_funding_keypair,
613
            # dummy values
614
            static_payment_key=None,
615
            dust_limit_sat=None,
616
            max_htlc_value_in_flight_msat=None,
617
            max_accepted_htlcs=None,
618
            initial_msat=None,
619
            reserve_sat=None,
620
            funding_locked_received=False,
621
            current_commitment_signature=None,
622
            current_htlc_signatures=b'',
623
            htlc_minimum_msat=1,
624
            upfront_shutdown_script='',
625
            announcement_node_sig=b'',
626
            announcement_bitcoin_sig=b'',
627
        )
628
        self.config[REMOTE] = RemoteConfig(
×
629
            # payment_basepoint needed to deobfuscate ctn in our_ctx
630
            payment_basepoint=OnlyPubkeyKeypair(cb.remote_payment_pubkey),
631
            # revocation_basepoint is used to claim to_local in our ctx
632
            revocation_basepoint=OnlyPubkeyKeypair(cb.remote_revocation_pubkey),
633
            to_self_delay=cb.remote_delay,
634
            # dummy values
635
            multisig_key=OnlyPubkeyKeypair(None),
636
            htlc_basepoint=OnlyPubkeyKeypair(None),
637
            delayed_basepoint=OnlyPubkeyKeypair(None),
638
            dust_limit_sat=None,
639
            max_htlc_value_in_flight_msat=None,
640
            max_accepted_htlcs=None,
641
            initial_msat = None,
642
            reserve_sat = None,
643
            htlc_minimum_msat=None,
644
            next_per_commitment_point=None,
645
            current_per_commitment_point=None,
646
            upfront_shutdown_script='',
647
            announcement_node_sig=b'',
648
            announcement_bitcoin_sig=b'',
649
        )
650

651
    def can_be_deleted(self):
1✔
652
        return self.is_imported or self.is_redeemed()
×
653

654
    def get_capacity(self):
1✔
655
        lnwatcher = self.lnworker.lnwatcher
×
656
        if lnwatcher:
×
657
            # fixme: we should probably not call that method here
658
            return lnwatcher.adb.get_tx_delta(self.funding_outpoint.txid, self.cb.funding_address)
×
659
        return None
×
660

661
    def is_backup(self):
1✔
662
        return True
×
663

664
    def create_sweeptxs_for_their_ctx(self, ctx):
1✔
665
        funding_tx = self.get_funding_tx()
×
666
        assert funding_tx
×
667
        return sweep_their_ctx_to_remote_backup(chan=self, ctx=ctx, funding_tx=funding_tx)
×
668

669
    def create_sweeptxs_for_our_ctx(self, ctx):
1✔
670
        if self.is_imported:
×
671
            return sweep_our_ctx(chan=self, ctx=ctx)
×
672
        else:
673
            return {}
×
674

675
    def maybe_sweep_htlcs(self, ctx: Transaction, htlc_tx: Transaction) -> Dict[str, SweepInfo]:
1✔
676
        return {}
×
677

678
    def extract_preimage_from_htlc_txin(self, txin: TxInput, *, is_deeply_mined: bool) -> None:
1✔
679
        return None
×
680

681
    def get_funding_address(self):
1✔
682
        return self.cb.funding_address
×
683

684
    def is_initiator(self):
1✔
685
        return self.cb.is_initiator
×
686

687
    def is_public(self):
1✔
688
        return False
×
689

690
    def get_oldest_unrevoked_ctn(self, who):
1✔
691
        return -1
×
692

693
    def included_htlcs(self, subject, direction, ctn=None):
1✔
694
        return []
×
695

696
    def funding_txn_minimum_depth(self):
1✔
697
        return 1
×
698

699
    def is_funding_tx_mined(self, funding_height):
1✔
700
        return funding_height.conf > 1
×
701

702
    def balance_minus_outgoing_htlcs(self, whose: HTLCOwner, *, ctx_owner: HTLCOwner = HTLCOwner.LOCAL, ctn: int = None):
1✔
703
        return 0
×
704

705
    def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
1✔
706
        return 0
×
707

708
    def is_frozen_for_sending(self) -> bool:
1✔
709
        return False
×
710

711
    def is_frozen_for_receiving(self) -> bool:
1✔
712
        return False
×
713

714
    def get_sweep_address(self) -> str:
1✔
715
        return self.lnworker.wallet.get_new_sweep_address_for_channel()
×
716

717
    def has_anchors(self) -> Optional[bool]:
1✔
718
        return None
×
719

720
    def is_zeroconf(self) -> bool:
1✔
721
        return False
×
722

723
    def remove_zeroconf_flag(self) -> None:
1✔
724
        pass
×
725

726
    def get_local_pubkey(self) -> bytes:
1✔
727
        cb = self.cb
×
728
        assert isinstance(cb, ChannelBackupStorage)
×
729
        if isinstance(cb, ImportedChannelBackupStorage):
×
730
            return ecc.ECPrivkey(cb.privkey).get_public_key_bytes(compressed=True)
×
731
        if isinstance(cb, OnchainChannelBackupStorage):
×
732
            return self.lnworker.node_keypair.pubkey
×
733
        raise NotImplementedError(f"unexpected cb type: {type(cb)}")
×
734

735
    def get_close_options(self) -> Sequence[ChanCloseOption]:
1✔
736
        ret = []
×
737
        if self.get_state() == ChannelState.FUNDED:
×
738
            ret.append(ChanCloseOption.REQUEST_REMOTE_FCLOSE)
×
739
        return ret
×
740

741
    def get_wallet_addresses_channel_might_want_reserved(self) -> Sequence[str]:
1✔
742
        if self.is_imported:
×
743
            # For v1 imported cbs, we have the local_payment_pubkey, which is
744
            # directly used as p2wpkh() of static_remotekey channels.
745
            # (for v0 imported cbs, the correct local_payment_pubkey is missing, and so
746
            #  we might calculate a different address here, which might not be wallet.is_mine,
747
            #  but that should be harmless)
748
            our_payment_pubkey = self.config[LOCAL].payment_basepoint.pubkey
×
749
            to_remote_address = make_commitment_output_to_remote_address(our_payment_pubkey, has_anchors=self.has_anchors())
×
750
            return [to_remote_address]
×
751
        else:  # on-chain backup
752
            return []
×
753

754

755
class Channel(AbstractChannel):
1✔
756
    # note: try to avoid naming ctns/ctxs/etc as "current" and "pending".
757
    #       they are ambiguous. Use "oldest_unrevoked" or "latest" or "next".
758
    #       TODO enforce this ^
759

760
    # our forwarding parameters for forwarding HTLCs through this channel
761
    forwarding_cltv_delta = 144
1✔
762
    forwarding_fee_base_msat = 1000
1✔
763
    forwarding_fee_proportional_millionths = 1
1✔
764

765
    def __repr__(self):
1✔
766
        return "Channel(%s)"%self.get_id_for_log()
×
767

768
    def __init__(self, state: 'StoredDict', *, name=None, lnworker=None, initial_feerate=None, opening_fee=None):
1✔
769
        self.opening_fee = opening_fee
1✔
770
        self.name = name
1✔
771
        self.channel_id = bfh(state["channel_id"])
1✔
772
        self.short_channel_id = ShortChannelID.normalize(state["short_channel_id"])
1✔
773
        Logger.__init__(self)  # should be after short_channel_id is set
1✔
774
        self.lnworker = lnworker
1✔
775
        self.storage = state
1✔
776
        self.db_lock = self.storage.lock
1✔
777
        self.config = {}
1✔
778
        self.config[LOCAL] = state["local_config"]
1✔
779
        self.config[REMOTE] = state["remote_config"]
1✔
780
        self.constraints = state["constraints"]  # type: ChannelConstraints
1✔
781
        self.funding_outpoint = state["funding_outpoint"]
1✔
782
        self.node_id = bfh(state["node_id"])
1✔
783
        self.onion_keys = state['onion_keys']  # type: Dict[int, bytes]
1✔
784
        self.data_loss_protect_remote_pcp = state['data_loss_protect_remote_pcp']
1✔
785
        self.hm = HTLCManager(log=state['log'], initial_feerate=initial_feerate)
1✔
786
        self.unfulfilled_htlcs = state["unfulfilled_htlcs"]  # type: Dict[int, Tuple[str, Optional[str]]]
1✔
787
        # ^ htlc_id -> onion_packet_hex, forwarding_key
788
        self._state = ChannelState[state['state']]
1✔
789
        self.peer_state = PeerState.DISCONNECTED
1✔
790
        self._outgoing_channel_update = None  # type: Optional[bytes]
1✔
791
        self.revocation_store = RevocationStore(state["revocation_store"])
1✔
792
        self._can_send_ctx_updates = True  # type: bool
1✔
793
        self._receive_fail_reasons = {}  # type: Dict[int, (bytes, OnionRoutingFailure)]
1✔
794
        self.unconfirmed_closing_txid = None # not a state, only for GUI
1✔
795
        self.sent_channel_ready = False # no need to persist this, because channel_ready is re-sent in channel_reestablish
1✔
796
        self.sent_announcement_signatures = False
1✔
797
        self.htlc_settle_time = {}
1✔
798

799
    def get_local_scid_alias(self, *, create_new_if_needed: bool = False) -> Optional[bytes]:
1✔
800
        """Get scid_alias to be used for *outgoing* HTLCs.
801
        (called local as we choose the value)
802
        """
803
        if alias := self.storage.get('local_scid_alias'):
1✔
804
            return bytes.fromhex(alias)
×
805
        elif create_new_if_needed:
1✔
806
            # deterministic, same secrecy level as wallet master pubkey
807
            wallet_fingerprint = bytes(self.lnworker.wallet.get_fingerprint(), "utf8")
1✔
808
            alias = sha256(wallet_fingerprint + self.channel_id)[0:8]
1✔
809
            self.storage['local_scid_alias'] = alias.hex()
1✔
810
            return alias
1✔
811
        return None
1✔
812

813
    def save_remote_scid_alias(self, alias: bytes):
1✔
814
        self.storage['alias'] = alias.hex()
1✔
815

816
    def get_remote_scid_alias(self) -> Optional[bytes]:
1✔
817
        """Get scid_alias to be used for *incoming* HTLCs.
818
        (called remote as the remote chooses the value)
819
        """
820
        alias = self.storage.get('alias')
1✔
821
        return bytes.fromhex(alias) if alias else None
1✔
822

823
    def get_scid_or_local_alias(self):
1✔
824
        return self.short_channel_id or self.get_local_scid_alias()
1✔
825

826
    def has_onchain_backup(self):
1✔
827
        return self.storage.get('has_onchain_backup', False)
×
828

829
    def can_be_deleted(self):
1✔
830
        return self.is_redeemed()
×
831

832
    def get_capacity(self):
1✔
833
        return self.constraints.capacity
×
834

835
    def is_public(self):
1✔
836
        return bool(self.constraints.flags & CF_ANNOUNCE_CHANNEL)
1✔
837

838
    def is_initiator(self):
1✔
839
        return self.constraints.is_initiator
1✔
840

841
    def is_active(self):
1✔
842
        return self.get_state() == ChannelState.OPEN and self.peer_state == PeerState.GOOD
1✔
843

844
    def funding_txn_minimum_depth(self):
1✔
845
        return self.constraints.funding_txn_minimum_depth
×
846

847
    def diagnostic_name(self):
1✔
848
        if self.name:
1✔
849
            return str(self.name)
1✔
850
        return super().diagnostic_name()
1✔
851

852
    def set_onion_key(self, key: int, value: bytes):
1✔
853
        self.onion_keys[key] = value
1✔
854

855
    def pop_onion_key(self, key: int) -> bytes:
1✔
856
        return self.onion_keys.pop(key)
1✔
857

858
    def set_data_loss_protect_remote_pcp(self, key, value):
1✔
859
        self.data_loss_protect_remote_pcp[key] = value
1✔
860

861
    def get_data_loss_protect_remote_pcp(self, key):
1✔
862
        return self.data_loss_protect_remote_pcp.get(key)
×
863

864
    def get_local_pubkey(self) -> bytes:
1✔
865
        if not self.lnworker:
1✔
866
            raise Exception('lnworker not set for channel!')
×
867
        return self.lnworker.node_keypair.pubkey
1✔
868

869
    def set_remote_update(self, payload: dict) -> None:
1✔
870
        """Save the ChannelUpdate message for the incoming direction of this channel.
871
        This message contains info we need to populate private route hints when
872
        creating invoices.
873
        """
874
        assert payload['short_channel_id'] in [self.short_channel_id, self.get_local_scid_alias()]
1✔
875
        from .channel_db import ChannelDB
1✔
876
        ChannelDB.verify_channel_update(payload, start_node=self.node_id)
1✔
877
        raw = payload['raw']
1✔
878
        self.storage['remote_update'] = raw.hex()
1✔
879

880
    def get_remote_update(self) -> Optional[bytes]:
1✔
881
        return bfh(self.storage.get('remote_update')) if self.storage.get('remote_update') else None
1✔
882

883
    def add_or_update_peer_addr(self, peer: LNPeerAddr) -> None:
1✔
884
        if 'peer_network_addresses' not in self.storage:
×
885
            self.storage['peer_network_addresses'] = {}
×
886
        self.storage['peer_network_addresses'][peer.net_addr_str()] = now()
×
887

888
    def get_peer_addresses(self) -> Iterator[LNPeerAddr]:
1✔
889
        # sort by timestamp: most recent first
890
        addrs = sorted(self.storage.get('peer_network_addresses', {}).items(),
×
891
                       key=lambda x: x[1], reverse=True)
892
        for net_addr_str, ts in addrs:
×
893
            net_addr = NetAddress.from_string(net_addr_str)
×
894
            yield LNPeerAddr(host=str(net_addr.host), port=net_addr.port, pubkey=self.node_id)
×
895

896
    def save_remote_peer_sent_error(self, original_error: bytes):
1✔
897
        # We save the original arbitrary text(/bytes) error, as received.
898
        # The length is only implicitly limited by the BOLT-08 max msg size.
899
        # Receiving an error usually results in the channel getting closed, so
900
        # there is likely no need to store multiple errors. We only store one, and overwrite.
901
        self.storage['remote_peer_sent_error'] = original_error.hex()
1✔
902

903
    def get_remote_peer_sent_error(self) -> Optional[str]:
1✔
904
        original_error = self.storage.get('remote_peer_sent_error')
×
905
        if not original_error:
×
906
            return None
×
907
        err_bytes = bytes.fromhex(original_error)
×
908
        safe_str = error_text_bytes_to_safe_str(err_bytes)   # note: truncates
×
909
        return safe_str
×
910

911
    def get_outgoing_gossip_channel_update(self, *, scid: ShortChannelID = None) -> bytes:
1✔
912
        """
913
        scid: to be put into the channel_update message instead of the real scid, as this might be an scid alias
914
        """
915
        if self._outgoing_channel_update is not None and scid is None:
1✔
916
            return self._outgoing_channel_update
1✔
917
        if not self.lnworker:
1✔
918
            raise Exception('lnworker not set for channel!')
×
919
        if scid is None:
1✔
920
            scid = self.short_channel_id
1✔
921
        sorted_node_ids = list(sorted([self.node_id, self.get_local_pubkey()]))
1✔
922
        channel_flags = b'\x00' if sorted_node_ids[0] == self.get_local_pubkey() else b'\x01'
1✔
923
        htlc_maximum_msat = min(self.config[REMOTE].max_htlc_value_in_flight_msat, 1000 * self.constraints.capacity)
1✔
924

925
        chan_upd = encode_msg(
1✔
926
            "channel_update",
927
            short_channel_id=scid,
928
            channel_flags=channel_flags,
929
            message_flags=b'\x01',
930
            cltv_expiry_delta=self.forwarding_cltv_delta,
931
            htlc_minimum_msat=self.config[REMOTE].htlc_minimum_msat,
932
            htlc_maximum_msat=htlc_maximum_msat,
933
            fee_base_msat=self.forwarding_fee_base_msat,
934
            fee_proportional_millionths=self.forwarding_fee_proportional_millionths,
935
            chain_hash=constants.net.rev_genesis_bytes(),
936
            timestamp=now(),
937
        )
938
        sighash = sha256d(chan_upd[2 + 64:])
1✔
939
        sig = ecc.ECPrivkey(self.lnworker.node_keypair.privkey).ecdsa_sign(sighash, sigencode=ecc.ecdsa_sig64_from_r_and_s)
1✔
940
        message_type, payload = decode_msg(chan_upd)
1✔
941
        payload['signature'] = sig
1✔
942
        chan_upd = encode_msg(message_type, **payload)
1✔
943

944
        self._outgoing_channel_update = chan_upd
1✔
945
        return chan_upd
1✔
946

947
    def construct_channel_announcement_without_sigs(self) -> Tuple[bytes, bool]:
1✔
948
        bitcoin_keys = [
1✔
949
            self.config[REMOTE].multisig_key.pubkey,
950
            self.config[LOCAL].multisig_key.pubkey]
951
        node_ids = [self.node_id, self.get_local_pubkey()]
1✔
952
        is_reverse = node_ids[0] > node_ids[1]
1✔
953
        if is_reverse:
1✔
954
            node_ids.reverse()
1✔
955
            bitcoin_keys.reverse()
1✔
956
        chan_ann = encode_msg(
1✔
957
            "channel_announcement",
958
            len=0,
959
            features=b'',
960
            chain_hash=constants.net.rev_genesis_bytes(),
961
            short_channel_id=self.short_channel_id,
962
            node_id_1=node_ids[0],
963
            node_id_2=node_ids[1],
964
            bitcoin_key_1=bitcoin_keys[0],
965
            bitcoin_key_2=bitcoin_keys[1],
966
        )
967
        return chan_ann, is_reverse
1✔
968

969
    def get_channel_announcement_hash(self):
1✔
970
        chan_ann, _ = self.construct_channel_announcement_without_sigs()
×
971
        return sha256d(chan_ann[256+2:])
×
972

973
    def is_static_remotekey_enabled(self) -> bool:
1✔
974
        channel_type = ChannelType(self.storage.get('channel_type'))
1✔
975
        return bool(channel_type & ChannelType.OPTION_STATIC_REMOTEKEY)
1✔
976

977
    def is_zeroconf(self) -> bool:
1✔
978
        channel_type = ChannelType(self.storage.get('channel_type'))
×
979
        return bool(channel_type & ChannelType.OPTION_ZEROCONF)
×
980

981
    def remove_zeroconf_flag(self) -> None:
1✔
982
        if not self.is_zeroconf():
×
983
            return
×
984
        channel_type = ChannelType(self.storage.get('channel_type'))
×
985
        self.storage['channel_type'] = channel_type & ~ChannelType.OPTION_ZEROCONF
×
986

987
    def get_sweep_address(self) -> str:
1✔
988
        # TODO: in case of unilateral close with pending HTLCs, this address will be reused
989
        if self.has_anchors():
1✔
990
            addr = self.lnworker.wallet.get_new_sweep_address_for_channel()
×
991
        elif self.is_static_remotekey_enabled():
1✔
992
            our_payment_pubkey = self.config[LOCAL].payment_basepoint.pubkey
1✔
993
            addr = make_commitment_output_to_remote_address(our_payment_pubkey, has_anchors=self.has_anchors())
1✔
994
        if self.lnworker:
1✔
995
            assert self.lnworker.wallet.is_mine(addr)
1✔
996
        return addr
1✔
997

998
    def has_anchors(self) -> bool:
1✔
999
        channel_type = ChannelType(self.storage.get('channel_type'))
1✔
1000
        return bool(channel_type & ChannelType.OPTION_ANCHORS_ZERO_FEE_HTLC_TX)
1✔
1001

1002
    def get_wallet_addresses_channel_might_want_reserved(self) -> Sequence[str]:
1✔
1003
        assert self.is_static_remotekey_enabled()
1✔
1004
        our_payment_pubkey = self.config[LOCAL].payment_basepoint.pubkey
1✔
1005
        to_remote_address = make_commitment_output_to_remote_address(our_payment_pubkey, has_anchors=self.has_anchors())
1✔
1006
        return [to_remote_address]
1✔
1007

1008
    def get_feerate(self, subject: HTLCOwner, *, ctn: int) -> int:
1✔
1009
        # returns feerate in sat/kw
1010
        return self.hm.get_feerate(subject, ctn)
1✔
1011

1012
    def get_oldest_unrevoked_feerate(self, subject: HTLCOwner) -> int:
1✔
1013
        return self.hm.get_feerate_in_oldest_unrevoked_ctx(subject)
1✔
1014

1015
    def get_latest_feerate(self, subject: HTLCOwner) -> int:
1✔
1016
        return self.hm.get_feerate_in_latest_ctx(subject)
1✔
1017

1018
    def get_next_feerate(self, subject: HTLCOwner) -> int:
1✔
1019
        return self.hm.get_feerate_in_next_ctx(subject)
1✔
1020

1021
    def get_payments(self, status=None) -> Mapping[bytes, List[HTLCWithStatus]]:
1✔
1022
        out = defaultdict(list)
1✔
1023
        for direction, htlc in self.hm.all_htlcs_ever():
1✔
1024
            htlc_proposer = LOCAL if direction is SENT else REMOTE
1✔
1025
            if self.hm.was_htlc_failed(htlc_id=htlc.htlc_id, htlc_proposer=htlc_proposer):
1✔
1026
                _status = 'failed'
1✔
1027
            elif self.hm.was_htlc_preimage_released(htlc_id=htlc.htlc_id, htlc_proposer=htlc_proposer):
1✔
1028
                _status = 'settled'
1✔
1029
            else:
1030
                _status = 'inflight'
1✔
1031
            if status and status != _status:
1✔
1032
                continue
1✔
1033
            htlc_with_status = HTLCWithStatus(
1✔
1034
                channel_id=self.channel_id, htlc=htlc, direction=direction, status=_status)
1035
            out[htlc.payment_hash].append(htlc_with_status)
1✔
1036
        return out
1✔
1037

1038
    def open_with_first_pcp(self, remote_pcp: bytes, remote_sig: bytes) -> None:
1✔
1039
        with self.db_lock:
1✔
1040
            self.config[REMOTE].current_per_commitment_point = remote_pcp
1✔
1041
            self.config[REMOTE].next_per_commitment_point = None
1✔
1042
            self.config[LOCAL].current_commitment_signature = remote_sig
1✔
1043
            self.hm.channel_open_finished()
1✔
1044
            self.peer_state = PeerState.GOOD
1✔
1045

1046
    def get_state_for_GUI(self):
1✔
1047
        cs_name = super().get_state_for_GUI()
×
1048
        if self.is_closed() or self.unconfirmed_closing_txid:
×
1049
            return cs_name
×
1050
        ps = self.peer_state
×
1051
        if ps != PeerState.GOOD:
×
1052
            return ps.name
×
1053
        return cs_name
×
1054

1055
    def set_can_send_ctx_updates(self, b: bool) -> None:
1✔
1056
        self._can_send_ctx_updates = b
1✔
1057

1058
    def can_update_ctx(self, *, proposer: HTLCOwner) -> bool:
1✔
1059
        """Whether proposer is allowed to send commitment_signed, revoke_and_ack,
1060
        and update_* messages.
1061
        """
1062
        if self.get_state() not in (ChannelState.OPEN, ChannelState.SHUTDOWN):
1✔
1063
            return False
1✔
1064
        if self.peer_state != PeerState.GOOD:
1✔
1065
            return False
×
1066
        if proposer == LOCAL:
1✔
1067
            if not self._can_send_ctx_updates:
1✔
1068
                return False
×
1069
        return True
1✔
1070

1071
    def can_send_update_add_htlc(self) -> bool:
1✔
1072
        return self.can_update_ctx(proposer=LOCAL) and self.is_open()
1✔
1073

1074
    def is_frozen_for_sending(self) -> bool:
1✔
1075
        if self.lnworker and self.lnworker.uses_trampoline() and not self.lnworker.is_trampoline_peer(self.node_id):
1✔
1076
            return True
×
1077
        return self.storage.get('frozen_for_sending', False)
1✔
1078

1079
    def set_frozen_for_sending(self, b: bool) -> None:
1✔
1080
        self.storage['frozen_for_sending'] = bool(b)
×
1081
        util.trigger_callback('channel', self.lnworker.wallet, self)
×
1082

1083
    def is_frozen_for_receiving(self) -> bool:
1✔
1084
        if self.lnworker and self.lnworker.uses_trampoline() and not self.lnworker.is_trampoline_peer(self.node_id):
1✔
1085
            return True
×
1086
        return self.storage.get('frozen_for_receiving', False)
1✔
1087

1088
    def set_frozen_for_receiving(self, b: bool) -> None:
1✔
1089
        self.storage['frozen_for_receiving'] = bool(b)
×
1090
        util.trigger_callback('channel', self.lnworker.wallet, self)
×
1091

1092
    def _assert_can_add_htlc(self, *, htlc_proposer: HTLCOwner, amount_msat: int,
1✔
1093
                             ignore_min_htlc_value: bool = False) -> None:
1094
        """Raises PaymentFailure if the htlc_proposer cannot add this new HTLC.
1095
        (this is relevant both for forwarding and endpoint)
1096
        """
1097
        htlc_receiver = htlc_proposer.inverted()
1✔
1098
        # note: all these tests are about the *receiver's* *next* commitment transaction,
1099
        #       and the constraints are the ones imposed by their config
1100
        ctn = self.get_next_ctn(htlc_receiver)
1✔
1101
        chan_config = self.config[htlc_receiver]
1✔
1102
        if self.get_state() != ChannelState.OPEN:
1✔
1103
            raise PaymentFailure(f"Channel not open. {self.get_state()!r}")
×
1104
        if not self.can_update_ctx(proposer=htlc_proposer):
1✔
1105
            raise PaymentFailure(f"cannot update channel. {self.get_state()!r} {self.peer_state!r}")
×
1106
        if htlc_proposer == LOCAL:
1✔
1107
            if not self.can_send_update_add_htlc():
1✔
1108
                raise PaymentFailure('Channel cannot add htlc')
×
1109

1110
        # check htlc raw value
1111
        if not ignore_min_htlc_value:
1✔
1112
            if amount_msat <= 0:
1✔
1113
                raise PaymentFailure("HTLC value must be positive")
×
1114
            if amount_msat < chan_config.htlc_minimum_msat:
1✔
1115
                raise PaymentFailure(f'HTLC value too small: {amount_msat} msat')
×
1116

1117
        if self.htlc_slots_left(htlc_proposer) == 0:
1✔
1118
            raise PaymentFailure('Too many HTLCs already in channel')
×
1119

1120
        if amount_msat > self.remaining_max_inflight(htlc_receiver, strict=False):
1✔
1121
            raise PaymentFailure(
1✔
1122
                f'HTLC value sum (sum of pending htlcs plus new htlc) '
1123
                f'would exceed max allowed: {chan_config.max_htlc_value_in_flight_msat/1000} sat')
1124

1125
        # check proposer can afford htlc
1126
        max_can_send_msat = self.available_to_spend(htlc_proposer)
1✔
1127
        if max_can_send_msat < amount_msat:
1✔
1128
            raise PaymentFailure(f'Not enough balance. can send: {max_can_send_msat}, tried: {amount_msat}')
1✔
1129

1130
    def htlc_slots_left(self, htlc_proposer: HTLCOwner) -> int:
1✔
1131
        # check "max_accepted_htlcs"
1132
        htlc_receiver = htlc_proposer.inverted()
1✔
1133
        ctn = self.get_next_ctn(htlc_receiver)
1✔
1134
        chan_config = self.config[htlc_receiver]
1✔
1135
        # If proposer is LOCAL we apply stricter checks as that is behaviour we can control.
1136
        # This should lead to fewer disagreements (i.e. channels failing).
1137
        strict = (htlc_proposer == LOCAL)
1✔
1138
        if not strict:
1✔
1139
            # this is the loose check BOLT-02 specifies:
1140
            return chan_config.max_accepted_htlcs - len(self.hm.htlcs_by_direction(htlc_receiver, direction=RECEIVED, ctn=ctn))
1✔
1141
        else:
1142
            # however, c-lightning is a lot stricter, so extra checks:
1143
            # https://github.com/ElementsProject/lightning/blob/4dcd4ca1556b13b6964a10040ba1d5ef82de4788/channeld/full_channel.c#L581
1144
            max_concurrent_htlcs = min(
1✔
1145
                self.config[htlc_proposer].max_accepted_htlcs,
1146
                self.config[htlc_receiver].max_accepted_htlcs)
1147
            return max_concurrent_htlcs - len(self.hm.htlcs(htlc_receiver, ctn=ctn))
1✔
1148

1149
    def remaining_max_inflight(self, htlc_receiver: HTLCOwner, *, strict: bool) -> int:
1✔
1150
        """
1151
        Checks max_htlc_value_in_flight_msat
1152
        strict = False -> how much we can accept according to BOLT2
1153
        strict = True -> how much the remote will accept to send to us (Eclair has stricter rules)
1154
        """
1155
        ctn = self.get_next_ctn(htlc_receiver)
1✔
1156
        current_htlc_sum = htlcsum(self.hm.htlcs_by_direction(htlc_receiver, direction=RECEIVED, ctn=ctn).values())
1✔
1157
        max_inflight = self.config[htlc_receiver].max_htlc_value_in_flight_msat
1✔
1158
        if strict and htlc_receiver == LOCAL:
1✔
1159
            # in order to send, eclair applies both local and remote max values
1160
            # https://github.com/ACINQ/eclair/blob/9b0c00a2a28d3ba6c7f3d01fbd2d8704ebbdc75d/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala#L503
1161
            max_inflight = min(
1✔
1162
                self.config[LOCAL].max_htlc_value_in_flight_msat,
1163
                self.config[REMOTE].max_htlc_value_in_flight_msat
1164
            )
1165
        return max_inflight - current_htlc_sum
1✔
1166

1167
    def can_pay(self, amount_msat: int, *, check_frozen=False) -> bool:
1✔
1168
        """Returns whether we can add an HTLC of given value."""
1169
        if check_frozen and self.is_frozen_for_sending():
1✔
1170
            return False
×
1171
        try:
1✔
1172
            self._assert_can_add_htlc(htlc_proposer=LOCAL, amount_msat=amount_msat)
1✔
1173
        except PaymentFailure:
1✔
1174
            return False
1✔
1175
        return True
1✔
1176

1177
    def can_receive(self, amount_msat: int, *, check_frozen=False,
1✔
1178
                    ignore_min_htlc_value: bool = False) -> bool:
1179
        """Returns whether the remote can add an HTLC of given value."""
1180
        if check_frozen and self.is_frozen_for_receiving():
×
1181
            return False
×
1182
        try:
×
1183
            self._assert_can_add_htlc(
×
1184
                htlc_proposer=REMOTE,
1185
                amount_msat=amount_msat,
1186
                ignore_min_htlc_value=ignore_min_htlc_value)
1187
        except PaymentFailure:
×
1188
            return False
×
1189
        return True
×
1190

1191
    def should_try_to_reestablish_peer(self) -> bool:
1✔
1192
        if self.peer_state != PeerState.DISCONNECTED:
×
1193
            return False
×
1194
        if self.should_request_force_close:
×
1195
            return True
×
1196
        return ChannelState.PREOPENING < self._state < ChannelState.CLOSING
×
1197

1198
    def get_funding_address(self):
1✔
1199
        script = funding_output_script(self.config[LOCAL], self.config[REMOTE])
1✔
1200
        return redeem_script_to_address('p2wsh', script)
1✔
1201

1202
    def add_htlc(self, htlc: UpdateAddHtlc) -> UpdateAddHtlc:
1✔
1203
        """Adds a new LOCAL HTLC to the channel.
1204
        Action must be initiated by LOCAL.
1205
        """
1206
        assert isinstance(htlc, UpdateAddHtlc)
1✔
1207
        self._assert_can_add_htlc(htlc_proposer=LOCAL, amount_msat=htlc.amount_msat)
1✔
1208
        if htlc.htlc_id is None:
1✔
1209
            htlc = dataclasses.replace(htlc, htlc_id=self.hm.get_next_htlc_id(LOCAL))
1✔
1210
        with self.db_lock:
1✔
1211
            self.hm.send_htlc(htlc)
1✔
1212
        self.logger.info("add_htlc")
1✔
1213
        return htlc
1✔
1214

1215
    def receive_htlc(self, htlc: UpdateAddHtlc, onion_packet:bytes = None) -> UpdateAddHtlc:
1✔
1216
        """Adds a new REMOTE HTLC to the channel.
1217
        Action must be initiated by REMOTE.
1218
        """
1219
        assert isinstance(htlc, UpdateAddHtlc)
1✔
1220
        try:
1✔
1221
            self._assert_can_add_htlc(htlc_proposer=REMOTE, amount_msat=htlc.amount_msat)
1✔
1222
        except PaymentFailure as e:
×
1223
            raise RemoteMisbehaving(e) from e
×
1224
        if htlc.htlc_id is None:  # used in unit tests
1✔
1225
            htlc = dataclasses.replace(htlc, htlc_id=self.hm.get_next_htlc_id(REMOTE))
1✔
1226
        with self.db_lock:
1✔
1227
            self.hm.recv_htlc(htlc)
1✔
1228
            if onion_packet:
1✔
1229
                self.unfulfilled_htlcs[htlc.htlc_id] = onion_packet.hex(), None
1✔
1230

1231
        self.logger.info("receive_htlc")
1✔
1232
        return htlc
1✔
1233

1234
    def sign_next_commitment(self) -> Tuple[bytes, Sequence[bytes]]:
1✔
1235
        """Returns signatures for our next remote commitment tx.
1236
        Action must be initiated by LOCAL.
1237
        Finally, the next remote ctx becomes the latest remote ctx.
1238
        """
1239
        # TODO: when more channel types are supported, this method should depend on channel type
1240
        next_remote_ctn = self.get_next_ctn(REMOTE)
1✔
1241
        self.logger.info(f"sign_next_commitment. ctn={next_remote_ctn}")
1✔
1242
        assert not self.is_closed(), self.get_state()
1✔
1243

1244
        pending_remote_commitment = self.get_next_commitment(REMOTE)
1✔
1245
        sig_64 = sign_and_get_sig_string(pending_remote_commitment, self.config[LOCAL], self.config[REMOTE])
1✔
1246
        self.logger.debug(f"sign_next_commitment. {pending_remote_commitment.serialize()=}. {sig_64.hex()=}")
1✔
1247

1248
        their_remote_htlc_privkey_number = derive_privkey(
1✔
1249
            int.from_bytes(self.config[LOCAL].htlc_basepoint.privkey, 'big'),
1250
            self.config[REMOTE].next_per_commitment_point)
1251
        their_remote_htlc_privkey = their_remote_htlc_privkey_number.to_bytes(32, 'big')
1✔
1252

1253
        htlcsigs = []
1✔
1254
        htlc_to_ctx_output_idx_map = map_htlcs_to_ctx_output_idxs(chan=self,
1✔
1255
                                                                  ctx=pending_remote_commitment,
1256
                                                                  pcp=self.config[REMOTE].next_per_commitment_point,
1257
                                                                  subject=REMOTE,
1258
                                                                  ctn=next_remote_ctn)
1259
        for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items():
1✔
1260
            _script, htlc_tx = make_htlc_tx_with_open_channel(chan=self,
1✔
1261
                                                              pcp=self.config[REMOTE].next_per_commitment_point,
1262
                                                              subject=REMOTE,
1263
                                                              ctn=next_remote_ctn,
1264
                                                              htlc_direction=direction,
1265
                                                              commit=pending_remote_commitment,
1266
                                                              ctx_output_idx=ctx_output_idx,
1267
                                                              htlc=htlc)
1268
            if self.has_anchors():
1✔
1269
                # we send a signature with the following sighash flags
1270
                # for the peer to be able to replace inputs and outputs
1271
                htlc_tx.inputs()[0].sighash = Sighash.ANYONECANPAY | Sighash.SINGLE
1✔
1272
            sig = htlc_tx.sign_txin(0, their_remote_htlc_privkey)
1✔
1273
            htlc_sig = ecc.ecdsa_sig64_from_der_sig(sig[:-1])
1✔
1274
            htlcsigs.append((ctx_output_idx, htlc_sig))
1✔
1275
        htlcsigs.sort()
1✔
1276
        htlcsigs = [x[1] for x in htlcsigs]
1✔
1277
        with self.db_lock:
1✔
1278
            self.hm.send_ctx()
1✔
1279
        return sig_64, htlcsigs
1✔
1280

1281
    def receive_new_commitment(self, sig: bytes, htlc_sigs: Sequence[bytes]) -> None:
1✔
1282
        """Processes signatures for our next local commitment tx, sent by the REMOTE.
1283
        Action must be initiated by REMOTE.
1284
        If all checks pass, the next local ctx becomes the latest local ctx.
1285
        """
1286
        # TODO in many failure cases below, we should "fail" the channel (force-close)
1287
        # TODO: when more channel types are supported, this method should depend on channel type
1288
        next_local_ctn = self.get_next_ctn(LOCAL)
1✔
1289
        self.logger.info(f"receive_new_commitment. ctn={next_local_ctn}, len(htlc_sigs)={len(htlc_sigs)}")
1✔
1290
        assert not self.is_closed(), self.get_state()
1✔
1291

1292
        assert len(htlc_sigs) == 0 or type(htlc_sigs[0]) is bytes
1✔
1293

1294
        pending_local_commitment = self.get_next_commitment(LOCAL)
1✔
1295
        pre_hash = pending_local_commitment.serialize_preimage(0)
1✔
1296
        msg_hash = sha256d(pre_hash)
1✔
1297
        if not ECPubkey(self.config[REMOTE].multisig_key.pubkey).ecdsa_verify(sig, msg_hash):
1✔
1298
            raise LNProtocolWarning(
×
1299
                f'failed verifying signature for our updated commitment transaction. '
1300
                f'sig={sig.hex()}. '
1301
                f'msg_hash={msg_hash.hex()}. '
1302
                f'pubkey={self.config[REMOTE].multisig_key.pubkey}. '
1303
                f'ctx={pending_local_commitment.serialize()} '
1304
            )
1305

1306
        htlc_sigs_string = b''.join(htlc_sigs)
1✔
1307

1308
        _secret, pcp = self.get_secret_and_point(subject=LOCAL, ctn=next_local_ctn)
1✔
1309

1310
        htlc_to_ctx_output_idx_map = map_htlcs_to_ctx_output_idxs(chan=self,
1✔
1311
                                                                  ctx=pending_local_commitment,
1312
                                                                  pcp=pcp,
1313
                                                                  subject=LOCAL,
1314
                                                                  ctn=next_local_ctn)
1315
        if len(htlc_to_ctx_output_idx_map) != len(htlc_sigs):
1✔
1316
            raise LNProtocolWarning(f'htlc sigs failure. recv {len(htlc_sigs)} sigs, expected {len(htlc_to_ctx_output_idx_map)}')
×
1317
        for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items():
1✔
1318
            htlc_sig = htlc_sigs[htlc_relative_idx]
1✔
1319
            self._verify_htlc_sig(htlc=htlc,
1✔
1320
                                  htlc_sig=htlc_sig,
1321
                                  htlc_direction=direction,
1322
                                  pcp=pcp,
1323
                                  ctx=pending_local_commitment,
1324
                                  ctx_output_idx=ctx_output_idx,
1325
                                  ctn=next_local_ctn)
1326
        with self.db_lock:
1✔
1327
            self.hm.recv_ctx()
1✔
1328
            self.config[LOCAL].current_commitment_signature=sig
1✔
1329
            self.config[LOCAL].current_htlc_signatures=htlc_sigs_string
1✔
1330

1331
    def _verify_htlc_sig(self, *, htlc: UpdateAddHtlc, htlc_sig: bytes, htlc_direction: Direction,
1✔
1332
                         pcp: bytes, ctx: Transaction, ctx_output_idx: int, ctn: int) -> None:
1333
        _script, htlc_tx = make_htlc_tx_with_open_channel(chan=self,
1✔
1334
                                                          pcp=pcp,
1335
                                                          subject=LOCAL,
1336
                                                          ctn=ctn,
1337
                                                          htlc_direction=htlc_direction,
1338
                                                          commit=ctx,
1339
                                                          ctx_output_idx=ctx_output_idx,
1340
                                                          htlc=htlc)
1341
        if self.has_anchors():
1✔
1342
            # peer sent us a signature for our ctx using anchor sighash flags
1343
            htlc_tx.inputs()[0].sighash = Sighash.ANYONECANPAY | Sighash.SINGLE
1✔
1344
        pre_hash = htlc_tx.serialize_preimage(0)
1✔
1345
        msg_hash = sha256d(pre_hash)
1✔
1346
        remote_htlc_pubkey = derive_pubkey(self.config[REMOTE].htlc_basepoint.pubkey, pcp)
1✔
1347
        if not ECPubkey(remote_htlc_pubkey).ecdsa_verify(htlc_sig, msg_hash):
1✔
1348
            raise LNProtocolWarning(
×
1349
                f'failed verifying HTLC signatures: {htlc=}, {htlc_direction=}. '
1350
                f'htlc_tx={htlc_tx.serialize()}. '
1351
                f'htlc_sig={htlc_sig.hex()}. '
1352
                f'remote_htlc_pubkey={remote_htlc_pubkey.hex()}. '
1353
                f'msg_hash={msg_hash.hex()}. '
1354
                f'ctx={ctx.serialize()}. '
1355
                f'ctx_output_idx={ctx_output_idx}. '
1356
                f'ctn={ctn}. '
1357
            )
1358

1359
    def get_remote_htlc_sig_for_htlc(self, *, htlc_relative_idx: int) -> bytes:
1✔
1360
        data = self.config[LOCAL].current_htlc_signatures
×
1361
        htlc_sigs = list(chunks(data, 64))
×
1362
        htlc_sig = htlc_sigs[htlc_relative_idx]
×
1363
        remote_sighash = Sighash.ALL if not self.has_anchors() else Sighash.ANYONECANPAY | Sighash.SINGLE
×
1364
        remote_htlc_sig = ecc.ecdsa_der_sig_from_ecdsa_sig64(htlc_sig) + Sighash.to_sigbytes(remote_sighash)
×
1365
        return remote_htlc_sig
×
1366

1367
    def revoke_current_commitment(self):
1✔
1368
        self.logger.info("revoke_current_commitment")
1✔
1369
        assert not self.is_closed(), self.get_state()
1✔
1370
        new_ctn = self.get_latest_ctn(LOCAL)
1✔
1371
        new_ctx = self.get_latest_commitment(LOCAL)
1✔
1372
        if not self.signature_fits(new_ctx):
1✔
1373
            # this should never fail; as receive_new_commitment already did this test
1374
            raise Exception("refusing to revoke as remote sig does not fit")
×
1375
        with self.db_lock:
1✔
1376
            self.hm.send_rev()
1✔
1377
        last_secret, last_point = self.get_secret_and_point(LOCAL, new_ctn - 1)
1✔
1378
        next_secret, next_point = self.get_secret_and_point(LOCAL, new_ctn + 1)
1✔
1379
        return RevokeAndAck(last_secret, next_point)
1✔
1380

1381
    def receive_revocation(self, revocation: RevokeAndAck):
1✔
1382
        self.logger.info("receive_revocation")
1✔
1383
        assert not self.is_closed(), self.get_state()
1✔
1384
        new_ctn = self.get_latest_ctn(REMOTE)
1✔
1385
        cur_point = self.config[REMOTE].current_per_commitment_point
1✔
1386
        derived_point = ecc.ECPrivkey(revocation.per_commitment_secret).get_public_key_bytes(compressed=True)
1✔
1387
        if cur_point != derived_point:
1✔
1388
            raise Exception('revoked secret not for current point')
×
1389
        with self.db_lock:
1✔
1390
            self.revocation_store.add_next_entry(revocation.per_commitment_secret)
1✔
1391
            ##### start applying fee/htlc changes
1392
            self.hm.recv_rev()
1✔
1393
            self.config[REMOTE].current_per_commitment_point=self.config[REMOTE].next_per_commitment_point
1✔
1394
            self.config[REMOTE].next_per_commitment_point=revocation.next_per_commitment_point
1✔
1395
        assert new_ctn == self.get_oldest_unrevoked_ctn(REMOTE)
1✔
1396
        # lnworker callbacks
1397
        if self.lnworker:
1✔
1398
            sent = self.hm.sent_in_ctn(new_ctn)
1✔
1399
            for htlc in sent:
1✔
1400
                self.lnworker.htlc_fulfilled(self, htlc.payment_hash, htlc.htlc_id)
1✔
1401
            failed = self.hm.failed_in_ctn(new_ctn)
1✔
1402
            for htlc in failed:
1✔
1403
                try:
1✔
1404
                    error_bytes, failure_message = self._receive_fail_reasons.pop(htlc.htlc_id)
1✔
1405
                except KeyError:
×
1406
                    error_bytes, failure_message = None, None
×
1407
                self.lnworker.htlc_failed(self, htlc.payment_hash, htlc.htlc_id, error_bytes, failure_message)
1✔
1408

1409
    def extract_preimage_from_htlc_txin(self, txin: TxInput, *, is_deeply_mined: bool) -> None:
1✔
1410
        from . import lnutil
×
1411
        from .crypto import ripemd
×
1412
        from .transaction import match_script_against_template, script_GetOp
×
1413
        from .lnonion import OnionRoutingFailure, OnionFailureCode
×
1414
        witness = txin.witness_elements()
×
1415
        witness_script = witness[-1]
×
1416
        script_ops = [x for x in script_GetOp(witness_script)]
×
1417
        if match_script_against_template(witness_script, lnutil.WITNESS_TEMPLATE_OFFERED_HTLC, debug=False) \
×
1418
           or match_script_against_template(witness_script, lnutil.WITNESS_TEMPLATE_OFFERED_HTLC_ANCHORS, debug=False):
1419
            ripemd_payment_hash = script_ops[21][1]
×
1420
        elif match_script_against_template(witness_script, lnutil.WITNESS_TEMPLATE_RECEIVED_HTLC, debug=False) \
×
1421
           or match_script_against_template(witness_script, lnutil.WITNESS_TEMPLATE_RECEIVED_HTLC_ANCHORS, debug=False):
1422
            ripemd_payment_hash = script_ops[14][1]
×
1423
        else:
1424
            return
×
1425
        found = {}
×
1426
        for direction, htlc in itertools.chain(
×
1427
                self.hm.get_htlcs_in_oldest_unrevoked_ctx(REMOTE),
1428
                self.hm.get_htlcs_in_latest_ctx(REMOTE)):
1429
            if ripemd(htlc.payment_hash) == ripemd_payment_hash:
×
1430
                is_sent = direction == RECEIVED
×
1431
                found[htlc.htlc_id] = (htlc, is_sent)
×
1432
        for direction, htlc in itertools.chain(
×
1433
                self.hm.get_htlcs_in_oldest_unrevoked_ctx(LOCAL),
1434
                self.hm.get_htlcs_in_latest_ctx(LOCAL)):
1435
            if ripemd(htlc.payment_hash) == ripemd_payment_hash:
×
1436
                is_sent = direction == SENT
×
1437
                found[htlc.htlc_id] = (htlc, is_sent)
×
1438
        if not found:
×
1439
            return
×
1440
        if len(witness) == 5:    # HTLC success tx
×
1441
            preimage = witness[3]
×
1442
        elif len(witness) == 3:  # spending offered HTLC directly from ctx
×
1443
            preimage = witness[1]
×
1444
        else:
1445
            preimage = None      # HTLC timeout tx
×
1446
        if preimage:
×
1447
            assert ripemd(sha256(preimage)) == ripemd_payment_hash
×
1448
            payment_hash = sha256(preimage)
×
1449
            if self.lnworker.get_preimage(payment_hash) is not None:
×
1450
                return
×
1451
            # ^ note: log message text grepped for in regtests
1452
            self.logger.info(f"found preimage in witness of length {len(witness)}, for {payment_hash.hex()}")
×
1453

1454
        # Mark the htlc as fulfilled or failed.
1455
        # If we forwarded this, this ensures that the success/failure is propagated back on the incoming channel.
1456
        # FIXME we only look at outgoing htlcs that have a corresponding output in the commitment tx,
1457
        #       however we should also look at those that do not. E.g. a small value htlc might not create an output
1458
        #       but we should still propagate back success or failure on the incoming link. And it is not just about
1459
        #       small value htlcs: even a large htlc might not appear in the outgoing channel's ctx, e.g. maybe it was
1460
        #       not committed yet - we should still make sure it gets removed on the incoming channel. (see #9631)
1461
        if preimage:
×
1462
            self.lnworker.save_preimage(payment_hash, preimage)
×
1463
            for htlc, is_sent in found.values():
×
1464
                if is_sent:
×
1465
                    self.lnworker.htlc_fulfilled(self, payment_hash, htlc.htlc_id)
×
1466
        else:
1467
            # htlc timeout tx
1468
            if not is_deeply_mined:
×
1469
                return
×
1470
            failure = OnionRoutingFailure(code=OnionFailureCode.PERMANENT_CHANNEL_FAILURE, data=b'')
×
1471
            for htlc, is_sent in found.values():
×
1472
                if is_sent:
×
1473
                    self.logger.info(f'htlc timeout tx: failing htlc {is_sent}')
×
1474
                    self.lnworker.htlc_failed(
×
1475
                        self,
1476
                        payment_hash=htlc.payment_hash,
1477
                        htlc_id=htlc.htlc_id,
1478
                        error_bytes=None,
1479
                        failure_message=failure)
1480

1481
    def balance(self, whose: HTLCOwner, *, ctx_owner=HTLCOwner.LOCAL, ctn: int = None) -> int:
1✔
1482
        assert type(whose) is HTLCOwner
1✔
1483
        initial = self.config[whose].initial_msat
1✔
1484
        return self.hm.get_balance_msat(whose=whose,
1✔
1485
                                        ctx_owner=ctx_owner,
1486
                                        ctn=ctn,
1487
                                        initial_balance_msat=initial)
1488

1489
    def balance_minus_outgoing_htlcs(self, whose: HTLCOwner, *, ctx_owner: HTLCOwner = HTLCOwner.LOCAL,
1✔
1490
                                     ctn: int = None) -> int:
1491
        assert type(whose) is HTLCOwner
1✔
1492
        if ctn is None:
1✔
1493
            ctn = self.get_next_ctn(ctx_owner)
1✔
1494
        committed_balance = self.balance(whose, ctx_owner=ctx_owner, ctn=ctn)
1✔
1495
        direction = RECEIVED if whose != ctx_owner else SENT
1✔
1496
        balance_in_htlcs = self.balance_tied_up_in_htlcs_by_direction(ctx_owner, ctn=ctn, direction=direction)
1✔
1497
        return committed_balance - balance_in_htlcs
1✔
1498

1499
    def balance_tied_up_in_htlcs_by_direction(self, ctx_owner: HTLCOwner = LOCAL, *, ctn: int = None,
1✔
1500
                                              direction: Direction):
1501
        # in msat
1502
        if ctn is None:
1✔
1503
            ctn = self.get_next_ctn(ctx_owner)
×
1504
        return htlcsum(self.hm.htlcs_by_direction(ctx_owner, direction, ctn).values())
1✔
1505

1506
    def has_unsettled_htlcs(self) -> bool:
1✔
1507
        return len(self.hm.htlcs(LOCAL)) + len(self.hm.htlcs(REMOTE)) > 0
1✔
1508

1509
    def available_to_spend(self, subject: HTLCOwner) -> int:
1✔
1510
        """The usable balance of 'subject' in msat, after taking reserve and fees (and anchors) into
1511
        consideration. Note that fees (and hence the result) fluctuate even without user interaction.
1512
        """
1513
        assert type(subject) is HTLCOwner
1✔
1514
        sender = subject
1✔
1515
        receiver = subject.inverted()
1✔
1516
        initiator = LOCAL if self.constraints.is_initiator else REMOTE  # the initiator/funder pays on-chain fees
1✔
1517

1518
        def consider_ctx(*, ctx_owner: HTLCOwner, is_htlc_dust: bool) -> int:
1✔
1519
            ctn = self.get_next_ctn(ctx_owner)
1✔
1520
            sender_balance_msat = self.balance_minus_outgoing_htlcs(whose=sender, ctx_owner=ctx_owner, ctn=ctn)
1✔
1521
            receiver_balance_msat = self.balance_minus_outgoing_htlcs(whose=receiver, ctx_owner=ctx_owner, ctn=ctn)
1✔
1522
            sender_reserve_msat = self.config[receiver].reserve_sat * 1000
1✔
1523
            receiver_reserve_msat = self.config[sender].reserve_sat * 1000
1✔
1524
            num_htlcs_in_ctx = len(self.included_htlcs(ctx_owner, SENT, ctn=ctn) + self.included_htlcs(ctx_owner, RECEIVED, ctn=ctn))
1✔
1525
            feerate = self.get_feerate(ctx_owner, ctn=ctn)
1✔
1526
            ctx_fees_msat = calc_fees_for_commitment_tx(
1✔
1527
                num_htlcs=num_htlcs_in_ctx,
1528
                feerate=feerate,
1529
                is_local_initiator=self.constraints.is_initiator,
1530
                round_to_sat=False,
1531
                has_anchors=self.has_anchors()
1532
            )
1533
            htlc_fee_msat = fee_for_htlc_output(feerate=feerate)
1✔
1534
            htlc_trim_func = received_htlc_trim_threshold_sat if ctx_owner == receiver else offered_htlc_trim_threshold_sat
1✔
1535
            htlc_trim_threshold_msat = htlc_trim_func(dust_limit_sat=self.config[ctx_owner].dust_limit_sat, feerate=feerate, has_anchors=self.has_anchors()) * 1000
1✔
1536

1537
            # the sender cannot spend below its reserve
1538
            max_send_msat = sender_balance_msat - sender_reserve_msat
1✔
1539

1540
            # reserve a fee spike buffer
1541
            # see https://github.com/lightningnetwork/lightning-rfc/pull/740
1542
            if sender == initiator == LOCAL:
1✔
1543
                fee_spike_buffer = calc_fees_for_commitment_tx(
1✔
1544
                    num_htlcs=num_htlcs_in_ctx + int(not is_htlc_dust) + 1,
1545
                    feerate=2 * feerate,
1546
                    is_local_initiator=self.constraints.is_initiator,
1547
                    round_to_sat=False,
1548
                    has_anchors=self.has_anchors())[sender]
1549
                max_send_msat -= fee_spike_buffer
1✔
1550
            # we can't enforce the fee spike buffer on the remote party
1551
            elif sender == initiator == REMOTE:
1✔
1552
                max_send_msat -= ctx_fees_msat[sender]
1✔
1553

1554
            # initiator pays for anchor outputs
1555
            if sender == initiator and self.has_anchors():
1✔
1556
                max_send_msat -= 2 * FIXED_ANCHOR_SAT * 1000
1✔
1557

1558
            # handle the transaction fees for the HTLC transaction
1559
            if is_htlc_dust:
1✔
1560
                # nobody pays additional HTLC transaction fees
1561
                return min(max_send_msat, htlc_trim_threshold_msat - 1)
1✔
1562
            else:
1563
                # somebody has to pay for the additional HTLC transaction fees
1564
                if sender == initiator:
1✔
1565
                    return max_send_msat - htlc_fee_msat
1✔
1566
                else:
1567
                    # check if the receiver can afford to pay for the HTLC transaction fees
1568
                    new_receiver_balance = receiver_balance_msat - receiver_reserve_msat - ctx_fees_msat[receiver] - htlc_fee_msat
1✔
1569
                    if self.has_anchors():
1✔
1570
                        new_receiver_balance -= 2 * FIXED_ANCHOR_SAT * 1000
1✔
1571
                    if new_receiver_balance < 0:
1✔
1572
                        return 0
1✔
1573
                    return max_send_msat
1✔
1574

1575
        max_send_msat = min(
1✔
1576
            max(
1577
                consider_ctx(ctx_owner=receiver, is_htlc_dust=True),
1578
                consider_ctx(ctx_owner=receiver, is_htlc_dust=False),
1579
            ),
1580
            max(
1581
                consider_ctx(ctx_owner=sender, is_htlc_dust=True),
1582
                consider_ctx(ctx_owner=sender, is_htlc_dust=False),
1583
            ),
1584
        )
1585

1586
        max_send_msat = min(max_send_msat, self.remaining_max_inflight(receiver, strict=True))
1✔
1587
        if self.htlc_slots_left(sender) == 0:
1✔
1588
            max_send_msat = 0
×
1589

1590
        max_send_msat = max(max_send_msat, 0)
1✔
1591
        return max_send_msat
1✔
1592

1593

1594
    def included_htlcs(self, subject: HTLCOwner, direction: Direction, ctn: int = None, *,
1✔
1595
                       feerate: int = None) -> List[UpdateAddHtlc]:
1596
        """Returns list of non-dust HTLCs for subject's commitment tx at ctn,
1597
        filtered by direction (of HTLCs).
1598
        """
1599
        assert type(subject) is HTLCOwner
1✔
1600
        assert type(direction) is Direction
1✔
1601
        if ctn is None:
1✔
1602
            ctn = self.get_oldest_unrevoked_ctn(subject)
×
1603
        if feerate is None:
1✔
1604
            feerate = self.get_feerate(subject, ctn=ctn)
1✔
1605
        conf = self.config[subject]
1✔
1606
        if direction == RECEIVED:
1✔
1607
            threshold_sat = received_htlc_trim_threshold_sat(dust_limit_sat=conf.dust_limit_sat, feerate=feerate, has_anchors=self.has_anchors())
1✔
1608
        else:
1609
            threshold_sat = offered_htlc_trim_threshold_sat(dust_limit_sat=conf.dust_limit_sat, feerate=feerate, has_anchors=self.has_anchors())
1✔
1610
        htlcs = self.hm.htlcs_by_direction(subject, direction, ctn=ctn).values()
1✔
1611
        return list(filter(lambda htlc: htlc.amount_msat // 1000 >= threshold_sat, htlcs))
1✔
1612

1613
    def get_secret_and_point(self, subject: HTLCOwner, ctn: int) -> Tuple[Optional[bytes], bytes]:
1✔
1614
        assert type(subject) is HTLCOwner
1✔
1615
        assert ctn >= 0, ctn
1✔
1616
        offset = ctn - self.get_oldest_unrevoked_ctn(subject)
1✔
1617
        if subject == REMOTE:
1✔
1618
            if offset > 1:
1✔
1619
                raise RemoteCtnTooFarInFuture(f"offset: {offset}")
×
1620
            conf = self.config[REMOTE]
1✔
1621
            if offset == 1:
1✔
1622
                secret = None
1✔
1623
                point = conf.next_per_commitment_point
1✔
1624
            elif offset == 0:
1✔
1625
                secret = None
1✔
1626
                point = conf.current_per_commitment_point
1✔
1627
            else:
1628
                secret = self.revocation_store.retrieve_secret(RevocationStore.START_INDEX - ctn)
×
1629
                point = secret_to_pubkey(int.from_bytes(secret, 'big'))
×
1630
        else:
1631
            secret = get_per_commitment_secret_from_seed(self.config[LOCAL].per_commitment_secret_seed, RevocationStore.START_INDEX - ctn)
1✔
1632
            point = secret_to_pubkey(int.from_bytes(secret, 'big'))
1✔
1633
        return secret, point
1✔
1634

1635
    def get_secret_and_commitment(self, subject: HTLCOwner, *, ctn: int) -> Tuple[Optional[bytes], PartialTransaction]:
1✔
1636
        secret, point = self.get_secret_and_point(subject, ctn)
1✔
1637
        ctx = self.make_commitment(subject, point, ctn)
1✔
1638
        return secret, ctx
1✔
1639

1640
    def get_commitment(self, subject: HTLCOwner, *, ctn: int) -> PartialTransaction:
1✔
1641
        secret, ctx = self.get_secret_and_commitment(subject, ctn=ctn)
1✔
1642
        return ctx
1✔
1643

1644
    def get_next_commitment(self, subject: HTLCOwner) -> PartialTransaction:
1✔
1645
        ctn = self.get_next_ctn(subject)
1✔
1646
        return self.get_commitment(subject, ctn=ctn)
1✔
1647

1648
    def get_latest_commitment(self, subject: HTLCOwner) -> PartialTransaction:
1✔
1649
        ctn = self.get_latest_ctn(subject)
1✔
1650
        return self.get_commitment(subject, ctn=ctn)
1✔
1651

1652
    def get_oldest_unrevoked_commitment(self, subject: HTLCOwner) -> PartialTransaction:
1✔
1653
        ctn = self.get_oldest_unrevoked_ctn(subject)
1✔
1654
        return self.get_commitment(subject, ctn=ctn)
1✔
1655

1656
    def create_sweeptxs_for_watchtower(self, ctn: int) -> List[Transaction]:
1✔
1657
        from .lnsweep import sweep_their_ctx_watchtower
×
1658
        from .fee_policy import FeePolicy
×
1659
        from .transaction import PartialTxOutput, PartialTransaction
×
1660
        secret, ctx = self.get_secret_and_commitment(REMOTE, ctn=ctn)
×
1661
        txs = []
×
1662
        txins = sweep_their_ctx_watchtower(self, ctx, secret)
×
1663
        fee_policy = FeePolicy('eta:2')
×
1664
        for txin in txins:
×
1665
            output_idx = txin.prevout.out_idx
×
1666
            value = ctx.outputs()[output_idx].value
×
1667
            tx_size_bytes = 121
×
1668
            fee = fee_policy.estimate_fee(tx_size_bytes, network=self.lnworker.network, allow_fallback_to_static_rates=True)
×
1669
            outvalue = value - fee
×
1670
            sweep_outputs = [PartialTxOutput.from_address_and_value(self.get_sweep_address(), outvalue)]
×
1671
            sweep_tx = PartialTransaction.from_io([txin], sweep_outputs, version=2)
×
1672
            sig = sweep_tx.sign_txin(0, txin.privkey)
×
1673
            txin.witness = txin.make_witness(sig)
×
1674
            txs.append(sweep_tx)
×
1675
        return txs
×
1676

1677
    def get_oldest_unrevoked_ctn(self, subject: HTLCOwner) -> int:
1✔
1678
        return self.hm.ctn_oldest_unrevoked(subject)
1✔
1679

1680
    def get_latest_ctn(self, subject: HTLCOwner) -> int:
1✔
1681
        return self.hm.ctn_latest(subject)
1✔
1682

1683
    def get_next_ctn(self, subject: HTLCOwner) -> int:
1✔
1684
        return self.hm.ctn_latest(subject) + 1
1✔
1685

1686
    def total_msat(self, direction: Direction) -> int:
1✔
1687
        """Return the cumulative total msat amount received/sent so far."""
1688
        assert type(direction) is Direction
1✔
1689
        return htlcsum(self.hm.all_settled_htlcs_ever_by_direction(LOCAL, direction))
1✔
1690

1691
    def settle_htlc(self, preimage: bytes, htlc_id: int) -> None:
1✔
1692
        """Settle/fulfill a pending received HTLC.
1693
        Action must be initiated by LOCAL.
1694
        """
1695
        self.logger.info("settle_htlc")
1✔
1696
        assert self.can_update_ctx(proposer=LOCAL), f"cannot update channel. {self.get_state()!r} {self.peer_state!r}"
1✔
1697
        htlc = self.hm.get_htlc_by_id(REMOTE, htlc_id)
1✔
1698
        if htlc.payment_hash != sha256(preimage):
1✔
1699
            raise Exception("incorrect preimage for HTLC")
×
1700
        assert htlc_id not in self.hm.log[REMOTE]['settles']
1✔
1701
        self.hm.send_settle(htlc_id)
1✔
1702
        self.htlc_settle_time[htlc_id] = now()
1✔
1703

1704
    def get_payment_hash(self, htlc_id: int) -> bytes:
1✔
1705
        htlc = self.hm.get_htlc_by_id(LOCAL, htlc_id)
×
1706
        return htlc.payment_hash
×
1707

1708
    def receive_htlc_settle(self, preimage: bytes, htlc_id: int) -> None:
1✔
1709
        """Settle/fulfill a pending offered HTLC.
1710
        Action must be initiated by REMOTE.
1711
        """
1712
        self.logger.info("receive_htlc_settle")
1✔
1713
        assert self.can_update_ctx(proposer=REMOTE), f"cannot update channel. {self.get_state()!r} {self.peer_state!r}"
1✔
1714
        htlc = self.hm.get_htlc_by_id(LOCAL, htlc_id)
1✔
1715
        if htlc.payment_hash != sha256(preimage):
1✔
1716
            raise RemoteMisbehaving("received incorrect preimage for HTLC")
×
1717
        assert htlc_id not in self.hm.log[LOCAL]['settles']
1✔
1718
        with self.db_lock:
1✔
1719
            self.hm.recv_settle(htlc_id)
1✔
1720

1721
    def fail_htlc(self, htlc_id: int) -> None:
1✔
1722
        """Fail a pending received HTLC.
1723
        Action must be initiated by LOCAL.
1724
        """
1725
        self.logger.info("fail_htlc")
1✔
1726
        assert self.can_update_ctx(proposer=LOCAL), f"cannot update channel. {self.get_state()!r} {self.peer_state!r}"
1✔
1727
        with self.db_lock:
1✔
1728
            self.hm.send_fail(htlc_id)
1✔
1729

1730
    def receive_fail_htlc(self, htlc_id: int, *,
1✔
1731
                          error_bytes: Optional[bytes],
1732
                          reason: Optional[OnionRoutingFailure] = None) -> None:
1733
        """Fail a pending offered HTLC.
1734
        Action must be initiated by REMOTE.
1735
        """
1736
        self.logger.info("receive_fail_htlc")
1✔
1737
        assert self.can_update_ctx(proposer=REMOTE), f"cannot update channel. {self.get_state()!r} {self.peer_state!r}"
1✔
1738
        with self.db_lock:
1✔
1739
            self.hm.recv_fail(htlc_id)
1✔
1740
        self._receive_fail_reasons[htlc_id] = (error_bytes, reason)
1✔
1741

1742
    def get_next_fee(self, subject: HTLCOwner) -> int:
1✔
1743
        return self.constraints.capacity - sum(x.value for x in self.get_next_commitment(subject).outputs())
1✔
1744

1745
    def get_latest_fee(self, subject: HTLCOwner) -> int:
1✔
1746
        return self.constraints.capacity - sum(x.value for x in self.get_latest_commitment(subject).outputs())
1✔
1747

1748
    def update_fee(self, feerate: int, from_us: bool) -> None:
1✔
1749
        # feerate uses sat/kw
1750
        if self.constraints.is_initiator != from_us:
1✔
1751
            raise Exception(f"Cannot update_fee: wrong initiator. us: {from_us}")
×
1752
        if feerate < FEERATE_PER_KW_MIN_RELAY_LIGHTNING:
1✔
1753
            raise Exception(f"Cannot update_fee: feerate lower than min relay fee. {feerate} sat/kw. us: {from_us}")
×
1754
        sender = LOCAL if from_us else REMOTE
1✔
1755
        ctx_owner = -sender
1✔
1756
        ctn = self.get_next_ctn(ctx_owner)
1✔
1757
        sender_balance_msat = self.balance_minus_outgoing_htlcs(whose=sender, ctx_owner=ctx_owner, ctn=ctn)
1✔
1758
        sender_reserve_msat = self.config[-sender].reserve_sat * 1000
1✔
1759
        num_htlcs_in_ctx = len(self.included_htlcs(ctx_owner, SENT, ctn=ctn, feerate=feerate) +
1✔
1760
                               self.included_htlcs(ctx_owner, RECEIVED, ctn=ctn, feerate=feerate))
1761
        ctx_fees_msat = calc_fees_for_commitment_tx(
1✔
1762
            num_htlcs=num_htlcs_in_ctx,
1763
            feerate=feerate,
1764
            is_local_initiator=self.constraints.is_initiator,
1765
            has_anchors=self.has_anchors()
1766
        )
1767
        remainder = sender_balance_msat - sender_reserve_msat - ctx_fees_msat[sender]
1✔
1768
        if remainder < 0:
1✔
1769
            raise Exception(f"Cannot update_fee. {sender} tried to update fee but they cannot afford it. "
×
1770
                            f"Their balance would go below reserve: {remainder} msat missing.")
1771
        assert self.can_update_ctx(proposer=LOCAL if from_us else REMOTE), f"cannot update channel. {self.get_state()!r} {self.peer_state!r}. {from_us=}"
1✔
1772
        with self.db_lock:
1✔
1773
            if from_us:
1✔
1774
                self.hm.send_update_fee(feerate)
1✔
1775
            else:
1776
                self.hm.recv_update_fee(feerate)
1✔
1777

1778
    def make_commitment(self, subject: HTLCOwner, this_point: bytes, ctn: int) -> PartialTransaction:
1✔
1779
        assert type(subject) is HTLCOwner
1✔
1780
        feerate = self.get_feerate(subject, ctn=ctn)
1✔
1781
        other = subject.inverted()
1✔
1782
        local_msat = self.balance(subject, ctx_owner=subject, ctn=ctn)
1✔
1783
        remote_msat = self.balance(other, ctx_owner=subject, ctn=ctn)
1✔
1784
        received_htlcs = self.hm.htlcs_by_direction(subject, RECEIVED, ctn).values()
1✔
1785
        sent_htlcs = self.hm.htlcs_by_direction(subject, SENT, ctn).values()
1✔
1786
        remote_msat -= htlcsum(received_htlcs)
1✔
1787
        local_msat -= htlcsum(sent_htlcs)
1✔
1788
        assert remote_msat >= 0
1✔
1789
        assert local_msat >= 0
1✔
1790
        # same htlcs as before, but now without dust.
1791
        received_htlcs = self.included_htlcs(subject, RECEIVED, ctn)
1✔
1792
        sent_htlcs = self.included_htlcs(subject, SENT, ctn)
1✔
1793

1794
        this_config = self.config[subject]
1✔
1795
        other_config = self.config[-subject]
1✔
1796
        other_htlc_pubkey = derive_pubkey(other_config.htlc_basepoint.pubkey, this_point)
1✔
1797
        this_htlc_pubkey = derive_pubkey(this_config.htlc_basepoint.pubkey, this_point)
1✔
1798
        other_revocation_pubkey = derive_blinded_pubkey(other_config.revocation_basepoint.pubkey, this_point)
1✔
1799
        htlcs = []  # type: List[ScriptHtlc]
1✔
1800
        for is_received_htlc, htlc_list in zip((True, False), (received_htlcs, sent_htlcs)):
1✔
1801
            for htlc in htlc_list:
1✔
1802
                htlcs.append(ScriptHtlc(make_htlc_output_witness_script(
1✔
1803
                    is_received_htlc=is_received_htlc,
1804
                    remote_revocation_pubkey=other_revocation_pubkey,
1805
                    remote_htlc_pubkey=other_htlc_pubkey,
1806
                    local_htlc_pubkey=this_htlc_pubkey,
1807
                    payment_hash=htlc.payment_hash,
1808
                    cltv_abs=htlc.cltv_abs,
1809
                    has_anchors=self.has_anchors()), htlc))
1810
        # note: maybe flip initiator here for fee purposes, we want LOCAL and REMOTE
1811
        #       in the resulting dict to correspond to the to_local and to_remote *outputs* of the ctx
1812
        onchain_fees = calc_fees_for_commitment_tx(
1✔
1813
            num_htlcs=len(htlcs),
1814
            feerate=feerate,
1815
            is_local_initiator=self.constraints.is_initiator == (subject == LOCAL),
1816
            has_anchors=self.has_anchors(),
1817
        )
1818
        assert self.is_static_remotekey_enabled()
1✔
1819
        payment_pubkey = other_config.payment_basepoint.pubkey
1✔
1820
        return make_commitment(
1✔
1821
            ctn=ctn,
1822
            local_funding_pubkey=this_config.multisig_key.pubkey,
1823
            remote_funding_pubkey=other_config.multisig_key.pubkey,
1824
            remote_payment_pubkey=payment_pubkey,
1825
            funder_payment_basepoint=self.config[LOCAL if     self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
1826
            fundee_payment_basepoint=self.config[LOCAL if not self.constraints.is_initiator else REMOTE].payment_basepoint.pubkey,
1827
            revocation_pubkey=other_revocation_pubkey,
1828
            delayed_pubkey=derive_pubkey(this_config.delayed_basepoint.pubkey, this_point),
1829
            to_self_delay=other_config.to_self_delay,
1830
            funding_txid=self.funding_outpoint.txid,
1831
            funding_pos=self.funding_outpoint.output_index,
1832
            funding_sat=self.constraints.capacity,
1833
            local_amount=local_msat,
1834
            remote_amount=remote_msat,
1835
            dust_limit_sat=this_config.dust_limit_sat,
1836
            fees_per_participant=onchain_fees,
1837
            htlcs=htlcs,
1838
            has_anchors=self.has_anchors()
1839
        )
1840

1841
    def make_closing_tx(self, local_script: bytes, remote_script: bytes,
1✔
1842
                        fee_sat: int, *, drop_remote = False) -> Tuple[bytes, PartialTransaction]:
1843
        """ cooperative close """
1844
        _, outputs = make_commitment_outputs(
1✔
1845
            fees_per_participant={
1846
                LOCAL: fee_sat * 1000 if self.constraints.is_initiator else 0,
1847
                REMOTE: fee_sat * 1000 if not self.constraints.is_initiator else 0,
1848
            },
1849
            local_amount_msat=self.balance(LOCAL),
1850
            remote_amount_msat=self.balance(REMOTE) if not drop_remote else 0,
1851
            local_script=local_script,
1852
            remote_script=remote_script,
1853
            htlcs=[],
1854
            dust_limit_sat=self.config[LOCAL].dust_limit_sat,
1855
            has_anchors=self.has_anchors(),
1856
            local_anchor_script=None,
1857
            remote_anchor_script=None,
1858
        )
1859

1860
        closing_tx = make_closing_tx(self.config[LOCAL].multisig_key.pubkey,
1✔
1861
                                     self.config[REMOTE].multisig_key.pubkey,
1862
                                     funding_txid=self.funding_outpoint.txid,
1863
                                     funding_pos=self.funding_outpoint.output_index,
1864
                                     funding_sat=self.constraints.capacity,
1865
                                     outputs=outputs)
1866

1867
        der_sig = closing_tx.sign_txin(0, self.config[LOCAL].multisig_key.privkey)
1✔
1868
        sig = ecc.ecdsa_sig64_from_der_sig(der_sig[:-1])
1✔
1869
        return sig, closing_tx
1✔
1870

1871
    def signature_fits(self, tx: PartialTransaction) -> bool:
1✔
1872
        remote_sig = self.config[LOCAL].current_commitment_signature
1✔
1873
        pre_hash = tx.serialize_preimage(0)
1✔
1874
        msg_hash = sha256d(pre_hash)
1✔
1875
        assert remote_sig
1✔
1876
        res = ECPubkey(self.config[REMOTE].multisig_key.pubkey).ecdsa_verify(remote_sig, msg_hash)
1✔
1877
        return res
1✔
1878

1879
    def force_close_tx(self) -> PartialTransaction:
1✔
1880
        tx = self.get_latest_commitment(LOCAL)
1✔
1881
        assert self.signature_fits(tx)
1✔
1882
        tx.sign({self.config[LOCAL].multisig_key.pubkey: self.config[LOCAL].multisig_key.privkey})
1✔
1883
        remote_sig = self.config[LOCAL].current_commitment_signature
1✔
1884
        remote_sig = ecc.ecdsa_der_sig_from_ecdsa_sig64(remote_sig) + Sighash.to_sigbytes(Sighash.ALL)
1✔
1885
        tx.add_signature_to_txin(txin_idx=0,
1✔
1886
                                 signing_pubkey=self.config[REMOTE].multisig_key.pubkey,
1887
                                 sig=remote_sig)
1888
        assert tx.is_complete()
1✔
1889
        return tx
1✔
1890

1891
    def get_close_options(self) -> Sequence[ChanCloseOption]:
1✔
1892
        # This method is used both in the GUI, and in lnpeer.schedule_force_closing
1893
        # in the latter case, the result does not depend on peer_state
1894
        ret = []
1✔
1895
        if not self.is_closed() and self.peer_state == PeerState.GOOD:
1✔
1896
            # If there are unsettled HTLCs, although is possible to cooperatively close,
1897
            # we choose not to expose that option in the GUI, because it is very likely
1898
            # that HTLCs will take a long time to settle (submarine swap, or stuck payment),
1899
            # and the close dialog would be taking a very long time to finish
1900
            if not self.has_unsettled_htlcs():
1✔
1901
                ret.append(ChanCloseOption.COOP_CLOSE)
1✔
1902
                ret.append(ChanCloseOption.REQUEST_REMOTE_FCLOSE)
1✔
1903
        if self.get_state() == ChannelState.WE_ARE_TOXIC:
1✔
1904
            ret.append(ChanCloseOption.REQUEST_REMOTE_FCLOSE)
×
1905
        if not self.is_closed() or self.get_state() == ChannelState.REQUESTED_FCLOSE:
1✔
1906
            ret.append(ChanCloseOption.LOCAL_FCLOSE)
1✔
1907
        assert not (self.get_state() == ChannelState.WE_ARE_TOXIC and ChanCloseOption.LOCAL_FCLOSE in ret), "local force-close unsafe if we are toxic"
1✔
1908
        return ret
1✔
1909

1910
    def maybe_sweep_htlcs(self, ctx: Transaction, htlc_tx: Transaction) -> Dict[str, SweepInfo]:
1✔
1911
        # look at the output address, check if it matches
1912
        d = sweep_their_htlctx_justice(self, ctx, htlc_tx)
×
1913
        d2 = sweep_our_htlctx(self, ctx, htlc_tx)
×
1914
        d.update(d2)
×
1915
        return d
×
1916

1917
    def has_pending_changes(self, subject: HTLCOwner) -> bool:
1✔
1918
        next_htlcs = self.hm.get_htlcs_in_next_ctx(subject)
1✔
1919
        latest_htlcs = self.hm.get_htlcs_in_latest_ctx(subject)
1✔
1920
        return not (next_htlcs == latest_htlcs and self.get_next_feerate(subject) == self.get_latest_feerate(subject))
1✔
1921

1922
    def should_be_closed_due_to_expiring_htlcs(self, local_height: int) -> bool:
1✔
1923
        htlcs_we_could_reclaim = {}  # type: Dict[Tuple[Direction, int], UpdateAddHtlc]
×
1924
        # If there is a received HTLC for which we already released the preimage
1925
        # but the remote did not revoke yet, and the CLTV of this HTLC is dangerously close
1926
        # to the present, then unilaterally close channel
1927
        recv_htlc_deadline_delta = lnutil.NBLOCK_DEADLINE_DELTA_BEFORE_EXPIRY_FOR_RECEIVED_HTLCS
×
1928
        for sub, dir, ctn in ((LOCAL, RECEIVED, self.get_latest_ctn(LOCAL)),
×
1929
                              (REMOTE, SENT, self.get_oldest_unrevoked_ctn(REMOTE)),
1930
                              (REMOTE, SENT, self.get_latest_ctn(REMOTE)),):
1931
            for htlc_id, htlc in self.hm.htlcs_by_direction(subject=sub, direction=dir, ctn=ctn).items():
×
1932
                if not self.hm.was_htlc_preimage_released(htlc_id=htlc_id, htlc_proposer=REMOTE):
×
1933
                    continue
×
1934
                if htlc.cltv_abs - recv_htlc_deadline_delta > local_height:
×
1935
                    continue
×
1936
                # Do not force-close if we just sent fulfill_htlc and have not received revack yet
1937
                if htlc_id in self.htlc_settle_time and now() - self.htlc_settle_time[htlc_id] < 30:
×
1938
                    continue
×
1939
                htlcs_we_could_reclaim[(RECEIVED, htlc_id)] = htlc
×
1940
        # If there is an offered HTLC which has already expired (+ some grace period after), we
1941
        # will unilaterally close the channel and time out the HTLC
1942
        offered_htlc_deadline_delta = lnutil.NBLOCK_DEADLINE_DELTA_AFTER_EXPIRY_FOR_OFFERED_HTLCS
×
1943
        for sub, dir, ctn in ((LOCAL, SENT, self.get_latest_ctn(LOCAL)),
×
1944
                              (REMOTE, RECEIVED, self.get_oldest_unrevoked_ctn(REMOTE)),
1945
                              (REMOTE, RECEIVED, self.get_latest_ctn(REMOTE)),):
1946
            for htlc_id, htlc in self.hm.htlcs_by_direction(subject=sub, direction=dir, ctn=ctn).items():
×
1947
                if htlc.cltv_abs + offered_htlc_deadline_delta > local_height:
×
1948
                    continue
×
1949
                htlcs_we_could_reclaim[(SENT, htlc_id)] = htlc
×
1950
        # Note: previously we used a threshold concept, "min_value_worth_closing_channel_over_sat", and
1951
        #       only force-closed the channel if the total value of these expiring htlcs was large enough.
1952
        #       However, if we are forwarding, and an outgoing htlc expires, we should always close
1953
        #       the outgoing channel (regardless of htlc value), so that we can propagate back the
1954
        #       removal of the htlc in the incoming channel.
1955
        return len(htlcs_we_could_reclaim) > 0
×
1956

1957
    def is_funding_tx_mined(self, funding_height):
1✔
1958
        funding_txid = self.funding_outpoint.txid
×
1959
        funding_idx = self.funding_outpoint.output_index
×
1960
        conf = funding_height.conf
×
1961
        if conf < self.funding_txn_minimum_depth():
×
1962
            #self.logger.info(f"funding tx is still not at sufficient depth. actual depth: {conf}")
1963
            return False
×
1964
        assert conf > 0 or self.is_zeroconf()
×
1965
        # check funding_tx amount and script
1966
        funding_tx = self.lnworker.lnwatcher.adb.get_transaction(funding_txid)
×
1967
        if not funding_tx:
×
1968
            self.logger.info(f"no funding_tx {funding_txid}")
×
1969
            return False
×
1970
        outp = funding_tx.outputs()[funding_idx]
×
1971
        redeem_script = funding_output_script(self.config[REMOTE], self.config[LOCAL])
×
1972
        funding_address = redeem_script_to_address('p2wsh', redeem_script)
×
1973
        funding_sat = self.constraints.capacity
×
1974
        if not (outp.address == funding_address and outp.value == funding_sat):
×
1975
            self.logger.info('funding outpoint mismatch')
×
1976
            return False
×
1977
        return True
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc