URI: 
       tlnsweep.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
       tlnsweep.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