From 4bde19fe33429e95eaeffdc3bcdf147a868d6644 Mon Sep 17 00:00:00 2001
From: tecnovert <tecnovert@tecnovert.net>
Date: Wed, 9 Dec 2020 21:30:21 +0200
Subject: [PATCH] Record the coin b lock tx before it's confirmed.

---
 basicswap/basicswap.py           | 39 ++++++++++++++++++++++++--------
 basicswap/interface_xmr.py       | 13 +++++++----
 basicswap/templates/bid_xmr.html |  4 ++--
 basicswap/ui.py                  |  5 +++-
 4 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py
index a539509..fb3bef8 100644
--- a/basicswap/basicswap.py
+++ b/basicswap/basicswap.py
@@ -187,6 +187,8 @@ class EventLogTypes(IntEnum):
     LOCK_TX_A_PUBLISHED = auto()
     LOCK_TX_B_PUBLISHED = auto()
     FAILED_TX_B_SPEND = auto()
+    LOCK_TX_B_SEEN = auto()
+    LOCK_TX_B_CONFIRMED = auto()
 
 
 class XmrSplitMsgTypes(IntEnum):
@@ -319,6 +321,10 @@ def describeEventEntry(event_type, event_msg):
         return 'Lock tx b published'
     if event_type == EventLogTypes.FAILED_TX_B_SPEND:
         return 'Failed to publish lock tx b spend'
+    if event_type == EventLogTypes.LOCK_TX_B_SEEN:
+        return 'Lock tx b seen in chain'
+    if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED:
+        return 'Lock tx b confirmed in chain'
 
 
 def getExpectedSequence(lockType, lockVal, coin_type):
@@ -569,6 +575,7 @@ class BasicSwap(BaseApp):
             'conf_target': chain_client_settings.get('conf_target', 2),
             'watched_outputs': [],
             'last_height_checked': last_height_checked,
+            'last_height': None,
             'use_segwit': chain_client_settings.get('use_segwit', False),
             'use_csv': chain_client_settings.get('use_csv', True),
             'core_version_group': chain_client_settings.get('core_version_group', 0),
@@ -2643,27 +2650,41 @@ class BasicSwap(BaseApp):
                 if bid.was_sent and bid.xmr_b_lock_tx is None:
                     return rv
 
+                bid_changed = False
+                # Have to use findTxB instead of relying on the first seen height to detect chain reorgs
                 found_tx = ci_to.findTxB(xmr_swap.vkbv, xmr_swap.pkbs, bid.amount_to, ci_to.blocks_confirmed, xmr_swap.b_restore_height)
                 if found_tx is not None:
-                    self.log.debug('Found {} lock tx in chain'.format(ci_to.coin_name()))
                     if bid.xmr_b_lock_tx is None:
+                        self.log.debug('Found {} lock tx in chain'.format(ci_to.coin_name()))
+                        self.logBidEvent(bid, EventLogTypes.LOCK_TX_B_SEEN, '', session)
                         b_lock_tx_id = bytes.fromhex(found_tx['txid'])
                         bid.xmr_b_lock_tx = SwapTx(
                             bid_id=bid_id,
                             tx_type=TxTypes.XMR_SWAP_B_LOCK,
                             txid=b_lock_tx_id,
+                            chain_height=found_tx['height'],
                         )
+                        bid_changed = True
+                    else:
+                        bid.xmr_b_lock_tx.chain_height = found_tx['height']
+                        bid_changed = True
 
-                    bid.xmr_b_lock_tx.setState(TxStates.TX_CONFIRMED)
+                if bid.xmr_b_lock_tx and bid.xmr_b_lock_tx.chain_height is not None and bid.xmr_b_lock_tx.chain_height > 0:
+                    chain_height = ci_to.getChainHeight()
+                    self.coin_clients[ci_to.coin_type()]['last_height'] = chain_height
 
-                    bid.setState(BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED)
+                    if chain_height - bid.xmr_b_lock_tx.chain_height >= ci_to.blocks_confirmed:
+                        self.logBidEvent(bid, EventLogTypes.LOCK_TX_B_CONFIRMED, '', session)
+                        bid.xmr_b_lock_tx.setState(TxStates.TX_CONFIRMED)
+                        bid.setState(BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED)
+
+                        if bid.was_received:
+                            delay = random.randrange(self.min_delay_event, self.max_delay_event)
+                            self.log.info('Releasing xmr swap secret for bid %s in %d seconds', bid_id.hex(), delay)
+                            self.createEventInSession(delay, EventTypes.SEND_XMR_SECRET, bid_id, session)
+
+                if bid_changed:
                     self.saveBidInSession(bid_id, bid, session, xmr_swap)
-
-                    if bid.was_received:
-                        delay = random.randrange(self.min_delay_event, self.max_delay_event)
-                        self.log.info('Releasing xmr swap secret for bid %s in %d seconds', bid_id.hex(), delay)
-                        self.createEventInSession(delay, EventTypes.SEND_XMR_SECRET, bid_id, session)
-
                     session.commit()
             elif state == BidStates.XMR_SWAP_SECRET_SHARED:
                 # Wait for script spend tx to confirm
diff --git a/basicswap/interface_xmr.py b/basicswap/interface_xmr.py
index 2f0f94b..7a3d8d8 100644
--- a/basicswap/interface_xmr.py
+++ b/basicswap/interface_xmr.py
@@ -232,21 +232,24 @@ class XMRInterface(CoinInterface):
 
         rv = self.rpc_wallet_cb('refresh')
 
+        '''
         # Debug
         try:
-            current_height = self.rpc_cb('get_block_count')['count']
+            current_height = self.rpc_wallet_cb('get_block_count')['count']
             logging.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58)
         except Exception as e:
             logging.info('rpc_cb failed %s', str(e))
             current_height = None  # If the transfer is available it will be deep enough
-
+        '''
         params = {'transfer_type': 'available'}
         rv = self.rpc_wallet_cb('incoming_transfers', params)
         if 'transfers' in rv:
             for transfer in rv['transfers']:
-                if transfer['amount'] == cb_swap_value \
-                   and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
-                    return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': transfer['block_height']}
+                if transfer['amount'] == cb_swap_value:
+                #   and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
+                    return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
+                else:
+                    logging.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
 
         return None
 
diff --git a/basicswap/templates/bid_xmr.html b/basicswap/templates/bid_xmr.html
index d32016c..afa08dc 100644
--- a/basicswap/templates/bid_xmr.html
+++ b/basicswap/templates/bid_xmr.html
@@ -24,9 +24,9 @@
 {% if data.show_txns %}
 <h4>Transactions</h4>
 <table>
-<tr><th>Tx Type</th><th>Tx ID</th></tr>
+<tr><th>Tx Type</th><th>Tx ID</th><th>Blocks Deep</th></tr>
 {% for tx in data.txns %}
-<tr><td>{{ tx.type }}</td><td>{{ tx.txid }}</td></tr>
+<tr><td>{{ tx.type }}</td><td>{{ tx.txid }}</td><td>{{ tx.confirms }}</td></tr>
 {% endfor %}
 </table>
 {% endif %}
diff --git a/basicswap/ui.py b/basicswap/ui.py
index 79dd50e..1490136 100644
--- a/basicswap/ui.py
+++ b/basicswap/ui.py
@@ -156,7 +156,10 @@ def describeBid(swap_client, bid, offer, edit_bid, show_txns):
             if bid.xmr_a_lock_spend_tx:
                 txns.append({'type': 'Chain A Lock Spend', 'txid': bid.xmr_a_lock_spend_tx.txid.hex()})
             if bid.xmr_b_lock_tx:
-                txns.append({'type': 'Chain B Lock', 'txid': bid.xmr_b_lock_tx.txid.hex()})
+                confirms = None
+                if swap_client.coin_clients[ci_to.coin_type()]['last_height'] and bid.xmr_b_lock_tx.chain_height:
+                    confirms = swap_client.coin_clients[ci_to.coin_type()]['last_height'] - bid.xmr_b_lock_tx.chain_height
+                txns.append({'type': 'Chain B Lock', 'txid': bid.xmr_b_lock_tx.txid.hex(), 'confirms': confirms})
             if bid.xmr_b_lock_tx and bid.xmr_b_lock_tx.spend_txid:
                 txns.append({'type': 'Chain B Lock Spend', 'txid': bid.xmr_b_lock_tx.spend_txid.hex()})