Browse Source

Handle lost noscript lock transaction.

pull/22/head
tecnovert 2 years ago
parent
commit
2a9e423eaa
No known key found for this signature in database GPG Key ID: 8ED6D8750C4E3F93
  1. 2
      basicswap/__init__.py
  2. 77
      basicswap/basicswap.py
  3. 5
      basicswap/basicswap_util.py
  4. 2
      basicswap/interface/btc.py
  5. 17
      basicswap/interface/dash.py
  6. 38
      basicswap/interface/xmr.py
  7. 12
      basicswap/js_server.py
  8. 18
      basicswap/protocols/xmr_swap_1.py
  9. 4
      basicswap/templates/bid.html
  10. 12
      basicswap/templates/bid_xmr.html
  11. 11
      basicswap/ui/page_offers.py
  12. 8
      basicswap/ui/util.py
  13. 18
      doc/release-notes.md
  14. 20
      tests/basicswap/test_xmr.py

2
basicswap/__init__.py

@ -1,3 +1,3 @@
name = "basicswap"
__version__ = "0.11.53"
__version__ = "0.11.54"

77
basicswap/basicswap.py

@ -3065,6 +3065,33 @@ class BasicSwap(BaseApp):
return sum_unspent
return None
def findTxB(self, ci_to, xmr_swap, bid, session) -> bool:
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, bid.chain_b_height_start, bid.was_sent)
if isinstance(found_tx, int) and found_tx == -1:
if self.countBidEvents(bid, EventLogTypes.LOCK_TX_B_INVALID, session) < 1:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_INVALID, 'Detected invalid lock tx B', session)
bid_changed = True
elif found_tx is not None:
if bid.xmr_b_lock_tx is None or not bid.xmr_b_lock_tx.chain_height:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_SEEN, '', session)
if bid.xmr_b_lock_tx is None:
self.log.debug('Found {} lock tx in chain'.format(ci_to.coin_name()))
xmr_swap.b_lock_tx_id = bytes.fromhex(found_tx['txid'])
bid.xmr_b_lock_tx = SwapTx(
bid_id=bid.bid_id,
tx_type=TxTypes.XMR_SWAP_B_LOCK,
txid=xmr_swap.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
return bid_changed
def checkXmrBidState(self, bid_id, bid, offer):
rv = False
@ -3176,6 +3203,13 @@ class BasicSwap(BaseApp):
rv = True # Remove from swaps_in_progress
elif state == BidStates.XMR_SWAP_FAILED_SWIPED:
rv = True # Remove from swaps_in_progress
elif state == BidStates.XMR_SWAP_FAILED:
if bid.was_sent and bid.xmr_b_lock_tx:
if self.countQueuedActions(session, bid_id, ActionTypes.RECOVER_XMR_SWAP_LOCK_TX_B) < 1:
delay = random.randrange(self.min_delay_event, self.max_delay_event)
self.log.info('Recovering xmr swap chain B lock tx for bid %s in %d seconds', bid_id.hex(), delay)
self.createActionInSession(delay, ActionTypes.RECOVER_XMR_SWAP_LOCK_TX_B, bid_id, session)
session.commit()
elif state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX:
if bid.xmr_a_lock_tx is None:
return rv
@ -3217,33 +3251,7 @@ class BasicSwap(BaseApp):
session.commit()
elif state == BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED:
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, bid.chain_b_height_start, bid.was_sent)
if isinstance(found_tx, int) and found_tx == -1:
if self.countBidEvents(bid, EventLogTypes.LOCK_TX_B_INVALID, session) < 1:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_INVALID, 'Detected invalid lock tx B', session)
bid_changed = True
elif found_tx is not None:
if bid.xmr_b_lock_tx is None or not bid.xmr_b_lock_tx.chain_height:
self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_SEEN, '', session)
if bid.xmr_b_lock_tx is None:
self.log.debug('Found {} lock tx in chain'.format(ci_to.coin_name()))
xmr_swap.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=xmr_swap.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_changed = self.findTxB(ci_to, xmr_swap, bid, session)
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()
@ -4715,6 +4723,14 @@ class BasicSwap(BaseApp):
ci_from = self.ci(Coins(offer.coin_from))
ci_to = self.ci(Coins(offer.coin_to))
if self.findTxB(ci_to, xmr_swap, bid, session) is True:
self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
return
if bid.xmr_b_lock_tx:
self.log.warning('Coin B lock tx {} exists for xmr bid {}'.format(bid.xmr_b_lock_tx.b_lock_tx_id, bid_id.hex()))
return
if bid.debug_ind == DebugTypes.BID_STOP_AFTER_COIN_A_LOCK:
self.log.debug('XMR bid %s: Stalling bid for testing: %d.', bid_id.hex(), bid.debug_ind)
bid.setState(BidStates.BID_STALLED_FOR_TEST)
@ -4723,7 +4739,7 @@ class BasicSwap(BaseApp):
return
unlock_time = 0
if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK:
if bid.debug_ind in (DebugTypes.CREATE_INVALID_COIN_B_LOCK, DebugTypes.B_LOCK_TX_MISSED_SEND):
bid.amount_to -= int(bid.amount_to * 0.1)
self.log.debug('XMR bid %s: Debug %d - Reducing lock b txn amount by 10%% to %s.', bid_id.hex(), bid.debug_ind, ci_to.format_amount(bid.amount_to))
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
@ -4731,8 +4747,13 @@ class BasicSwap(BaseApp):
unlock_time = 10000
self.log.debug('XMR bid %s: Debug %d - Sending locked XMR.', bid_id.hex(), bid.debug_ind)
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
try:
b_lock_tx_id = ci_to.publishBLockTx(xmr_swap.pkbv, xmr_swap.pkbs, bid.amount_to, xmr_offer.b_fee_rate, unlock_time=unlock_time)
if bid.debug_ind == DebugTypes.B_LOCK_TX_MISSED_SEND:
self.log.debug('XMR bid %s: Debug %d - Losing xmr lock tx %s.', bid_id.hex(), bid.debug_ind, b_lock_tx_id.hex())
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
raise TemporaryError('Fail for debug event')
except Exception as ex:
if self.debug:
self.log.error(traceback.format_exc())

5
basicswap/basicswap_util.py

@ -189,6 +189,7 @@ class DebugTypes(IntEnum):
DONT_SPEND_ITX = auto()
SKIP_LOCK_TX_REFUND = auto()
SEND_LOCKED_XMR = auto()
B_LOCK_TX_MISSED_SEND = auto()
def strOfferState(state):
@ -322,8 +323,6 @@ def getLockName(lock_type):
def describeEventEntry(event_type, event_msg):
if event_type == EventLogTypes.FAILED_TX_B_LOCK_PUBLISH:
return 'Failed to publish lock tx B'
if event_type == EventLogTypes.FAILED_TX_B_LOCK_PUBLISH:
return 'Failed to publish lock tx B'
if event_type == EventLogTypes.LOCK_TX_A_PUBLISHED:
@ -456,4 +455,6 @@ def isActiveBidState(state):
return True
if state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX:
return True
if state == BidStates.XMR_SWAP_FAILED:
return True
return False

2
basicswap/interface/btc.py

@ -1186,7 +1186,7 @@ class BTCInterface(CoinInterface):
return True if address_hash == pubkey_hash else False
def showLockTransfers(self, Kbv, Kbs):
def showLockTransfers(self, kbv, Kbs, restore_height):
raise ValueError('Unimplemented')
def getLockTxSwapOutputValue(self, bid, xmr_swap):

17
basicswap/interface/dash.py

@ -20,12 +20,18 @@ class DASHInterface(BTCInterface):
def coin_type():
return Coins.DASH
def __init__(self, coin_settings, network, swap_client=None):
super().__init__(coin_settings, network, swap_client)
self._wallet_passphrase = ''
def seedToMnemonic(self, key):
return Mnemonic('english').to_mnemonic(key)
def initialiseWallet(self, key):
words = self.seedToMnemonic(key)
self.rpc_callback('upgradetohd', [words, ])
mnemonic_passphrase = ''
self.rpc_callback('upgradetohd', [words, mnemonic_passphrase, self._wallet_passphrase])
def decodeAddress(self, address):
return decodeAddress(address)[1:]
@ -70,3 +76,12 @@ class DASHInterface(BTCInterface):
return {'txid': txid_hex, 'amount': 0, 'height': block_height}
return None
def unlockWallet(self, password: str):
super().unlockWallet(password)
# Store password for initialiseWallet
self._wallet_passphrase = password
def lockWallet(self):
super().lockWallet()
self._wallet_passphrase = ''

38
basicswap/interface/xmr.py

@ -5,7 +5,6 @@
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
import os
import json
import logging
@ -100,7 +99,6 @@ class XMRInterface(CoinInterface):
try:
# Can't reopen the same wallet in windows, !is_keys_file_locked()
if os.name == 'nt':
self.rpc_wallet_cb('close_wallet')
except Exception:
pass
@ -263,6 +261,7 @@ class XMRInterface(CoinInterface):
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate, delay_for: int = 10, unlock_time: int = 0) -> bytes:
with self._mx_wallet:
self.openWallet(self._wallet_filename)
self.rpc_wallet_cb('refresh')
shared_addr = xmr_util.encode_address(Kbv, Kbs)
@ -276,8 +275,8 @@ class XMRInterface(CoinInterface):
if self._sc.debug:
i = 0
while not self._sc.delay_event.is_set():
params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
rv = self.rpc_wallet_cb('get_transfers', params)
gt_params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
rv = self.rpc_wallet_cb('get_transfers', gt_params)
self._log.debug('get_transfers {}'.format(dumpj(rv)))
if 'pending' not in rv:
break
@ -292,11 +291,6 @@ class XMRInterface(CoinInterface):
Kbv = self.getPubkey(kbv)
address_b58 = xmr_util.encode_address(Kbv, Kbs)
try:
self.rpc_wallet_cb('close_wallet')
except Exception as e:
self._log.warning('close_wallet failed %s', str(e))
kbv_le = kbv[::-1]
params = {
'restore_height': restore_height,
@ -328,8 +322,12 @@ class XMRInterface(CoinInterface):
rv = None
if 'transfers' in transfers:
for transfer in transfers['transfers']:
# unlocked <- wallet->is_transfer_unlocked() checks unlock_time and CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
if not transfer['unlocked']:
self._log.warning('Coin b lock txn is locked: {}'.format(transfer['tx_hash']))
full_tx = self.rpc_wallet_cb('get_transfer_by_txid', {'txid': transfer['tx_hash']})
unlock_time = full_tx['transfer']['unlock_time']
if unlock_time != 0:
self._log.warning('Coin b lock txn is locked: {}, unlock_time {}'.format(transfer['tx_hash'], unlock_time))
rv = -1
continue
if transfer['amount'] == cb_swap_value:
@ -367,11 +365,6 @@ class XMRInterface(CoinInterface):
Kbs = self.getPubkey(kbs)
address_b58 = xmr_util.encode_address(Kbv, Kbs)
try:
self.rpc_wallet_cb('close_wallet')
except Exception as e:
self._log.warning('close_wallet failed %s', str(e))
wallet_filename = address_b58 + '_spend'
params = {
@ -446,16 +439,29 @@ class XMRInterface(CoinInterface):
rv = self.rpc_wallet_cb('transfer', params)
return rv['tx_hash']
def showLockTransfers(self, Kbv, Kbs):
def showLockTransfers(self, kbv, Kbs, restore_height):
with self._mx_wallet:
try:
Kbv = self.getPubkey(kbv)
address_b58 = xmr_util.encode_address(Kbv, Kbs)
wallet_file = address_b58 + '_spend'
try:
self.openWallet(wallet_file)
except Exception:
wallet_file = address_b58
try:
self.openWallet(wallet_file)
except Exception:
self._log.info(f'showLockTransfers trying to create wallet for address {address_b58}.')
kbv_le = kbv[::-1]
params = {
'restore_height': restore_height,
'filename': address_b58,
'address': address_b58,
'viewkey': b2h(kbv_le),
}
self.createWallet(params)
self.openWallet(address_b58)
self.rpc_wallet_cb('refresh')

12
basicswap/js_server.py

@ -168,11 +168,11 @@ def js_offers(self, url_split, post_string, is_json, sent=False):
filters['limit'] = int(get_data_entry(post_data, 'limit'))
assert (filters['limit'] > 0 and filters['limit'] <= PAGE_LIMIT), 'Invalid limit'
offers = self.server.swap_client.listOffers(sent, filters)
offers = swap_client.listOffers(sent, filters)
rv = []
for o in offers:
ci_from = self.server.swap_client.ci(o.coin_from)
ci_to = self.server.swap_client.ci(o.coin_to)
ci_from = swap_client.ci(o.coin_from)
ci_to = swap_client.ci(o.coin_to)
rv.append({
'addr_from': o.addr_from,
'addr_to': o.addr_to,
@ -494,6 +494,10 @@ def js_lock(self, url_split, post_string, is_json):
return bytes(json.dumps({'success': True}), 'UTF-8')
def js_404(self, url_split, post_string, is_json):
return bytes(json.dumps({'Error': 'path unknown'}), 'UTF-8')
def js_help(self, url_split, post_string, is_json):
# TODO: Add details and examples
commands = []
@ -528,5 +532,5 @@ pages = {
def js_url_to_function(url_split):
if len(url_split) > 2:
return pages.get(url_split[2], js_index)
return pages.get(url_split[2], js_404)
return js_index

18
basicswap/protocols/xmr_swap_1.py

@ -91,6 +91,24 @@ def getChainBSplitKey(swap_client, bid, xmr_swap, offer):
return ci_to.encodeKey(swap_client.getPathKey(offer.coin_from, offer.coin_to, bid.created_at, xmr_swap.contract_count, key_type, True if offer.coin_to == Coins.XMR else False))
def getChainBRemoteSplitKey(swap_client, bid, xmr_swap, offer):
ci_from = swap_client.ci(offer.coin_from)
ci_to = swap_client.ci(offer.coin_to)
if bid.was_sent:
if xmr_swap.a_lock_refund_spend_tx:
af_lock_refund_spend_tx_sig = ci_from.extractFollowerSig(xmr_swap.a_lock_refund_spend_tx)
kbsl = ci_from.recoverEncKey(xmr_swap.af_lock_refund_spend_tx_esig, af_lock_refund_spend_tx_sig, xmr_swap.pkasl)
return ci_to.encodeKey(kbsl)
else:
if xmr_swap.a_lock_spend_tx:
al_lock_spend_tx_sig = ci_from.extractLeaderSig(xmr_swap.a_lock_spend_tx)
kbsf = ci_from.recoverEncKey(xmr_swap.al_lock_spend_tx_esig, al_lock_spend_tx_sig, xmr_swap.pkasf)
return ci_to.encodeKey(kbsf)
return None
class XmrSwapInterface(ProtocolInterface):
swap_type = SwapTypes.XMR_SWAP

4
basicswap/templates/bid.html

@ -349,7 +349,7 @@
</div>
<div class="w-full md:w-auto p-1.5">
<button name="edit_bid_submit" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit Bid </button>
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit </button>
</div>
{% else %}
{% if data.show_bidder_seq_diagram %}
@ -393,7 +393,7 @@
{% endif %}
<div class="w-full md:w-auto p-1.5">
<button name="edit_bid" type="submit" value="Edit Bid" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bit </button>
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bid </button>
</div>
{% endif %}
{% if data.was_received == 'True' %}

12
basicswap/templates/bid_xmr.html

@ -305,10 +305,16 @@
{% endif %}
{% if data.xmr_b_half_privatekey %}
<tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold">Key Half:</td>
<td class="py-4 px-6 bold">Key Half (WARNING key data!):</td>
<td class="py-4 monospace">{{ data.xmr_b_half_privatekey }}</td>
</tr>
{% endif %}
{% if data.xmr_b_half_privatekey_remote %}
<tr class="bg-white border-t hover:bg-gray-50">
<td class="py-4 px-6 bold">Remote Key Half:</td>
<td class="py-4 monospace">{{ data.xmr_b_half_privatekey_remote }}</td>
</tr>
{% endif %}
</table>
</div>
</div>
@ -503,7 +509,7 @@
</div>
<div class="w-full md:w-auto p-1.5">
<button name="edit_bid_submit" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit Bid </button>
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Submit Edit </button>
</div>
{% else %}
{% if data.show_bidder_seq_diagram %}
@ -547,7 +553,7 @@
{% endif %}
<div class="w-full md:w-auto p-1.5">
<button name="edit_bid" type="submit" value="Edit Bid" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bit </button>
<svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" ><line x1="2" y1="23" x2="22" y2="23" stroke="#556987"></line> <line data-cap="butt" x1="13" y1="5" x2="17" y2="9"></line> <polygon points="8 18 3 19 4 14 16 2 20 6 8 18"></polygon></g></svg> Edit bid </button>
</div>
{% endif %}
{% if data.was_received == 'True' %}

11
basicswap/ui/page_offers.py

@ -213,7 +213,16 @@ def parseOfferFormData(swap_client, form_data, page_data, options={}):
def postNewOfferFromParsed(swap_client, parsed_data):
swap_type = SwapTypes.SELLER_FIRST
if parsed_data['coin_to'] in (Coins.XMR, Coins.PART_ANON):
if swap_type in parsed_data:
str_swap_type = parsed_data['swap_type'].lower()
if str_swap_type == 'seller_first':
swap_type = SwapTypes.SELLER_FIRST
elif str_swap_type == 'xmr_swap':
swap_type = SwapTypes.XMR_SWAP
else:
raise ValueError('Unknown swap type')
elif parsed_data['coin_to'] in (Coins.XMR, Coins.PART_ANON):
swap_type = SwapTypes.XMR_SWAP
if swap_client.coin_clients[parsed_data['coin_from']]['use_csv'] and swap_client.coin_clients[parsed_data['coin_to']]['use_csv']:

8
basicswap/ui/util.py

@ -28,7 +28,7 @@ from basicswap.basicswap_util import (
getLastBidState,
)
from basicswap.protocols.xmr_swap_1 import getChainBSplitKey
from basicswap.protocols.xmr_swap_1 import getChainBSplitKey, getChainBRemoteSplitKey
PAGE_LIMIT = 50
invalid_coins_from = (Coins.XMR, Coins.PART_ANON)
@ -302,12 +302,16 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b
if swap_client.debug_ui:
try:
data['xmr_b_half_privatekey'] = getChainBSplitKey(swap_client, bid, xmr_swap, offer)
remote_split_key = getChainBRemoteSplitKey(swap_client, bid, xmr_swap, offer)
if remote_split_key:
data['xmr_b_half_privatekey_remote'] = remote_split_key
except Exception as e:
swap_client.log.error(traceback.format_exc())
if show_lock_transfers:
if xmr_swap.pkbs:
data['lock_transfers'] = json.dumps(ci_to.showLockTransfers(xmr_swap.pkbv, xmr_swap.pkbs), indent=4)
data['lock_transfers'] = json.dumps(ci_to.showLockTransfers(xmr_swap.vkbv, xmr_swap.pkbs, bid.chain_b_height_start), indent=4)
else:
data['lock_transfers'] = 'Shared address not yet known.'
else:

18
doc/release-notes.md

@ -3,6 +3,24 @@
==============
0.0.54
==============
- If the XMR daemon is busy the wallet can fail a transfer, later sending the tx unknown to bsx.
- Check for existing transfers before trying to send the chain b lock tx.
- Check for transfers in XMR_SWAP_SCRIPT_COIN_LOCKED state when bid is sent.
- Continually try refund noscript lock tx in XMR_SWAP_FAILED state.
- showLockTransfers will attempt to create a wallet if none exists.
- tests:
- Add B_LOCK_TX_MISSED_SEND debug event and test.
- Store the Dash wallet password in memory for use in upgradetohd
- Remove false positive warning. Check for unlock_time transfer is not unlocked.
- ui:
- Add 'Remote Key Half' to Show More Info section (with debug_ui on)
- api:
- An unknown path will return an error instead of the default/index data.
0.0.32
==============

20
tests/basicswap/test_xmr.py

@ -1318,6 +1318,26 @@ class Test(BaseTest):
assert (txin['txid'] == itx_after['vin'][i]['txid'])
assert (txin['vout'] == itx_after['vin'][i]['vout'])
def test_15_missed_xmr_send(self):
logging.info('---------- Test PART to XMR B lock tx is lost')
swap_clients = self.swap_clients
amt_swap = make_int(random.uniform(0.1, 10.0), scale=8, r=1)
rate_swap = make_int(random.uniform(2.0, 20.0), scale=12, r=1)
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, amt_swap, rate_swap, amt_swap, SwapTypes.XMR_SWAP,
lock_type=TxLockTypes.SEQUENCE_LOCK_BLOCKS, lock_value=28)
wait_for_offer(test_delay_event, swap_clients[1], offer_id)
offer = swap_clients[1].getOffer(offer_id)
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_RECEIVED)
swap_clients[1].setBidDebugInd(bid_id, DebugTypes.B_LOCK_TX_MISSED_SEND)
swap_clients[0].acceptXmrBid(bid_id)
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=1800)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=1800, sent=True)
def test_98_withdraw_all(self):
logging.info('---------- Test XMR withdrawal all')
try:

Loading…
Cancel
Save