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