mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-03 20:35:13 +00:00
swaps: stop watching address once utxo is spent and mined
This commit is contained in:
parent
252591832a
commit
04fb329c2e
2 changed files with 33 additions and 14 deletions
|
@ -760,22 +760,28 @@ class AddressSynchronizer(Logger):
|
||||||
sent[txi] = height
|
sent[txi] = height
|
||||||
return received, sent
|
return received, sent
|
||||||
|
|
||||||
def get_addr_utxo(self, address: str) -> Dict[TxOutpoint, PartialTxInput]:
|
|
||||||
|
def get_addr_outputs(self, address: str) -> Dict[TxOutpoint, PartialTxInput]:
|
||||||
coins, spent = self.get_addr_io(address)
|
coins, spent = self.get_addr_io(address)
|
||||||
for txi in spent:
|
|
||||||
coins.pop(txi)
|
|
||||||
out = {}
|
out = {}
|
||||||
for prevout_str, v in coins.items():
|
for prevout_str, v in coins.items():
|
||||||
tx_height, value, is_cb = v
|
tx_height, value, is_cb = v
|
||||||
prevout = TxOutpoint.from_str(prevout_str)
|
prevout = TxOutpoint.from_str(prevout_str)
|
||||||
utxo = PartialTxInput(prevout=prevout,
|
utxo = PartialTxInput(prevout=prevout, is_coinbase_output=is_cb)
|
||||||
is_coinbase_output=is_cb)
|
|
||||||
utxo._trusted_address = address
|
utxo._trusted_address = address
|
||||||
utxo._trusted_value_sats = value
|
utxo._trusted_value_sats = value
|
||||||
utxo.block_height = tx_height
|
utxo.block_height = tx_height
|
||||||
|
utxo.spent_height = spent.get(prevout_str, None)
|
||||||
out[prevout] = utxo
|
out[prevout] = utxo
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def get_addr_utxo(self, address: str) -> Dict[TxOutpoint, PartialTxInput]:
|
||||||
|
out = self.get_addr_outputs(address)
|
||||||
|
for k, v in list(out.items()):
|
||||||
|
if v.spent_height is not None:
|
||||||
|
out.pop(k)
|
||||||
|
return out
|
||||||
|
|
||||||
# return the total amount ever received by an address
|
# return the total amount ever received by an address
|
||||||
def get_addr_received(self, address):
|
def get_addr_received(self, address):
|
||||||
received, sent = self.get_addr_io(address)
|
received, sent = self.get_addr_io(address)
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from .crypto import sha256, hash_160
|
from .crypto import sha256, hash_160
|
||||||
from .ecc import ECPrivkey
|
from .ecc import ECPrivkey
|
||||||
from .bitcoin import address_to_script, script_to_p2wsh, redeem_script_to_address, opcodes, p2wsh_nested_script, push_script, is_segwit_address
|
from .bitcoin import address_to_script, script_to_p2wsh, redeem_script_to_address, opcodes, p2wsh_nested_script, push_script, is_segwit_address
|
||||||
from .transaction import TxOutpoint, PartialTxInput, PartialTxOutput, PartialTransaction, construct_witness
|
from .transaction import TxOutpoint, PartialTxInput, PartialTxOutput, PartialTransaction, construct_witness
|
||||||
from .transaction import script_GetOp, match_script_against_template, OPPushDataGeneric, OPPushDataPubkey
|
from .transaction import script_GetOp, match_script_against_template, OPPushDataGeneric, OPPushDataPubkey
|
||||||
from .util import log_exceptions
|
from .util import log_exceptions
|
||||||
|
from .lnutil import REDEEM_AFTER_DOUBLE_SPENT_DELAY
|
||||||
from .bitcoin import dust_threshold
|
from .bitcoin import dust_threshold
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -78,17 +80,27 @@ class SwapManager(Logger):
|
||||||
|
|
||||||
@log_exceptions
|
@log_exceptions
|
||||||
async def _claim_swap(self, lockup_address, onchain_amount, redeem_script, preimage, privkey, locktime):
|
async def _claim_swap(self, lockup_address, onchain_amount, redeem_script, preimage, privkey, locktime):
|
||||||
utxos = self.lnwatcher.get_addr_utxo(lockup_address)
|
if not self.lnwatcher.is_up_to_date():
|
||||||
if not utxos:
|
|
||||||
return
|
return
|
||||||
delta = self.network.get_local_height() - locktime
|
current_height = self.network.get_local_height()
|
||||||
if not preimage and delta < 0:
|
delta = current_height - locktime
|
||||||
self.logger.info(f'height not reached for refund {lockup_address} {delta}, {locktime}')
|
is_reverse = bool(preimage)
|
||||||
|
if not is_reverse and delta < 0:
|
||||||
|
# too early for refund
|
||||||
return
|
return
|
||||||
for txin in list(utxos.values()):
|
txos = self.lnwatcher.get_addr_outputs(lockup_address)
|
||||||
|
swap = self.swaps[preimage.hex()]
|
||||||
|
for txin in txos.values():
|
||||||
if preimage and txin._trusted_value_sats < onchain_amount:
|
if preimage and txin._trusted_value_sats < onchain_amount:
|
||||||
self.logger.info('amount too low, we should not reveal the preimage')
|
self.logger.info('amount too low, we should not reveal the preimage')
|
||||||
continue
|
continue
|
||||||
|
spent_height = txin.spent_height
|
||||||
|
if spent_height is not None:
|
||||||
|
if spent_height > 0 and current_height - spent_height > REDEEM_AFTER_DOUBLE_SPENT_DELAY:
|
||||||
|
self.logger.info(f'stop watching swap {lockup_address}')
|
||||||
|
self.lnwatcher.remove_callback(lockup_address)
|
||||||
|
swap['redeemed'] = True
|
||||||
|
continue
|
||||||
amount_sat = txin._trusted_value_sats - self.get_tx_fee()
|
amount_sat = txin._trusted_value_sats - self.get_tx_fee()
|
||||||
if amount_sat < dust_threshold():
|
if amount_sat < dust_threshold():
|
||||||
self.logger.info('utxo value below dust threshold')
|
self.logger.info('utxo value below dust threshold')
|
||||||
|
@ -97,8 +109,7 @@ class SwapManager(Logger):
|
||||||
tx = create_claim_tx(txin, redeem_script, preimage, privkey, address, amount_sat, locktime)
|
tx = create_claim_tx(txin, redeem_script, preimage, privkey, address, amount_sat, locktime)
|
||||||
await self.network.broadcast_transaction(tx)
|
await self.network.broadcast_transaction(tx)
|
||||||
# save txid
|
# save txid
|
||||||
what = 'claim_txid' if preimage else 'refund_txid'
|
swap['claim_txid' if preimage else 'refund_txid'] = tx.txid()
|
||||||
self.swaps[preimage.hex()][what] = tx.txid()
|
|
||||||
|
|
||||||
def get_tx_fee(self):
|
def get_tx_fee(self):
|
||||||
return self.lnwatcher.config.estimate_fee(136, allow_fallback_to_static_rates=True)
|
return self.lnwatcher.config.estimate_fee(136, allow_fallback_to_static_rates=True)
|
||||||
|
@ -111,6 +122,8 @@ class SwapManager(Logger):
|
||||||
self.lnwatcher = self.wallet.lnworker.lnwatcher
|
self.lnwatcher = self.wallet.lnworker.lnwatcher
|
||||||
self.swaps = self.wallet.db.get_dict('submarine_swaps')
|
self.swaps = self.wallet.db.get_dict('submarine_swaps')
|
||||||
for data in self.swaps.values():
|
for data in self.swaps.values():
|
||||||
|
if data.get('redeemed'):
|
||||||
|
continue
|
||||||
redeem_script = bytes.fromhex(data['redeemScript'])
|
redeem_script = bytes.fromhex(data['redeemScript'])
|
||||||
locktime = data['timeoutBlockHeight']
|
locktime = data['timeoutBlockHeight']
|
||||||
privkey = bytes.fromhex(data['privkey'])
|
privkey = bytes.fromhex(data['privkey'])
|
||||||
|
|
Loading…
Add table
Reference in a new issue