Browse Source

swaps: more precise tx size estimation for claim tx when RBF-ing

patch-4
SomberNight 3 years ago
parent
commit
e36d7fed7d
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 30
      electrum/submarine_swaps.py
  2. 3
      electrum/transaction.py
  3. 9
      electrum/wallet.py

30
electrum/submarine_swaps.py

@ -11,7 +11,7 @@ from .crypto import sha256, hash_160
from .ecc import ECPrivkey
from .bitcoin import (script_to_p2wsh, opcodes, p2wsh_nested_script, push_script,
is_segwit_address, construct_witness)
from .transaction import PartialTxInput, PartialTxOutput, PartialTransaction
from .transaction import PartialTxInput, PartialTxOutput, PartialTransaction, Transaction, TxInput
from .transaction import script_GetOp, match_script_against_template, OPPushDataGeneric, OPPushDataPubkey
from .util import log_exceptions
from .lnutil import REDEEM_AFTER_DOUBLE_SPENT_DELAY, ln_dummy_address
@ -246,7 +246,7 @@ class SwapManager(Logger):
assert self.lnwatcher
privkey = os.urandom(32)
pubkey = ECPrivkey(privkey).get_public_key_bytes(compressed=True)
lnaddr, invoice = await self.lnworker.create_invoice(
lnaddr, invoice = self.lnworker.create_invoice(
amount_msat=lightning_amount_sat * 1000,
message='swap',
expiry=3600 * 24,
@ -535,9 +535,12 @@ class SwapManager(Logger):
send_amount += self.get_claim_fee()
return send_amount
def get_swap_by_tx(self, tx):
def get_swap_by_tx(self, tx: Transaction) -> Optional[SwapData]:
# determine if tx is spending from a swap
txin = tx.inputs()[0]
return self.get_swap_by_claim_txin(txin)
def get_swap_by_claim_txin(self, txin: TxInput) -> Optional[SwapData]:
for key, swap in self.swaps.items():
if txin.prevout.txid.hex() == swap.funding_txid:
return swap
@ -549,10 +552,29 @@ class SwapManager(Logger):
return True
return False
def sign_tx(self, tx, swap):
def add_txin_info(self, txin: PartialTxInput) -> None:
"""Add some info to a claim txin.
note: even without signing, this is useful for tx size estimation.
"""
swap = self.get_swap_by_claim_txin(txin)
if not swap:
return
preimage = swap.preimage if swap.is_reverse else 0
witness_script = swap.redeem_script
txin.script_type = 'p2wsh'
txin.num_sig = 1 # hack so that txin not considered "is_complete"
txin.script_sig = b''
txin.witness_script = witness_script
sig_dummy = b'\x00' * 71 # DER-encoded ECDSA sig, with low S and low R
witness = [sig_dummy, preimage, witness_script]
txin.witness_sizehint = len(bytes.fromhex(construct_witness(witness)))
def sign_tx(self, tx: PartialTransaction, swap: SwapData) -> None:
preimage = swap.preimage if swap.is_reverse else 0
witness_script = swap.redeem_script
txin = tx.inputs()[0]
assert len(tx.inputs()) == 1, f"expected 1 input for swap claim tx. found {len(tx.inputs())}"
assert txin.prevout.txid.hex() == swap.funding_txid
txin.script_type = 'p2wsh'
txin.script_sig = b''
txin.witness_script = witness_script

3
electrum/transaction.py

@ -712,6 +712,8 @@ class Transaction:
if not txin.is_segwit():
return construct_witness([])
if estimate_size and txin.witness_sizehint is not None:
return '00' * txin.witness_sizehint
if _type in ('address', 'unknown') and estimate_size:
_type = cls.guess_txintype_from_address(txin.address)
pubkeys, sig_list = cls.get_siglist(txin, estimate_size=estimate_size)
@ -1213,6 +1215,7 @@ class PartialTxInput(TxInput, PSBTSection):
self.spent_txid = None # type: Optional[str] # txid of the spender
self._is_p2sh_segwit = None # type: Optional[bool] # None means unknown
self._is_native_segwit = None # type: Optional[bool] # None means unknown
self.witness_sizehint = None # type: Optional[int] # byte size of serialized complete witness, for tx size est
@property
def utxo(self):

9
electrum/wallet.py

@ -1929,10 +1929,13 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
address = self.get_txin_address(txin)
# note: we add input utxos regardless of is_mine
self._add_input_utxo_info(txin, ignore_network_issues=ignore_network_issues, address=address)
if not self.is_mine(address):
is_mine = self.is_mine(address)
if not is_mine:
is_mine = self._learn_derivation_path_for_address_from_txinout(txin, address)
if not is_mine:
return
if not is_mine:
if self.lnworker:
self.lnworker.swap_manager.add_txin_info(txin)
return
# set script_type first, as later checks might rely on it:
txin.script_type = self.get_txin_type(address)
txin.num_sig = self.m if isinstance(self, Multisig_Wallet) else 1

Loading…
Cancel
Save