electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

lnsweep.py (26747B)


      1 # Copyright (C) 2018 The Electrum developers
      2 # Distributed under the MIT software license, see the accompanying
      3 # file LICENCE or http://www.opensource.org/licenses/mit-license.php
      4 
      5 from typing import Optional, Dict, List, Tuple, TYPE_CHECKING, NamedTuple, Callable
      6 from enum import Enum, auto
      7 
      8 from .util import bfh, bh2u
      9 from .bitcoin import redeem_script_to_address, dust_threshold, construct_witness
     10 from . import ecc
     11 from .lnutil import (make_commitment_output_to_remote_address, make_commitment_output_to_local_witness_script,
     12                      derive_privkey, derive_pubkey, derive_blinded_pubkey, derive_blinded_privkey,
     13                      make_htlc_tx_witness, make_htlc_tx_with_open_channel, UpdateAddHtlc,
     14                      LOCAL, REMOTE, make_htlc_output_witness_script,
     15                      get_ordered_channel_configs, privkey_to_pubkey, get_per_commitment_secret_from_seed,
     16                      RevocationStore, extract_ctn_from_tx_and_chan, UnableToDeriveSecret, SENT, RECEIVED,
     17                      map_htlcs_to_ctx_output_idxs, Direction)
     18 from .transaction import (Transaction, TxOutput, PartialTransaction, PartialTxInput,
     19                           PartialTxOutput, TxOutpoint)
     20 from .simple_config import SimpleConfig
     21 from .logging import get_logger, Logger
     22 
     23 if TYPE_CHECKING:
     24     from .lnchannel import Channel, AbstractChannel
     25 
     26 
     27 _logger = get_logger(__name__)
     28 
     29 
     30 class SweepInfo(NamedTuple):
     31     name: str
     32     csv_delay: int
     33     cltv_expiry: int
     34     gen_tx: Callable[[], Optional[Transaction]]
     35 
     36 
     37 def create_sweeptxs_for_watchtower(chan: 'Channel', ctx: Transaction, per_commitment_secret: bytes,
     38                                    sweep_address: str) -> List[Transaction]:
     39     """Presign sweeping transactions using the just received revoked pcs.
     40     These will only be utilised if the remote breaches.
     41     Sweep 'to_local', and all the HTLCs (two cases: directly from ctx, or from HTLC tx).
     42     """
     43     # prep
     44     ctn = extract_ctn_from_tx_and_chan(ctx, chan)
     45     pcp = ecc.ECPrivkey(per_commitment_secret).get_public_key_bytes(compressed=True)
     46     this_conf, other_conf = get_ordered_channel_configs(chan=chan, for_us=False)
     47     other_revocation_privkey = derive_blinded_privkey(other_conf.revocation_basepoint.privkey,
     48                                                       per_commitment_secret)
     49     to_self_delay = other_conf.to_self_delay
     50     this_delayed_pubkey = derive_pubkey(this_conf.delayed_basepoint.pubkey, pcp)
     51     txs = []
     52     # to_local
     53     revocation_pubkey = ecc.ECPrivkey(other_revocation_privkey).get_public_key_bytes(compressed=True)
     54     witness_script = bh2u(make_commitment_output_to_local_witness_script(
     55         revocation_pubkey, to_self_delay, this_delayed_pubkey))
     56     to_local_address = redeem_script_to_address('p2wsh', witness_script)
     57     output_idxs = ctx.get_output_idxs_from_address(to_local_address)
     58     if output_idxs:
     59         output_idx = output_idxs.pop()
     60         sweep_tx = create_sweeptx_ctx_to_local(
     61             sweep_address=sweep_address,
     62             ctx=ctx,
     63             output_idx=output_idx,
     64             witness_script=witness_script,
     65             privkey=other_revocation_privkey,
     66             is_revocation=True,
     67             config=chan.lnworker.config)
     68         if sweep_tx:
     69             txs.append(sweep_tx)
     70     # HTLCs
     71     def create_sweeptx_for_htlc(*, htlc: 'UpdateAddHtlc', htlc_direction: Direction,
     72                                 ctx_output_idx: int) -> Optional[Transaction]:
     73         htlc_tx_witness_script, htlc_tx = make_htlc_tx_with_open_channel(
     74             chan=chan,
     75             pcp=pcp,
     76             subject=REMOTE,
     77             ctn=ctn,
     78             htlc_direction=htlc_direction,
     79             commit=ctx,
     80             htlc=htlc,
     81             ctx_output_idx=ctx_output_idx)
     82         return create_sweeptx_that_spends_htlctx_that_spends_htlc_in_ctx(
     83             to_self_delay=0,
     84             htlc_tx=htlc_tx,
     85             htlctx_witness_script=htlc_tx_witness_script,
     86             sweep_address=sweep_address,
     87             privkey=other_revocation_privkey,
     88             is_revocation=True,
     89             config=chan.lnworker.config)
     90 
     91     htlc_to_ctx_output_idx_map = map_htlcs_to_ctx_output_idxs(
     92         chan=chan,
     93         ctx=ctx,
     94         pcp=pcp,
     95         subject=REMOTE,
     96         ctn=ctn)
     97     for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items():
     98         secondstage_sweep_tx = create_sweeptx_for_htlc(
     99             htlc=htlc,
    100             htlc_direction=direction,
    101             ctx_output_idx=ctx_output_idx)
    102         if secondstage_sweep_tx:
    103             txs.append(secondstage_sweep_tx)
    104     return txs
    105 
    106 
    107 def create_sweeptx_for_their_revoked_ctx(
    108         chan: 'Channel',
    109         ctx: Transaction,
    110         per_commitment_secret: bytes,
    111         sweep_address: str) -> Optional[Callable[[], Optional[Transaction]]]:
    112     # prep
    113     pcp = ecc.ECPrivkey(per_commitment_secret).get_public_key_bytes(compressed=True)
    114     this_conf, other_conf = get_ordered_channel_configs(chan=chan, for_us=False)
    115     other_revocation_privkey = derive_blinded_privkey(other_conf.revocation_basepoint.privkey,
    116                                                       per_commitment_secret)
    117     to_self_delay = other_conf.to_self_delay
    118     this_delayed_pubkey = derive_pubkey(this_conf.delayed_basepoint.pubkey, pcp)
    119     txs = []
    120     # to_local
    121     revocation_pubkey = ecc.ECPrivkey(other_revocation_privkey).get_public_key_bytes(compressed=True)
    122     witness_script = bh2u(make_commitment_output_to_local_witness_script(
    123         revocation_pubkey, to_self_delay, this_delayed_pubkey))
    124     to_local_address = redeem_script_to_address('p2wsh', witness_script)
    125     output_idxs = ctx.get_output_idxs_from_address(to_local_address)
    126     if output_idxs:
    127         output_idx = output_idxs.pop()
    128         sweep_tx = lambda: create_sweeptx_ctx_to_local(
    129             sweep_address=sweep_address,
    130             ctx=ctx,
    131             output_idx=output_idx,
    132             witness_script=witness_script,
    133             privkey=other_revocation_privkey,
    134             is_revocation=True,
    135             config=chan.lnworker.config)
    136         return sweep_tx
    137     return None
    138 
    139 
    140 def create_sweeptx_for_their_revoked_htlc(
    141         chan: 'Channel',
    142         ctx: Transaction,
    143         htlc_tx: Transaction,
    144         sweep_address: str) -> Optional[SweepInfo]:
    145 
    146     x = analyze_ctx(chan, ctx)
    147     if not x:
    148         return
    149     ctn, their_pcp, is_revocation, per_commitment_secret = x
    150     if not is_revocation:
    151         return
    152     # prep
    153     pcp = ecc.ECPrivkey(per_commitment_secret).get_public_key_bytes(compressed=True)
    154     this_conf, other_conf = get_ordered_channel_configs(chan=chan, for_us=False)
    155     other_revocation_privkey = derive_blinded_privkey(
    156         other_conf.revocation_basepoint.privkey,
    157         per_commitment_secret)
    158     to_self_delay = other_conf.to_self_delay
    159     this_delayed_pubkey = derive_pubkey(this_conf.delayed_basepoint.pubkey, pcp)
    160     # same witness script as to_local
    161     revocation_pubkey = ecc.ECPrivkey(other_revocation_privkey).get_public_key_bytes(compressed=True)
    162     witness_script = bh2u(make_commitment_output_to_local_witness_script(
    163         revocation_pubkey, to_self_delay, this_delayed_pubkey))
    164     htlc_address = redeem_script_to_address('p2wsh', witness_script)
    165     # check that htlc_tx is a htlc
    166     if htlc_tx.outputs()[0].address != htlc_address:
    167         return
    168     gen_tx = lambda: create_sweeptx_ctx_to_local(
    169         sweep_address=sweep_address,
    170         ctx=htlc_tx,
    171         output_idx=0,
    172         witness_script=witness_script,
    173         privkey=other_revocation_privkey,
    174         is_revocation=True,
    175         config=chan.lnworker.config)
    176     return SweepInfo(
    177         name='redeem_htlc2',
    178         csv_delay=0,
    179         cltv_expiry=0,
    180         gen_tx=gen_tx)
    181 
    182 
    183 def create_sweeptxs_for_our_ctx(
    184         *, chan: 'AbstractChannel',
    185         ctx: Transaction,
    186         sweep_address: str) -> Optional[Dict[str, SweepInfo]]:
    187     """Handle the case where we force close unilaterally with our latest ctx.
    188     Construct sweep txns for 'to_local', and for all HTLCs (2 txns each).
    189     'to_local' can be swept even if this is a breach (by us),
    190     but HTLCs cannot (old HTLCs are no longer stored).
    191     """
    192     ctn = extract_ctn_from_tx_and_chan(ctx, chan)
    193     our_conf, their_conf = get_ordered_channel_configs(chan=chan, for_us=True)
    194     our_per_commitment_secret = get_per_commitment_secret_from_seed(
    195         our_conf.per_commitment_secret_seed, RevocationStore.START_INDEX - ctn)
    196     our_pcp = ecc.ECPrivkey(our_per_commitment_secret).get_public_key_bytes(compressed=True)
    197     our_delayed_bp_privkey = ecc.ECPrivkey(our_conf.delayed_basepoint.privkey)
    198     our_localdelayed_privkey = derive_privkey(our_delayed_bp_privkey.secret_scalar, our_pcp)
    199     our_localdelayed_privkey = ecc.ECPrivkey.from_secret_scalar(our_localdelayed_privkey)
    200     their_revocation_pubkey = derive_blinded_pubkey(their_conf.revocation_basepoint.pubkey, our_pcp)
    201     to_self_delay = their_conf.to_self_delay
    202     our_htlc_privkey = derive_privkey(secret=int.from_bytes(our_conf.htlc_basepoint.privkey, 'big'),
    203                                        per_commitment_point=our_pcp).to_bytes(32, 'big')
    204     our_localdelayed_pubkey = our_localdelayed_privkey.get_public_key_bytes(compressed=True)
    205     to_local_witness_script = bh2u(make_commitment_output_to_local_witness_script(
    206         their_revocation_pubkey, to_self_delay, our_localdelayed_pubkey))
    207     to_local_address = redeem_script_to_address('p2wsh', to_local_witness_script)
    208     # to remote address
    209     bpk = their_conf.payment_basepoint.pubkey
    210     their_payment_pubkey = bpk if chan.is_static_remotekey_enabled() else derive_pubkey(their_conf.payment_basepoint.pubkey, our_pcp)
    211     to_remote_address = make_commitment_output_to_remote_address(their_payment_pubkey)
    212     # test ctx
    213     _logger.debug(f'testing our ctx: {to_local_address} {to_remote_address}')
    214     if not ctx.get_output_idxs_from_address(to_local_address) \
    215        and not ctx.get_output_idxs_from_address(to_remote_address):
    216         return
    217     # we have to_local, to_remote.
    218     # other outputs are htlcs
    219     # if they are spent, we need to generate the script
    220     # so, second-stage htlc sweep should not be returned here
    221     txs = {}  # type: Dict[str, SweepInfo]
    222     # to_local
    223     output_idxs = ctx.get_output_idxs_from_address(to_local_address)
    224     if output_idxs:
    225         output_idx = output_idxs.pop()
    226         sweep_tx = lambda: create_sweeptx_ctx_to_local(
    227             sweep_address=sweep_address,
    228             ctx=ctx,
    229             output_idx=output_idx,
    230             witness_script=to_local_witness_script,
    231             privkey=our_localdelayed_privkey.get_secret_bytes(),
    232             is_revocation=False,
    233             to_self_delay=to_self_delay,
    234             config=chan.lnworker.config)
    235         prevout = ctx.txid() + ':%d'%output_idx
    236         txs[prevout] = SweepInfo(
    237             name='our_ctx_to_local',
    238             csv_delay=to_self_delay,
    239             cltv_expiry=0,
    240             gen_tx=sweep_tx)
    241     we_breached = ctn < chan.get_oldest_unrevoked_ctn(LOCAL)
    242     if we_breached:
    243         _logger.info("we breached.")
    244         # return only our_ctx_to_local, because we don't keep htlc_signatures for old states
    245         return txs
    246 
    247     # HTLCs
    248     def create_txns_for_htlc(
    249             *, htlc: 'UpdateAddHtlc', htlc_direction: Direction,
    250             ctx_output_idx: int, htlc_relative_idx: int):
    251         if htlc_direction == RECEIVED:
    252             preimage = chan.lnworker.get_preimage(htlc.payment_hash)
    253         else:
    254             preimage = None
    255         htlctx_witness_script, htlc_tx = create_htlctx_that_spends_from_our_ctx(
    256             chan=chan,
    257             our_pcp=our_pcp,
    258             ctx=ctx,
    259             htlc=htlc,
    260             local_htlc_privkey=our_htlc_privkey,
    261             preimage=preimage,
    262             htlc_direction=htlc_direction,
    263             ctx_output_idx=ctx_output_idx,
    264             htlc_relative_idx=htlc_relative_idx)
    265         sweep_tx = lambda: create_sweeptx_that_spends_htlctx_that_spends_htlc_in_ctx(
    266             to_self_delay=to_self_delay,
    267             htlc_tx=htlc_tx,
    268             htlctx_witness_script=htlctx_witness_script,
    269             sweep_address=sweep_address,
    270             privkey=our_localdelayed_privkey.get_secret_bytes(),
    271             is_revocation=False,
    272             config=chan.lnworker.config)
    273         # side effect
    274         txs[htlc_tx.inputs()[0].prevout.to_str()] = SweepInfo(
    275             name='first-stage-htlc',
    276             csv_delay=0,
    277             cltv_expiry=htlc_tx.locktime,
    278             gen_tx=lambda: htlc_tx)
    279         txs[htlc_tx.txid() + ':0'] = SweepInfo(
    280             name='second-stage-htlc',
    281             csv_delay=to_self_delay,
    282             cltv_expiry=0,
    283             gen_tx=sweep_tx)
    284 
    285     # offered HTLCs, in our ctx --> "timeout"
    286     # received HTLCs, in our ctx --> "success"
    287     htlc_to_ctx_output_idx_map = map_htlcs_to_ctx_output_idxs(
    288         chan=chan,
    289         ctx=ctx,
    290         pcp=our_pcp,
    291         subject=LOCAL,
    292         ctn=ctn)
    293     for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items():
    294         create_txns_for_htlc(
    295             htlc=htlc,
    296             htlc_direction=direction,
    297             ctx_output_idx=ctx_output_idx,
    298             htlc_relative_idx=htlc_relative_idx)
    299     return txs
    300 
    301 
    302 def analyze_ctx(chan: 'Channel', ctx: Transaction):
    303     # note: the remote sometimes has two valid non-revoked commitment transactions,
    304     # either of which could be broadcast
    305     our_conf, their_conf = get_ordered_channel_configs(chan=chan, for_us=True)
    306     ctn = extract_ctn_from_tx_and_chan(ctx, chan)
    307     per_commitment_secret = None
    308     oldest_unrevoked_remote_ctn = chan.get_oldest_unrevoked_ctn(REMOTE)
    309     if ctn == oldest_unrevoked_remote_ctn:
    310         their_pcp = their_conf.current_per_commitment_point
    311         is_revocation = False
    312     elif ctn == oldest_unrevoked_remote_ctn + 1:
    313         their_pcp = their_conf.next_per_commitment_point
    314         is_revocation = False
    315     elif ctn < oldest_unrevoked_remote_ctn:  # breach
    316         try:
    317             per_commitment_secret = chan.revocation_store.retrieve_secret(RevocationStore.START_INDEX - ctn)
    318         except UnableToDeriveSecret:
    319             return
    320         their_pcp = ecc.ECPrivkey(per_commitment_secret).get_public_key_bytes(compressed=True)
    321         is_revocation = True
    322         #_logger.info(f'tx for revoked: {list(txs.keys())}')
    323     elif chan.get_data_loss_protect_remote_pcp(ctn):
    324         their_pcp = chan.get_data_loss_protect_remote_pcp(ctn)
    325         is_revocation = False
    326     else:
    327         return
    328     return ctn, their_pcp, is_revocation, per_commitment_secret
    329 
    330 
    331 def create_sweeptxs_for_their_ctx(
    332         *, chan: 'Channel',
    333         ctx: Transaction,
    334         sweep_address: str) -> Optional[Dict[str,SweepInfo]]:
    335     """Handle the case when the remote force-closes with their ctx.
    336     Sweep outputs that do not have a CSV delay ('to_remote' and first-stage HTLCs).
    337     Outputs with CSV delay ('to_local' and second-stage HTLCs) are redeemed by LNWatcher.
    338     """
    339     txs = {}  # type: Dict[str, SweepInfo]
    340     our_conf, their_conf = get_ordered_channel_configs(chan=chan, for_us=True)
    341     x = analyze_ctx(chan, ctx)
    342     if not x:
    343         return
    344     ctn, their_pcp, is_revocation, per_commitment_secret = x
    345     # to_local and to_remote addresses
    346     our_revocation_pubkey = derive_blinded_pubkey(our_conf.revocation_basepoint.pubkey, their_pcp)
    347     their_delayed_pubkey = derive_pubkey(their_conf.delayed_basepoint.pubkey, their_pcp)
    348     witness_script = bh2u(make_commitment_output_to_local_witness_script(
    349         our_revocation_pubkey, our_conf.to_self_delay, their_delayed_pubkey))
    350     to_local_address = redeem_script_to_address('p2wsh', witness_script)
    351     # to remote address
    352     bpk = our_conf.payment_basepoint.pubkey
    353     our_payment_pubkey = bpk if chan.is_static_remotekey_enabled() else derive_pubkey(bpk, their_pcp)
    354     to_remote_address = make_commitment_output_to_remote_address(our_payment_pubkey)
    355     # test if this is their ctx
    356     _logger.debug(f'testing their ctx: {to_local_address} {to_remote_address}')
    357     if not ctx.get_output_idxs_from_address(to_local_address) \
    358        and not ctx.get_output_idxs_from_address(to_remote_address):
    359         return
    360     if is_revocation:
    361         our_revocation_privkey = derive_blinded_privkey(our_conf.revocation_basepoint.privkey, per_commitment_secret)
    362         gen_tx = create_sweeptx_for_their_revoked_ctx(chan, ctx, per_commitment_secret, chan.sweep_address)
    363         if gen_tx:
    364             tx = gen_tx()
    365             txs[tx.inputs()[0].prevout.to_str()] = SweepInfo(
    366                 name='to_local_for_revoked_ctx',
    367                 csv_delay=0,
    368                 cltv_expiry=0,
    369                 gen_tx=gen_tx)
    370     # prep
    371     our_htlc_privkey = derive_privkey(secret=int.from_bytes(our_conf.htlc_basepoint.privkey, 'big'), per_commitment_point=their_pcp)
    372     our_htlc_privkey = ecc.ECPrivkey.from_secret_scalar(our_htlc_privkey)
    373     their_htlc_pubkey = derive_pubkey(their_conf.htlc_basepoint.pubkey, their_pcp)
    374     # to_local is handled by lnwatcher
    375     # to_remote
    376     if not chan.is_static_remotekey_enabled():
    377         our_payment_bp_privkey = ecc.ECPrivkey(our_conf.payment_basepoint.privkey)
    378         our_payment_privkey = derive_privkey(our_payment_bp_privkey.secret_scalar, their_pcp)
    379         our_payment_privkey = ecc.ECPrivkey.from_secret_scalar(our_payment_privkey)
    380         assert our_payment_pubkey == our_payment_privkey.get_public_key_bytes(compressed=True)
    381         output_idxs = ctx.get_output_idxs_from_address(to_remote_address)
    382         if output_idxs:
    383             output_idx = output_idxs.pop()
    384             prevout = ctx.txid() + ':%d'%output_idx
    385             sweep_tx = lambda: create_sweeptx_their_ctx_to_remote(
    386                 sweep_address=sweep_address,
    387                 ctx=ctx,
    388                 output_idx=output_idx,
    389                 our_payment_privkey=our_payment_privkey,
    390                 config=chan.lnworker.config)
    391             txs[prevout] = SweepInfo(
    392                 name='their_ctx_to_remote',
    393                 csv_delay=0,
    394                 cltv_expiry=0,
    395                 gen_tx=sweep_tx)
    396     # HTLCs
    397     def create_sweeptx_for_htlc(
    398             htlc: 'UpdateAddHtlc', is_received_htlc: bool,
    399             ctx_output_idx: int) -> None:
    400         if not is_received_htlc and not is_revocation:
    401             preimage = chan.lnworker.get_preimage(htlc.payment_hash)
    402         else:
    403             preimage = None
    404         htlc_output_witness_script = make_htlc_output_witness_script(
    405             is_received_htlc=is_received_htlc,
    406             remote_revocation_pubkey=our_revocation_pubkey,
    407             remote_htlc_pubkey=our_htlc_privkey.get_public_key_bytes(compressed=True),
    408             local_htlc_pubkey=their_htlc_pubkey,
    409             payment_hash=htlc.payment_hash,
    410             cltv_expiry=htlc.cltv_expiry)
    411 
    412         cltv_expiry = htlc.cltv_expiry if is_received_htlc and not is_revocation else 0
    413         prevout = ctx.txid() + ':%d'%ctx_output_idx
    414         sweep_tx = lambda: create_sweeptx_their_ctx_htlc(
    415             ctx=ctx,
    416             witness_script=htlc_output_witness_script,
    417             sweep_address=sweep_address,
    418             preimage=preimage,
    419             output_idx=ctx_output_idx,
    420             privkey=our_revocation_privkey if is_revocation else our_htlc_privkey.get_secret_bytes(),
    421             is_revocation=is_revocation,
    422             cltv_expiry=cltv_expiry,
    423             config=chan.lnworker.config)
    424         txs[prevout] = SweepInfo(
    425             name=f'their_ctx_htlc_{ctx_output_idx}',
    426             csv_delay=0,
    427             cltv_expiry=cltv_expiry,
    428             gen_tx=sweep_tx)
    429     # received HTLCs, in their ctx --> "timeout"
    430     # offered HTLCs, in their ctx --> "success"
    431     htlc_to_ctx_output_idx_map = map_htlcs_to_ctx_output_idxs(
    432         chan=chan,
    433         ctx=ctx,
    434         pcp=their_pcp,
    435         subject=REMOTE,
    436         ctn=ctn)
    437     for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items():
    438         create_sweeptx_for_htlc(
    439             htlc=htlc,
    440             is_received_htlc=direction == RECEIVED,
    441             ctx_output_idx=ctx_output_idx)
    442     return txs
    443 
    444 
    445 def create_htlctx_that_spends_from_our_ctx(
    446         chan: 'Channel', our_pcp: bytes,
    447         ctx: Transaction, htlc: 'UpdateAddHtlc',
    448         local_htlc_privkey: bytes, preimage: Optional[bytes],
    449         htlc_direction: Direction, htlc_relative_idx: int,
    450         ctx_output_idx: int) -> Tuple[bytes, Transaction]:
    451     assert (htlc_direction == RECEIVED) == bool(preimage), 'preimage is required iff htlc is received'
    452     preimage = preimage or b''
    453     ctn = extract_ctn_from_tx_and_chan(ctx, chan)
    454     witness_script, htlc_tx = make_htlc_tx_with_open_channel(
    455         chan=chan,
    456         pcp=our_pcp,
    457         subject=LOCAL,
    458         ctn=ctn,
    459         htlc_direction=htlc_direction,
    460         commit=ctx,
    461         htlc=htlc,
    462         ctx_output_idx=ctx_output_idx,
    463         name=f'our_ctx_{ctx_output_idx}_htlc_tx_{bh2u(htlc.payment_hash)}')
    464     remote_htlc_sig = chan.get_remote_htlc_sig_for_htlc(htlc_relative_idx=htlc_relative_idx)
    465     local_htlc_sig = bfh(htlc_tx.sign_txin(0, local_htlc_privkey))
    466     txin = htlc_tx.inputs()[0]
    467     witness_program = bfh(Transaction.get_preimage_script(txin))
    468     txin.witness = make_htlc_tx_witness(remote_htlc_sig, local_htlc_sig, preimage, witness_program)
    469     return witness_script, htlc_tx
    470 
    471 
    472 def create_sweeptx_their_ctx_htlc(
    473         ctx: Transaction, witness_script: bytes, sweep_address: str,
    474         preimage: Optional[bytes], output_idx: int,
    475         privkey: bytes, is_revocation: bool,
    476         cltv_expiry: int, config: SimpleConfig) -> Optional[PartialTransaction]:
    477     assert type(cltv_expiry) is int
    478     preimage = preimage or b''  # preimage is required iff (not is_revocation and htlc is offered)
    479     val = ctx.outputs()[output_idx].value
    480     prevout = TxOutpoint(txid=bfh(ctx.txid()), out_idx=output_idx)
    481     txin = PartialTxInput(prevout=prevout)
    482     txin._trusted_value_sats = val
    483     txin.witness_script = witness_script
    484     txin.script_sig = b''
    485     sweep_inputs = [txin]
    486     tx_size_bytes = 200  # TODO (depends on offered/received and is_revocation)
    487     fee = config.estimate_fee(tx_size_bytes, allow_fallback_to_static_rates=True)
    488     outvalue = val - fee
    489     if outvalue <= dust_threshold(): return None
    490     sweep_outputs = [PartialTxOutput.from_address_and_value(sweep_address, outvalue)]
    491     tx = PartialTransaction.from_io(sweep_inputs, sweep_outputs, version=2, locktime=cltv_expiry)
    492     sig = bfh(tx.sign_txin(0, privkey))
    493     if not is_revocation:
    494         witness = construct_witness([sig, preimage, witness_script])
    495     else:
    496         revocation_pubkey = privkey_to_pubkey(privkey)
    497         witness = construct_witness([sig, revocation_pubkey, witness_script])
    498     tx.inputs()[0].witness = bfh(witness)
    499     assert tx.is_complete()
    500     return tx
    501 
    502 
    503 def create_sweeptx_their_ctx_to_remote(
    504         sweep_address: str, ctx: Transaction, output_idx: int,
    505         our_payment_privkey: ecc.ECPrivkey,
    506         config: SimpleConfig) -> Optional[PartialTransaction]:
    507     our_payment_pubkey = our_payment_privkey.get_public_key_hex(compressed=True)
    508     val = ctx.outputs()[output_idx].value
    509     prevout = TxOutpoint(txid=bfh(ctx.txid()), out_idx=output_idx)
    510     txin = PartialTxInput(prevout=prevout)
    511     txin._trusted_value_sats = val
    512     txin.script_type = 'p2wpkh'
    513     txin.pubkeys = [bfh(our_payment_pubkey)]
    514     txin.num_sig = 1
    515     sweep_inputs = [txin]
    516     tx_size_bytes = 110  # approx size of p2wpkh->p2wpkh
    517     fee = config.estimate_fee(tx_size_bytes, allow_fallback_to_static_rates=True)
    518     outvalue = val - fee
    519     if outvalue <= dust_threshold(): return None
    520     sweep_outputs = [PartialTxOutput.from_address_and_value(sweep_address, outvalue)]
    521     sweep_tx = PartialTransaction.from_io(sweep_inputs, sweep_outputs)
    522     sweep_tx.set_rbf(True)
    523     sweep_tx.sign({our_payment_pubkey: (our_payment_privkey.get_secret_bytes(), True)})
    524     if not sweep_tx.is_complete():
    525         raise Exception('channel close sweep tx is not complete')
    526     return sweep_tx
    527 
    528 
    529 def create_sweeptx_ctx_to_local(
    530         *, sweep_address: str, ctx: Transaction, output_idx: int, witness_script: str,
    531         privkey: bytes, is_revocation: bool, config: SimpleConfig,
    532         to_self_delay: int=None) -> Optional[PartialTransaction]:
    533     """Create a txn that sweeps the 'to_local' output of a commitment
    534     transaction into our wallet.
    535 
    536     privkey: either revocation_privkey or localdelayed_privkey
    537     is_revocation: tells us which ^
    538     """
    539     val = ctx.outputs()[output_idx].value
    540     prevout = TxOutpoint(txid=bfh(ctx.txid()), out_idx=output_idx)
    541     txin = PartialTxInput(prevout=prevout)
    542     txin._trusted_value_sats = val
    543     txin.script_sig = b''
    544     txin.witness_script = bfh(witness_script)
    545     sweep_inputs = [txin]
    546     if not is_revocation:
    547         assert isinstance(to_self_delay, int)
    548         sweep_inputs[0].nsequence = to_self_delay
    549     tx_size_bytes = 121  # approx size of to_local -> p2wpkh
    550     fee = config.estimate_fee(tx_size_bytes, allow_fallback_to_static_rates=True)
    551     outvalue = val - fee
    552     if outvalue <= dust_threshold():
    553         return None
    554     sweep_outputs = [PartialTxOutput.from_address_and_value(sweep_address, outvalue)]
    555     sweep_tx = PartialTransaction.from_io(sweep_inputs, sweep_outputs, version=2)
    556     sig = sweep_tx.sign_txin(0, privkey)
    557     witness = construct_witness([sig, int(is_revocation), witness_script])
    558     sweep_tx.inputs()[0].witness = bfh(witness)
    559     return sweep_tx
    560 
    561 
    562 def create_sweeptx_that_spends_htlctx_that_spends_htlc_in_ctx(
    563         *, htlc_tx: Transaction, htlctx_witness_script: bytes, sweep_address: str,
    564         privkey: bytes, is_revocation: bool, to_self_delay: int,
    565         config: SimpleConfig) -> Optional[PartialTransaction]:
    566     val = htlc_tx.outputs()[0].value
    567     prevout = TxOutpoint(txid=bfh(htlc_tx.txid()), out_idx=0)
    568     txin = PartialTxInput(prevout=prevout)
    569     txin._trusted_value_sats = val
    570     txin.script_sig = b''
    571     txin.witness_script = htlctx_witness_script
    572     sweep_inputs = [txin]
    573     if not is_revocation:
    574         assert isinstance(to_self_delay, int)
    575         sweep_inputs[0].nsequence = to_self_delay
    576     tx_size_bytes = 200  # TODO
    577     fee = config.estimate_fee(tx_size_bytes, allow_fallback_to_static_rates=True)
    578     outvalue = val - fee
    579     if outvalue <= dust_threshold(): return None
    580     sweep_outputs = [PartialTxOutput.from_address_and_value(sweep_address, outvalue)]
    581     tx = PartialTransaction.from_io(sweep_inputs, sweep_outputs, version=2)
    582     sig = bfh(tx.sign_txin(0, privkey))
    583     witness = construct_witness([sig, int(is_revocation), htlctx_witness_script])
    584     tx.inputs()[0].witness = bfh(witness)
    585     assert tx.is_complete()
    586     return tx