doc, tests: Test sequence diagrams are accurate.

Add delay between detecting PTX and redeeming ITX.
Add bid state history to json api.
Hide Tx none states in bid state history.
This commit is contained in:
tecnovert 2022-07-03 23:58:16 +02:00
parent a2afd3f00f
commit 0c620ea388
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
13 changed files with 738 additions and 297 deletions

View file

@ -746,14 +746,11 @@ class BasicSwap(BaseApp):
if not offer:
raise ValueError('Offer not found')
self.loadBidTxns(bid, session)
if offer.swap_type == SwapTypes.XMR_SWAP:
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid.bid_id).first()
self.loadBidTxns(bid, session)
self.watchXmrSwap(bid, offer, xmr_swap)
else:
bid.initiate_tx = session.query(SwapTx).filter(sa.and_(SwapTx.bid_id == bid.bid_id, SwapTx.tx_type == TxTypes.ITX)).first()
bid.participate_tx = session.query(SwapTx).filter(sa.and_(SwapTx.bid_id == bid.bid_id, SwapTx.tx_type == TxTypes.PTX)).first()
self.swaps_in_progress[bid.bid_id] = (bid, offer)
coin_from = Coins(offer.coin_from)
@ -1787,37 +1784,42 @@ class BasicSwap(BaseApp):
session.remove()
self.mxDB.release()
def getBid(self, bid_id):
self.mxDB.acquire()
def getBid(self, bid_id, session=None):
use_session = None
try:
session = scoped_session(self.session_factory)
bid = session.query(Bid).filter_by(bid_id=bid_id).first()
if session:
use_session = session
else:
self.mxDB.acquire()
use_session = scoped_session(self.session_factory)
bid = use_session.query(Bid).filter_by(bid_id=bid_id).first()
if bid:
self.loadBidTxns(bid, session)
self.loadBidTxns(bid, use_session)
return bid
finally:
session.close()
session.remove()
self.mxDB.release()
if session is None:
use_session.close()
use_session.remove()
self.mxDB.release()
def getBidAndOffer(self, bid_id):
self.mxDB.acquire()
def getBidAndOffer(self, bid_id, session=None):
try:
session = scoped_session(self.session_factory)
bid = session.query(Bid).filter_by(bid_id=bid_id).first()
if session:
use_session = session
else:
self.mxDB.acquire()
use_session = scoped_session(self.session_factory)
bid = use_session.query(Bid).filter_by(bid_id=bid_id).first()
offer = None
if bid:
offer = session.query(Offer).filter_by(offer_id=bid.offer_id).first()
if offer and offer.swap_type == SwapTypes.XMR_SWAP:
self.loadBidTxns(bid, session)
else:
bid.initiate_tx = session.query(SwapTx).filter(sa.and_(SwapTx.bid_id == bid_id, SwapTx.tx_type == TxTypes.ITX)).first()
bid.participate_tx = session.query(SwapTx).filter(sa.and_(SwapTx.bid_id == bid_id, SwapTx.tx_type == TxTypes.PTX)).first()
offer = use_session.query(Offer).filter_by(offer_id=bid.offer_id).first()
self.loadBidTxns(bid, use_session)
return bid, offer
finally:
session.close()
session.remove()
self.mxDB.release()
if session is None:
use_session.close()
use_session.remove()
self.mxDB.release()
def getXmrBidAndOffer(self, bid_id, list_events=True):
self.mxDB.acquire()
@ -1834,10 +1836,7 @@ class BasicSwap(BaseApp):
if offer and offer.swap_type == SwapTypes.XMR_SWAP:
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid.bid_id).first()
xmr_offer = session.query(XmrOffer).filter_by(offer_id=bid.offer_id).first()
self.loadBidTxns(bid, session)
else:
bid.initiate_tx = session.query(SwapTx).filter(sa.and_(SwapTx.bid_id == bid_id, SwapTx.tx_type == TxTypes.ITX)).first()
bid.participate_tx = session.query(SwapTx).filter(sa.and_(SwapTx.bid_id == bid_id, SwapTx.tx_type == TxTypes.PTX)).first()
self.loadBidTxns(bid, session)
if list_events:
events = self.list_bid_events(bid.bid_id, session)
@ -2941,7 +2940,7 @@ 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 in (BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX, BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX):
elif state == BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX:
if bid.xmr_a_lock_tx is None:
return rv
@ -3337,19 +3336,14 @@ class BasicSwap(BaseApp):
bid.setPTxState(TxStates.TX_REDEEMED)
if bid.was_sent:
txn = self.createRedeemTxn(coin_from, bid, for_txn_type='initiate')
if bid.debug_ind == DebugTypes.DONT_SPEND_ITX:
self.log.debug('bid %s: Abandoning bid for testing: %d, %s.', bid_id.hex(), bid.debug_ind, DebugTypes(bid.debug_ind).name)
bid.setState(BidStates.BID_ABANDONED)
self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), None)
else:
txid = self.submitTxn(coin_from, txn)
bid.initiate_tx.spend_txid = bytes.fromhex(txid)
# bid.initiate_txn_redeem = bytes.fromhex(txn) # Worth keeping?
self.log.debug('Submitted initiate redeem txn %s to %s chain for bid %s', txid, chainparams[coin_from]['name'], bid_id.hex())
delay = random.randrange(self.min_delay_event_short, self.max_delay_event_short)
self.log.info('Redeeming ITX for bid %s in %d seconds', bid_id.hex(), delay)
self.createAction(delay, ActionTypes.REDEEM_ITX, bid_id)
# TODO: Wait for depth? new state SWAP_TXI_REDEEM_SENT?
self.removeWatchedOutput(coin_to, bid_id, bid.participate_tx.txid.hex())
@ -3582,6 +3576,8 @@ class BasicSwap(BaseApp):
self.recoverXmrBidCoinBLockTx(row.linked_id, session)
elif row.action_type == ActionTypes.SEND_XMR_SWAP_LOCK_SPEND_MSG:
self.sendXmrBidCoinALockSpendTxMsg(row.linked_id, session)
elif row.action_type == ActionTypes.REDEEM_ITX:
atomic_swap_1.redeemITx(self, row.linked_id, session)
else:
self.log.warning('Unknown event type: %d', row.event_type)
except Exception as ex:
@ -4843,6 +4839,7 @@ class BasicSwap(BaseApp):
ci_from.verifyCompact(xmr_swap.pkal, 'proof key owned for swap', xmr_swap.kal_sig)
bid.setState(BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX)
bid.setState(BidStates.XMR_SWAP_MSG_SCRIPT_LOCK_SPEND_TX)
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
except Exception as ex:
if self.debug:

View file

@ -135,6 +135,7 @@ class ActionTypes(IntEnum):
REDEEM_XMR_SWAP_LOCK_TX_B = auto() # Leader
RECOVER_XMR_SWAP_LOCK_TX_B = auto()
SEND_XMR_SWAP_LOCK_SPEND_MSG = auto()
REDEEM_ITX = auto()
class EventLogTypes(IntEnum):

View file

@ -6,7 +6,6 @@
import os
import json
import struct
import traceback
import threading
import http.client
@ -55,6 +54,7 @@ from .ui.util import (
listBidStates,
get_data_entry,
have_data_entry,
listOldBidStates,
get_data_entry_or,
listAvailableCoins,
set_pagination_filters,
@ -695,23 +695,7 @@ class HttpHandler(BaseHTTPRequestHandler):
data['show_bidder_seq_diagram'] = show_bidder_seq_diagram
data['show_offerer_seq_diagram'] = show_offerer_seq_diagram
old_states = []
num_states = len(bid.states) // 12
for i in range(num_states):
up = struct.unpack_from('<iq', bid.states[i * 12:(i + 1) * 12])
old_states.append((up[1], 'Bid ' + strBidState(up[0])))
if bid.initiate_tx and bid.initiate_tx.states is not None:
num_states = len(bid.initiate_tx.states) // 12
for i in range(num_states):
up = struct.unpack_from('<iq', bid.initiate_tx.states[i * 12:(i + 1) * 12])
old_states.append((up[1], 'ITX ' + strTxState(up[0])))
if bid.participate_tx and bid.participate_tx.states is not None:
num_states = len(bid.participate_tx.states) // 12
for i in range(num_states):
up = struct.unpack_from('<iq', bid.participate_tx.states[i * 12:(i + 1) * 12])
old_states.append((up[1], 'PTX ' + strTxState(up[0])))
if len(old_states) > 0:
old_states.sort(key=lambda x: x[0])
old_states = listOldBidStates(bid)
if len(data['addr_from_label']) > 0:
data['addr_from_label'] = '(' + data['addr_from_label'] + ')'

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 tecnovert
# Copyright (c) 2020-2022 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -27,6 +27,7 @@ from .ui.util import (
get_data_entry_or,
have_data_entry,
tickerToCoinId,
listOldBidStates,
)
from .ui.page_offers import postNewOffer
from .protocols.xmr_swap_1 import recoverNoScriptTxnWithKey, getChainBSplitKey
@ -230,6 +231,10 @@ def js_bids(self, url_split, post_string, is_json):
remote_key = get_data_entry(post_data, 'remote_key')
return bytes(json.dumps({'txid': recoverNoScriptTxnWithKey(swap_client, bid_id, remote_key).hex()}), 'UTF-8')
if len(url_split) > 4 and url_split[4] == 'states':
old_states = listOldBidStates(bid)
return bytes(json.dumps(old_states), 'UTF-8')
edit_bid = False
show_txns = False
data = describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, events, edit_bid, show_txns, for_api=True)

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 tecnovert
# Copyright (c) 2020-2022 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -11,7 +11,6 @@ from basicswap.script import (
OpCodes,
)
INITIATE_TX_TIMEOUT = 40 * 60 # TODO: make variable per coin
@ -48,3 +47,14 @@ def buildContractScript(lock_val, secret_hash, pkh_redeem, pkh_refund, op_lock=O
def extractScriptSecretHash(script):
return script[7:39]
def redeemITx(self, bid_id, session):
bid, offer = self.getBidAndOffer(bid_id, session)
ci_from = self.ci(offer.coin_from)
txn = self.createRedeemTxn(ci_from.coin_type(), bid, for_txn_type='initiate')
txid = self.submitTxn(ci_from.coin_type(), txn)
bid.initiate_tx.spend_txid = bytes.fromhex(txid)
self.log.debug('Submitted initiate redeem txn %s to %s chain for bid %s', txid, ci_from.coin_name(), bid_id.hex())

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -1,4 +1,4 @@
<svg version="1.1" id="mscgenjsreplaceme" class="mscgenjsreplaceme" xmlns="http://www.w3.org/2000/svg" width="1272" height="2025.3" style="font-family:Helvetica,sans-serif;font-size:12px;font-weight:400;font-style:normal;text-decoration:none;background-color:#fff;stroke:#000;stroke-width:2">
<svg version="1.1" id="mscgenjsreplaceme" class="mscgenjsreplaceme" xmlns="http://www.w3.org/2000/svg" width="1272" height="2063.3" style="font-family:Helvetica,sans-serif;font-size:12px;font-weight:400;font-style:normal;text-decoration:none;background-color:#fff;stroke:#000;stroke-width:2">
<defs>
<marker orient="auto" id="mscgenjsreplacemecallback-#0000FF" class="arrow-marker" viewBox="0 0 10 10" refX="9" refY="3" markerUnits="strokeWidth" markerWidth="10" markerHeight="10">
<path d="m1 1 8 2-8 2" class="arrow-style" style="stroke-dasharray:100,1;stroke:#00f"/>
@ -35,10 +35,10 @@
</style>
</defs>
<g id="mscgenjsreplaceme_body" transform="translate(51 3)">
<path class="bglayer" style="fill:#fff;stroke:#fff;stroke-width:0" d="M-51-3h1272v2025.3H-51z" id="mscgenjsreplaceme_background"/>
<path class="bglayer" style="fill:#fff;stroke:#fff;stroke-width:0" d="M-51-3h1272v2063.3H-51z" id="mscgenjsreplaceme_background"/>
<g id="mscgenjsreplaceme_arcspans">
<path class="box inline_expression alt" d="M-41 680.06h1044V2000.3H-41z"/>
<path class="box inline_expression alt" d="M-37 1372.18H999v590.12H-37z"/>
<path class="box inline_expression alt" d="M-41 718.06h1044V2038.3H-41z"/>
<path class="box inline_expression alt" d="M-37 1410.18H999v590.12H-37z"/>
</g>
<g id="mscgenjsreplaceme_lifelines">
<path class="arcrow" style="stroke:transparent" d="M65 38v38"/>
@ -93,15 +93,15 @@
<path class="arcrow" style="stroke:#080" d="M273 510v38"/>
<path class="arcrow" style="stroke:red" d="M481 510v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 510v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 510v38M1105 510v38M65 548v75.06"/>
<path class="arcrow" style="stroke:#080" d="M273 548v75.06"/>
<path class="arcrow" style="stroke:red" d="M481 548v75.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 548v75.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 548v75.06M1105 548v75.06M65 623.06v38"/>
<path class="arcrow" style="stroke:#080" d="M273 623.06v38"/>
<path class="arcrow" style="stroke:red" d="M481 623.06v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 623.06v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 623.06v38M1105 623.06v38M65 661.06v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 510v38M1105 510v38M65 548v38"/>
<path class="arcrow" style="stroke:#080" d="M273 548v38"/>
<path class="arcrow" style="stroke:red" d="M481 548v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 548v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 548v38M1105 548v38M65 586v75.06"/>
<path class="arcrow" style="stroke:#080" d="M273 586v75.06"/>
<path class="arcrow" style="stroke:red" d="M481 586v75.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 586v75.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 586v75.06M1105 586v75.06M65 661.06v38"/>
<path class="arcrow" style="stroke:#080" d="M273 661.06v38"/>
<path class="arcrow" style="stroke:red" d="M481 661.06v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 661.06v38"/>
@ -109,23 +109,23 @@
<path class="arcrow" style="stroke:#080" d="M273 699.06v38"/>
<path class="arcrow" style="stroke:red" d="M481 699.06v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 699.06v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 699.06v38M1105 699.06v38M65 737.06v75.06"/>
<path class="arcrow" style="stroke:#080" d="M273 737.06v75.06"/>
<path class="arcrow" style="stroke:red" d="M481 737.06v75.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 737.06v75.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 737.06v75.06M1105 737.06v75.06M65 812.12v38"/>
<path class="arcrow" style="stroke:#080" d="M273 812.12v38"/>
<path class="arcrow" style="stroke:red" d="M481 812.12v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 812.12v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 812.12v38M1105 812.12v38M65 850.12v86"/>
<path class="arcrow" style="stroke:#080" d="M273 850.12v86"/>
<path class="arcrow" style="stroke:red" d="M481 850.12v86"/>
<path class="arcrow" style="stroke:#00f" d="M689 850.12v86"/>
<path class="arcrow" style="stroke:transparent" d="M897 850.12v86M1105 850.12v86M65 936.12v38"/>
<path class="arcrow" style="stroke:#080" d="M273 936.12v38"/>
<path class="arcrow" style="stroke:red" d="M481 936.12v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 936.12v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 936.12v38M1105 936.12v38M65 974.12v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 699.06v38M1105 699.06v38M65 737.06v38"/>
<path class="arcrow" style="stroke:#080" d="M273 737.06v38"/>
<path class="arcrow" style="stroke:red" d="M481 737.06v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 737.06v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 737.06v38M1105 737.06v38M65 775.06v75.06"/>
<path class="arcrow" style="stroke:#080" d="M273 775.06v75.06"/>
<path class="arcrow" style="stroke:red" d="M481 775.06v75.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 775.06v75.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 775.06v75.06M1105 775.06v75.06M65 850.12v38"/>
<path class="arcrow" style="stroke:#080" d="M273 850.12v38"/>
<path class="arcrow" style="stroke:red" d="M481 850.12v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 850.12v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 850.12v38M1105 850.12v38M65 888.12v86"/>
<path class="arcrow" style="stroke:#080" d="M273 888.12v86"/>
<path class="arcrow" style="stroke:red" d="M481 888.12v86"/>
<path class="arcrow" style="stroke:#00f" d="M689 888.12v86"/>
<path class="arcrow" style="stroke:transparent" d="M897 888.12v86M1105 888.12v86M65 974.12v38"/>
<path class="arcrow" style="stroke:#080" d="M273 974.12v38"/>
<path class="arcrow" style="stroke:red" d="M481 974.12v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 974.12v38"/>
@ -145,15 +145,15 @@
<path class="arcrow" style="stroke:#080" d="M273 1126.12v38"/>
<path class="arcrow" style="stroke:red" d="M481 1126.12v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1126.12v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1126.12v38M1105 1126.12v38M65 1164.12v75.06"/>
<path class="arcrow" style="stroke:#080" d="M273 1164.12v75.06"/>
<path class="arcrow" style="stroke:red" d="M481 1164.12v75.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 1164.12v75.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 1164.12v75.06M1105 1164.12v75.06M65 1239.18v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1239.18v38"/>
<path class="arcrow" style="stroke:red" d="M481 1239.18v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1239.18v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1239.18v38M1105 1239.18v38M65 1277.18v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1126.12v38M1105 1126.12v38M65 1164.12v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1164.12v38"/>
<path class="arcrow" style="stroke:red" d="M481 1164.12v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1164.12v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1164.12v38M1105 1164.12v38M65 1202.12v75.06"/>
<path class="arcrow" style="stroke:#080" d="M273 1202.12v75.06"/>
<path class="arcrow" style="stroke:red" d="M481 1202.12v75.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 1202.12v75.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 1202.12v75.06M1105 1202.12v75.06M65 1277.18v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1277.18v38"/>
<path class="arcrow" style="stroke:red" d="M481 1277.18v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1277.18v38"/>
@ -169,19 +169,19 @@
<path class="arcrow" style="stroke:#080" d="M273 1391.18v38"/>
<path class="arcrow" style="stroke:red" d="M481 1391.18v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1391.18v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1391.18v38M1105 1391.18v38M65 1429.18v59.06"/>
<path class="arcrow" style="stroke:#080" d="M273 1429.18v59.06"/>
<path class="arcrow" style="stroke:red" d="M481 1429.18v59.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 1429.18v59.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 1429.18v59.06M1105 1429.18v59.06M65 1488.24v54"/>
<path class="arcrow" style="stroke:#080" d="M273 1488.24v54"/>
<path class="arcrow" style="stroke:red" d="M481 1488.24v54"/>
<path class="arcrow" style="stroke:#00f" d="M689 1488.24v54"/>
<path class="arcrow" style="stroke:transparent" d="M897 1488.24v54M1105 1488.24v54M65 1542.24v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1542.24v38"/>
<path class="arcrow" style="stroke:red" d="M481 1542.24v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1542.24v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1542.24v38M1105 1542.24v38M65 1580.24v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1391.18v38M1105 1391.18v38M65 1429.18v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1429.18v38"/>
<path class="arcrow" style="stroke:red" d="M481 1429.18v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1429.18v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1429.18v38M1105 1429.18v38M65 1467.18v59.06"/>
<path class="arcrow" style="stroke:#080" d="M273 1467.18v59.06"/>
<path class="arcrow" style="stroke:red" d="M481 1467.18v59.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 1467.18v59.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 1467.18v59.06M1105 1467.18v59.06M65 1526.24v54"/>
<path class="arcrow" style="stroke:#080" d="M273 1526.24v54"/>
<path class="arcrow" style="stroke:red" d="M481 1526.24v54"/>
<path class="arcrow" style="stroke:#00f" d="M689 1526.24v54"/>
<path class="arcrow" style="stroke:transparent" d="M897 1526.24v54M1105 1526.24v54M65 1580.24v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1580.24v38"/>
<path class="arcrow" style="stroke:red" d="M481 1580.24v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1580.24v38"/>
@ -205,15 +205,15 @@
<path class="arcrow" style="stroke:#080" d="M273 1770.24v38"/>
<path class="arcrow" style="stroke:red" d="M481 1770.24v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1770.24v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1770.24v38M1105 1770.24v38M65 1808.24v59.06"/>
<path class="arcrow" style="stroke:#080" d="M273 1808.24v59.06"/>
<path class="arcrow" style="stroke:red" d="M481 1808.24v59.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 1808.24v59.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 1808.24v59.06M1105 1808.24v59.06M65 1867.3v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1867.3v38"/>
<path class="arcrow" style="stroke:red" d="M481 1867.3v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1867.3v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1867.3v38M1105 1867.3v38M65 1905.3v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1770.24v38M1105 1770.24v38M65 1808.24v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1808.24v38"/>
<path class="arcrow" style="stroke:red" d="M481 1808.24v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1808.24v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1808.24v38M1105 1808.24v38M65 1846.24v59.06"/>
<path class="arcrow" style="stroke:#080" d="M273 1846.24v59.06"/>
<path class="arcrow" style="stroke:red" d="M481 1846.24v59.06"/>
<path class="arcrow" style="stroke:#00f" d="M689 1846.24v59.06"/>
<path class="arcrow" style="stroke:transparent" d="M897 1846.24v59.06M1105 1846.24v59.06M65 1905.3v38"/>
<path class="arcrow" style="stroke:#080" d="M273 1905.3v38"/>
<path class="arcrow" style="stroke:red" d="M481 1905.3v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1905.3v38"/>
@ -225,7 +225,11 @@
<path class="arcrow" style="stroke:#080" d="M273 1981.3v38"/>
<path class="arcrow" style="stroke:red" d="M481 1981.3v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 1981.3v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1981.3v38M1105 1981.3v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 1981.3v38M1105 1981.3v38M65 2019.3v38"/>
<path class="arcrow" style="stroke:#080" d="M273 2019.3v38"/>
<path class="arcrow" style="stroke:red" d="M481 2019.3v38"/>
<path class="arcrow" style="stroke:#00f" d="M689 2019.3v38"/>
<path class="arcrow" style="stroke:transparent" d="M897 2019.3v38M1105 2019.3v38"/>
</g>
<g id="mscgenjsreplaceme_sequence">
<path class="entity" style="stroke:transparent" d="M0 0h130v38H0z"/>
@ -261,83 +265,83 @@
<path class="arc directional callback" style="stroke:red" marker-end="url(#mscgenjsreplacemecallback-#FF0000)" d="M481 529H273"/>
<path class="label-text-background" d="M311.64 513.25h130.72v14H311.64z"/>
<text x="377" y="524.25" class="directional-text callback-text"><tspan>Sends script-coin-lock-tx</tspan></text>
<path d="M689 577.93c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 529.67h40.91v14.02H692z"/>
<text x="692" y="540.68" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 545.67h107.02v14.02H692z"/>
<text x="692" y="556.68" class="directional-text method-text anchor-start"><tspan>script-coin-lock-tx to</tspan></text>
<path class="label-text-background" d="M692 561.67h39.34v14.02H692z"/>
<text x="692" y="572.68" class="directional-text method-text anchor-start"><tspan>confirm</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 718.06H273"/>
<path class="label-text-background" d="M408.97 702.3h144.06v14.02H408.97z"/>
<text x="481" y="713.31" class="directional-text callback-text"><tspan>Sends noscript-coin-lock-tx</tspan></text>
<path d="M689 766.99c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 718.73h40.91v14.02H692z"/>
<text x="692" y="729.74" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 734.73h120.38v14.02H692z"/>
<text x="692" y="745.74" class="directional-text method-text anchor-start"><tspan>noscript-coin-lock-tx to</tspan></text>
<path class="label-text-background" d="M692 750.73h39.34v14.02H692z"/>
<text x="692" y="761.74" class="directional-text method-text anchor-start"><tspan>confirm</tspan></text>
<path d="M481 766.99c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:red" marker-end="url(#mscgenjsreplacememethod-#FF0000)"/>
<path class="label-text-background" d="M484 718.73h40.91v14.02H484z"/>
<text x="484" y="729.74" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M484 734.73h120.38v14.02H484z"/>
<text x="484" y="745.74" class="directional-text method-text anchor-start"><tspan>noscript-coin-lock-tx to</tspan></text>
<path class="label-text-background" d="M484 750.73h39.34v14.02H484z"/>
<text x="484" y="761.74" class="directional-text method-text anchor-start"><tspan>confirm</tspan></text>
<path class="arc directional method" style="stroke:red" marker-end="url(#mscgenjsreplacememethod-#FF0000)" d="M481 893.12h208"/>
<path class="label-text-background" d="M519.64 877.36h130.72v14.02H519.64z"/>
<text x="585" y="888.37" class="directional-text method-text"><tspan>Sends script-coin-lock-tx</tspan></text>
<path class="label-text-background" d="M539.3 895.36h91.73v14.02H539.3z"/>
<text x="585" y="906.37" class="directional-text method-text"><tspan>release message</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 993.12H273"/>
<path class="label-text-background" d="M397.3 977.36h167.41v14.02H397.3z"/>
<text x="481" y="988.37" class="directional-text callback-text"><tspan>Sends script-coin-lock-spend-tx</tspan></text>
<path class="inline_expression_divider" d="M-41 1107.12h1044"/>
<path class="label-text-background" d="M459.98 1099.86h42.03v14.02h-42.03z"/>
<text x="481" y="1110.87" class="empty-text comment-row-text"><tspan>fail path</tspan></text>
<path d="M689 1194.05c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 1145.8h40.91v14.02H692z"/>
<text x="692" y="1156.8" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 1161.8h131.69v14.02H692z"/>
<text x="692" y="1172.8" class="directional-text method-text anchor-start"><tspan>script-coin-lock-tx lock to</tspan></text>
<path class="label-text-background" d="M692 1177.8h33.02v14.02H692z"/>
<text x="692" y="1188.8" class="directional-text method-text anchor-start"><tspan>expire</tspan></text>
<path class="arc directional callback" style="stroke:red" marker-end="url(#mscgenjsreplacemecallback-#FF0000)" d="M481 1258.18H273"/>
<path class="label-text-background" d="M359.98 1242.42h34.03v14.02h-34.03z"/>
<text x="377" y="1253.43" class="directional-text callback-text"><tspan>Sends</tspan></text>
<path class="label-text-background" d="M300.64 1260.42h152.72v14.02H300.64z"/>
<text x="377" y="1271.43" class="directional-text callback-text"><tspan>script-coin-lock-pre-refund-tx</tspan></text>
<path class="arc directional return" style="stroke:#080" marker-end="url(#mscgenjsreplacemecallback-#008800)" d="M273 1296.18h208"/>
<path class="label-text-background" d="M300.64 1280.42h152.72v14.02H300.64z"/>
<text x="377" y="1291.43" class="directional-text return-text"><tspan>script-coin-lock-pre-refund-tx</tspan></text>
<path d="M481 1451.11c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:red" marker-end="url(#mscgenjsreplacememethod-#FF0000)"/>
<path class="label-text-background" d="M484 1418.86h40.91v14.02H484z"/>
<text x="484" y="1429.86" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M484 1434.86h124.06v14.02H484z"/>
<text x="484" y="1445.86" class="directional-text method-text anchor-start"><tspan>pre-refund tx to confirm</tspan></text>
<path class="arc directional callback" style="stroke:red" marker-end="url(#mscgenjsreplacemecallback-#FF0000)" d="M481 1515.24H273"/>
<path class="label-text-background" d="M359.98 1499.48h34.03v14.02h-34.03z"/>
<text x="377" y="1510.49" class="directional-text callback-text"><tspan>Sends</tspan></text>
<path class="label-text-background" d="M282.3 1517.48h189.41v14.02H282.3z"/>
<text x="377" y="1528.49" class="directional-text callback-text"><tspan>script-coin-lock-pre-refund-spend-tx</tspan></text>
<path class="arc directional return" style="stroke:#080" marker-end="url(#mscgenjsreplacemecallback-#008800)" d="M273 1599.24h416"/>
<path class="label-text-background" d="M364.28 1583.48h233.44v14.02H364.28z"/>
<text x="481" y="1594.49" class="directional-text return-text"><tspan>Detects script-coin-lock-pre-refund-spend-tx</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 1637.24H273"/>
<path class="label-text-background" d="M382.97 1621.48h196.06v14.02H382.97z"/>
<text x="481" y="1632.49" class="directional-text callback-text"><tspan>Sends scriptless-coin-lock-recover-tx</tspan></text>
<path class="inline_expression_divider" d="M-37 1751.24H999"/>
<path class="label-text-background" d="M396.95 1743.98h168.09V1758H396.95z"/>
<text x="481" y="1754.99" class="empty-text comment-row-text"><tspan>bidder swipes script coin lock tx</tspan></text>
<path d="M689 1830.17c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 1797.91h40.91v14.02H692z"/>
<text x="692" y="1808.92" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 1813.91h142.41v14.02H692z"/>
<text x="692" y="1824.92" class="directional-text method-text anchor-start"><tspan>pre-refund tx lock to expire</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 1886.3H273"/>
<path class="label-text-background" d="M368.63 1870.55h224.75v14.02H368.63z"/>
<text x="481" y="1881.55" class="directional-text callback-text"><tspan>Sends script-coin-lock-pre-refund-swipe-tx</tspan></text>
<path d="M689 615.93c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 567.67h40.91v14.02H692z"/>
<text x="692" y="578.68" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 583.67h107.02v14.02H692z"/>
<text x="692" y="594.68" class="directional-text method-text anchor-start"><tspan>script-coin-lock-tx to</tspan></text>
<path class="label-text-background" d="M692 599.67h39.34v14.02H692z"/>
<text x="692" y="610.68" class="directional-text method-text anchor-start"><tspan>confirm</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 756.06H273"/>
<path class="label-text-background" d="M408.97 740.3h144.06v14.02H408.97z"/>
<text x="481" y="751.31" class="directional-text callback-text"><tspan>Sends noscript-coin-lock-tx</tspan></text>
<path d="M689 804.99c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 756.73h40.91v14.02H692z"/>
<text x="692" y="767.74" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 772.73h120.38v14.02H692z"/>
<text x="692" y="783.74" class="directional-text method-text anchor-start"><tspan>noscript-coin-lock-tx to</tspan></text>
<path class="label-text-background" d="M692 788.73h39.34v14.02H692z"/>
<text x="692" y="799.74" class="directional-text method-text anchor-start"><tspan>confirm</tspan></text>
<path d="M481 804.99c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:red" marker-end="url(#mscgenjsreplacememethod-#FF0000)"/>
<path class="label-text-background" d="M484 756.73h40.91v14.02H484z"/>
<text x="484" y="767.74" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M484 772.73h120.38v14.02H484z"/>
<text x="484" y="783.74" class="directional-text method-text anchor-start"><tspan>noscript-coin-lock-tx to</tspan></text>
<path class="label-text-background" d="M484 788.73h39.34v14.02H484z"/>
<text x="484" y="799.74" class="directional-text method-text anchor-start"><tspan>confirm</tspan></text>
<path class="arc directional method" style="stroke:red" marker-end="url(#mscgenjsreplacememethod-#FF0000)" d="M481 931.12h208"/>
<path class="label-text-background" d="M519.64 915.36h130.72v14.02H519.64z"/>
<text x="585" y="926.37" class="directional-text method-text"><tspan>Sends script-coin-lock-tx</tspan></text>
<path class="label-text-background" d="M539.3 933.36h91.73v14.02H539.3z"/>
<text x="585" y="944.37" class="directional-text method-text"><tspan>release message</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 1031.12H273"/>
<path class="label-text-background" d="M397.3 1015.36h167.41v14.02H397.3z"/>
<text x="481" y="1026.37" class="directional-text callback-text"><tspan>Sends script-coin-lock-spend-tx</tspan></text>
<path class="inline_expression_divider" d="M-41 1145.12h1044"/>
<path class="label-text-background" d="M459.98 1137.86h42.03v14.02h-42.03z"/>
<text x="481" y="1148.87" class="empty-text comment-row-text"><tspan>fail path</tspan></text>
<path d="M689 1232.05c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 1183.8h40.91v14.02H692z"/>
<text x="692" y="1194.8" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 1199.8h131.69v14.02H692z"/>
<text x="692" y="1210.8" class="directional-text method-text anchor-start"><tspan>script-coin-lock-tx lock to</tspan></text>
<path class="label-text-background" d="M692 1215.8h33.02v14.02H692z"/>
<text x="692" y="1226.8" class="directional-text method-text anchor-start"><tspan>expire</tspan></text>
<path class="arc directional callback" style="stroke:red" marker-end="url(#mscgenjsreplacemecallback-#FF0000)" d="M481 1296.18H273"/>
<path class="label-text-background" d="M359.98 1280.42h34.03v14.02h-34.03z"/>
<text x="377" y="1291.43" class="directional-text callback-text"><tspan>Sends</tspan></text>
<path class="label-text-background" d="M300.64 1298.42h152.72v14.02H300.64z"/>
<text x="377" y="1309.43" class="directional-text callback-text"><tspan>script-coin-lock-pre-refund-tx</tspan></text>
<path class="arc directional return" style="stroke:#080" marker-end="url(#mscgenjsreplacemecallback-#008800)" d="M273 1334.18h208"/>
<path class="label-text-background" d="M300.64 1318.42h152.72v14.02H300.64z"/>
<text x="377" y="1329.43" class="directional-text return-text"><tspan>script-coin-lock-pre-refund-tx</tspan></text>
<path d="M481 1489.11c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:red" marker-end="url(#mscgenjsreplacememethod-#FF0000)"/>
<path class="label-text-background" d="M484 1456.86h40.91v14.02H484z"/>
<text x="484" y="1467.86" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M484 1472.86h124.06v14.02H484z"/>
<text x="484" y="1483.86" class="directional-text method-text anchor-start"><tspan>pre-refund tx to confirm</tspan></text>
<path class="arc directional callback" style="stroke:red" marker-end="url(#mscgenjsreplacemecallback-#FF0000)" d="M481 1553.24H273"/>
<path class="label-text-background" d="M359.98 1537.48h34.03v14.02h-34.03z"/>
<text x="377" y="1548.49" class="directional-text callback-text"><tspan>Sends</tspan></text>
<path class="label-text-background" d="M282.3 1555.48h189.41v14.02H282.3z"/>
<text x="377" y="1566.49" class="directional-text callback-text"><tspan>script-coin-lock-pre-refund-spend-tx</tspan></text>
<path class="arc directional return" style="stroke:#080" marker-end="url(#mscgenjsreplacemecallback-#008800)" d="M273 1637.24h416"/>
<path class="label-text-background" d="M364.28 1621.48h233.44v14.02H364.28z"/>
<text x="481" y="1632.49" class="directional-text return-text"><tspan>Detects script-coin-lock-pre-refund-spend-tx</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 1675.24H273"/>
<path class="label-text-background" d="M382.97 1659.48h196.06v14.02H382.97z"/>
<text x="481" y="1670.49" class="directional-text callback-text"><tspan>Sends scriptless-coin-lock-recover-tx</tspan></text>
<path class="inline_expression_divider" d="M-37 1789.24H999"/>
<path class="label-text-background" d="M396.95 1781.98h168.09V1796H396.95z"/>
<text x="481" y="1792.99" class="empty-text comment-row-text"><tspan>bidder swipes script coin lock tx</tspan></text>
<path d="M689 1868.17c104 .1 104 22.8 0 22.8" class="arc directional method" style="stroke:#00f" marker-end="url(#mscgenjsreplacememethod-#0000FF)"/>
<path class="label-text-background" d="M692 1835.91h40.91v14.02H692z"/>
<text x="692" y="1846.92" class="directional-text method-text anchor-start"><tspan>Wait for</tspan></text>
<path class="label-text-background" d="M692 1851.91h142.41v14.02H692z"/>
<text x="692" y="1862.92" class="directional-text method-text anchor-start"><tspan>pre-refund tx lock to expire</tspan></text>
<path class="arc directional callback" style="stroke:#00f" marker-end="url(#mscgenjsreplacemecallback-#0000FF)" d="M689 1924.3H273"/>
<path class="label-text-background" d="M368.63 1908.55h224.75v14.02H368.63z"/>
<text x="481" y="1919.55" class="directional-text callback-text"><tspan>Sends script-coin-lock-pre-refund-swipe-tx</tspan></text>
</g>
<g id="mscgenjsreplaceme_notes">
<path d="m591 209 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
@ -363,45 +367,48 @@
<text x="1001" y="502.75" class="box-text note-text"><tspan>the offerer&apos;s signature for it.</tspan></text>
<path d="m591 529 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="532.75" class="box-text abox-text"><tspan>Bid Script coin spend tx valid</tspan></text>
<path d="m591 642.06 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="645.81" class="box-text abox-text"><tspan>Bid Script coin locked</tspan></text>
<path d="M-40 680.06h98.39v11.02l-7 7H-40" class="box inline_expression_label"/>
<text x="-38" y="693.31" class="inline_expression-text alt-text anchor-start"><tspan>alt: success path</tspan></text>
<path d="m591 831.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="834.87" class="box-text abox-text"><tspan>Bid Scriptless coin locked</tspan></text>
<path d="M799 852.11h395v9h9m-9-9 9 9v73.02H799v-82.02z" class="box note" style="fill:#ffc"/>
<text x="1001" y="864.87" class="box-text note-text"><tspan>The XmrBidLockReleaseMessage contains the offerer&apos;s OTVES for it. </tspan></text>
<text x="1001" y="880.87" class="box-text note-text"><tspan> The bidder decodes the offerer&apos;s signature</tspan></text>
<text x="1001" y="896.87" class="box-text note-text"><tspan>from the OTVES. When the offerer has the</tspan></text>
<text x="1001" y="912.87" class="box-text note-text"><tspan>plaintext signature, they can decode the bidder&apos;s noscript-coin-lock-tx</tspan></text>
<text x="1001" y="928.87" class="box-text note-text"><tspan>signature.</tspan></text>
<path d="m591 955.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="958.87" class="box-text abox-text"><tspan>Script coin lock released</tspan></text>
<path d="m591 1031.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1034.87" class="box-text abox-text"><tspan>Script tx redeemed</tspan></text>
<path d="m591 567 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="562.75" class="box-text abox-text"><tspan>Exchanged script lock spend tx</tspan></text>
<text x="689" y="578.75" class="box-text abox-text"><tspan>msg</tspan></text>
<path d="m591 680.06 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="683.81" class="box-text abox-text"><tspan>Bid Script coin locked</tspan></text>
<path d="M-40 718.06h98.39v11.02l-7 7H-40" class="box inline_expression_label"/>
<text x="-38" y="731.31" class="inline_expression-text alt-text anchor-start"><tspan>alt: success path</tspan></text>
<path d="m591 869.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="872.87" class="box-text abox-text"><tspan>Bid Scriptless coin locked</tspan></text>
<path d="M799 890.11h395v9h9m-9-9 9 9v73.02H799v-82.02z" class="box note" style="fill:#ffc"/>
<text x="1001" y="902.87" class="box-text note-text"><tspan>The XmrBidLockReleaseMessage contains the offerer&apos;s OTVES for it. </tspan></text>
<text x="1001" y="918.87" class="box-text note-text"><tspan> The bidder decodes the offerer&apos;s signature</tspan></text>
<text x="1001" y="934.87" class="box-text note-text"><tspan>from the OTVES. When the offerer has the</tspan></text>
<text x="1001" y="950.87" class="box-text note-text"><tspan>plaintext signature, they can decode the bidder&apos;s noscript-coin-lock-tx</tspan></text>
<text x="1001" y="966.87" class="box-text note-text"><tspan>signature.</tspan></text>
<path d="m591 993.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="996.87" class="box-text abox-text"><tspan>Script coin lock released</tspan></text>
<path d="m591 1069.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1072.87" class="box-text abox-text"><tspan>Bid Completed</tspan></text>
<path d="M799 1241.18h395v9h9m-9-9 9 9v25H799v-34z" class="box note" style="fill:#ffc"/>
<text x="1001" y="1261.93" class="box-text note-text"><tspan>tx can be sent by either party.</tspan></text>
<path d="m591 1334.18 3-17.01h190l3 17.01-3 17.01H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1329.93" class="box-text abox-text"><tspan>Bid Script pre-refund tx in</tspan></text>
<text x="689" y="1345.93" class="box-text abox-text"><tspan>chain</tspan></text>
<path d="M-36 1372.18h200.86v11.02l-7 7H-36" class="box inline_expression_label"/>
<text x="-34" y="1385.43" class="inline_expression-text alt-text anchor-start"><tspan>alt: offerer refunds script coin lock tx</tspan></text>
<path d="M799 1490.23h395v9h9m-9-9 9 9v41.02H799v-50.02z" class="box note" style="fill:#ffc"/>
<text x="1001" y="1502.99" class="box-text note-text"><tspan>Refunds the script lock tx, with the offerer&apos;s cleartext signature</tspan></text>
<text x="1001" y="1518.99" class="box-text note-text"><tspan>the bidder can refund the noscript lock tx. </tspan></text>
<text x="1001" y="1534.99" class="box-text note-text"><tspan>Once the lock expires the pre-refund tx can be spent by the bidder.</tspan></text>
<path d="m383 1561.24 3-17h190l3 17-3 17H386z" class="box abox" style="stroke:red"/>
<text x="481" y="1564.99" class="box-text abox-text"><tspan>Bid Failed, refunded</tspan></text>
<path d="M799 1582.24h395v9h9m-9-9 9 9v25H799v-34z" class="box note" style="fill:#ffc"/>
<text x="1001" y="1602.99" class="box-text note-text"><tspan>Bidder recovers the offerer&apos;s scriptless chain key-shard.</tspan></text>
<path d="m591 1675.24 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1678.99" class="box-text abox-text"><tspan>Bid Scriptless tx recovered</tspan></text>
<text x="689" y="1072.87" class="box-text abox-text"><tspan>Script tx redeemed</tspan></text>
<path d="m591 1107.12 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1110.87" class="box-text abox-text"><tspan>Bid Completed</tspan></text>
<path d="M799 1279.18h395v9h9m-9-9 9 9v25H799v-34z" class="box note" style="fill:#ffc"/>
<text x="1001" y="1299.93" class="box-text note-text"><tspan>tx can be sent by either party.</tspan></text>
<path d="m591 1372.18 3-17.01h190l3 17.01-3 17.01H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1367.93" class="box-text abox-text"><tspan>Bid Script pre-refund tx in</tspan></text>
<text x="689" y="1383.93" class="box-text abox-text"><tspan>chain</tspan></text>
<path d="M-36 1410.18h200.86v11.02l-7 7H-36" class="box inline_expression_label"/>
<text x="-34" y="1423.43" class="inline_expression-text alt-text anchor-start"><tspan>alt: offerer refunds script coin lock tx</tspan></text>
<path d="M799 1528.23h395v9h9m-9-9 9 9v41.02H799v-50.02z" class="box note" style="fill:#ffc"/>
<text x="1001" y="1540.99" class="box-text note-text"><tspan>Refunds the script lock tx, with the offerer&apos;s cleartext signature</tspan></text>
<text x="1001" y="1556.99" class="box-text note-text"><tspan>the bidder can refund the noscript lock tx. </tspan></text>
<text x="1001" y="1572.99" class="box-text note-text"><tspan>Once the lock expires the pre-refund tx can be spent by the bidder.</tspan></text>
<path d="m383 1599.24 3-17h190l3 17-3 17H386z" class="box abox" style="stroke:red"/>
<text x="481" y="1602.99" class="box-text abox-text"><tspan>Bid Failed, refunded</tspan></text>
<path d="M799 1620.24h395v9h9m-9-9 9 9v25H799v-34z" class="box note" style="fill:#ffc"/>
<text x="1001" y="1640.99" class="box-text note-text"><tspan>Bidder recovers the offerer&apos;s scriptless chain key-shard.</tspan></text>
<path d="m591 1713.24 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1716.99" class="box-text abox-text"><tspan>Bid Failed, refunded</tspan></text>
<path d="m591 1924.3 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1928.05" class="box-text abox-text"><tspan>Bid Failed, swiped</tspan></text>
<text x="689" y="1716.99" class="box-text abox-text"><tspan>Bid Scriptless tx recovered</tspan></text>
<path d="m591 1751.24 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1754.99" class="box-text abox-text"><tspan>Bid Failed, refunded</tspan></text>
<path d="m591 1962.3 3-17h190l3 17-3 17H594z" class="box abox" style="stroke:#00f"/>
<text x="689" y="1966.05" class="box-text abox-text"><tspan>Bid Failed, swiped</tspan></text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -5,6 +5,7 @@
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
import json
import struct
import traceback
from basicswap.util import (
make_int,
@ -358,6 +359,29 @@ def describeBid(swap_client, bid, xmr_swap, offer, xmr_offer, bid_events, edit_b
return data
def listOldBidStates(bid):
old_states = []
num_states = len(bid.states) // 12
for i in range(num_states):
up = struct.unpack_from('<iq', bid.states[i * 12:(i + 1) * 12])
old_states.append((up[1], 'Bid ' + strBidState(up[0])))
if bid.initiate_tx and bid.initiate_tx.states is not None:
num_states = len(bid.initiate_tx.states) // 12
for i in range(num_states):
up = struct.unpack_from('<iq', bid.initiate_tx.states[i * 12:(i + 1) * 12])
if up[0] != TxStates.TX_NONE:
old_states.append((up[1], 'ITX ' + strTxState(up[0])))
if bid.participate_tx and bid.participate_tx.states is not None:
num_states = len(bid.participate_tx.states) // 12
for i in range(num_states):
up = struct.unpack_from('<iq', bid.participate_tx.states[i * 12:(i + 1) * 12])
if up[0] != TxStates.TX_NONE:
old_states.append((up[1], 'PTX ' + strTxState(up[0])))
if len(old_states) > 0:
old_states.sort(key=lambda x: x[0])
return old_states
def getCoinName(c):
if c == Coins.PART_ANON:
return chainparams[Coins.PART]['name'].capitalize() + 'Anon'

View file

@ -26,6 +26,7 @@ xu {
N >> B [label="Detects Initiate Tx"];
B abox B [label="ITX Sent", textbgcolor="#4bdbf1"];
B => B [label="Wait for ITX to confirm"], O => O [label="Wait for ITX to confirm"];
B abox B [label="Bid Initiated"];
B abox B [label="ITX Confirmed", textbgcolor="#4bdbf1"];
B =>> N [label="Sends Participate Tx"],
C note C2

View file

@ -28,6 +28,7 @@ xu {
textbgcolor="#FFFFCC"];
O =>> N [label="Sends script-coin-lock-tx"],
B abox B [label="Bid Script coin spend tx valid"];
B abox B [label="Exchanged script lock spend tx msg"];
B => B [label="Wait for script-coin-lock-tx to confirm"];
B abox B [label="Bid Script coin locked"];
CB alt C [label="success path"] {

View file

@ -286,3 +286,92 @@ def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT):
nonlocal node_id, auth
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
return rpc_func
def extract_states_from_xu_file(file_path):
states = {}
alt_counter = 0
active_path = 0
states[active_path] = []
path_stack = [active_path, ]
with open(file_path) as fp:
for line in fp:
line = line.strip()
if line.startswith('#'):
continue
if line == '};':
if len(path_stack) > 1:
path_stack.pop()
active_path = path_stack[-1]
continue
split_line = line.split('[')
if len(split_line) < 2:
continue
definitions = split_line[0].split(' ')
if len(definitions) < 2:
continue
if definitions[1] == 'alt':
alt_counter += 1
path_stack.append(alt_counter)
states[alt_counter] = [s for s in states[active_path]]
continue
if definitions[0] == '---':
active_path = path_stack[-1]
continue
if definitions[1] != 'abox':
continue
tag_start = 'label="'
tag_end = '"'
pos_start = split_line[1].find(tag_start)
if pos_start < 0:
continue
pos_start += len(tag_start)
pos_end = split_line[1].find(tag_end, pos_start)
if pos_end < 0:
continue
label = split_line[1][pos_start:pos_end]
if line.find('textbgcolor') > 0:
# transaction status
pass
states[active_path].append(label)
return states
def compare_bid_states(states, expect_states):
for i in range(len(states) - 1, -1, -1):
if states[i][1] == 'Bid Delaying':
del states[i]
assert(len(states) == len(expect_states))
for i, s in enumerate(states):
if s[1] != expect_states[i]:
if 'Bid ' + expect_states[i] == s[1]:
logging.warning(f'Expected state {expect_states[i]} not an exact match to {s[1]}.')
continue
if [s[0], expect_states[i]] in states:
logging.warning(f'Expected state {expect_states[i]} found out of order at the same time as {s[1]}.')
continue
raise ValueError(f'Expected state {expect_states[i]}, found {s[1]}')
assert(s[1] == expect_states[i])
return True
def read_json_api(port, path=None):
url = f'http://127.0.0.1:{port}/json'
if path is not None:
url += '/' + path
return json.loads(urlopen(url).read())

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2019-2021 tecnovert
# Copyright (c) 2019-2022 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
@ -13,11 +13,11 @@ $ pytest -v -s tests/basicswap/test_run.py::Test::test_04_ltc_btc
"""
import os
import json
import random
import logging
import unittest
from urllib.request import urlopen
from basicswap.basicswap import (
Coins,
@ -41,9 +41,12 @@ from tests.basicswap.common import (
wait_for_bid_tx_state,
wait_for_in_progress,
post_json_req,
read_json_api,
TEST_HTTP_PORT,
LTC_BASE_RPC_PORT,
BTC_BASE_RPC_PORT,
compare_bid_states,
extract_states_from_xu_file,
)
from .test_xmr import BaseTest, test_delay_event, callnoderpc
@ -69,6 +72,10 @@ class Test(BaseTest):
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/btc', 'balance', 1000.0)
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/ltc', 'balance', 1000.0)
diagrams_dir = 'doc/protocols/sequence_diagrams'
cls.states_bidder = extract_states_from_xu_file(os.path.join(diagrams_dir, 'bidder.alt.xu'))
cls.states_offerer = extract_states_from_xu_file(os.path.join(diagrams_dir, 'offerer.alt.xu'))
@classmethod
def tearDownClass(cls):
logging.info('Finalising test')
@ -133,11 +140,19 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read())
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
bid_id_hex = bid_id.hex()
path = f'bids/{bid_id_hex}/states'
offerer_states = read_json_api(1800, path)
bidder_states = read_json_api(1801, path)
assert(compare_bid_states(offerer_states, self.states_offerer[0]) is True)
assert(compare_bid_states(bidder_states, self.states_bidder[0]) is True)
def test_03_ltc_part(self):
logging.info('---------- Test LTC to PART')
swap_clients = self.swap_clients
@ -156,8 +171,8 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read())
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
@ -179,11 +194,8 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
js_0bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read())
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read())
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
@ -206,13 +218,13 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=60)
js_0_bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read())
js_1_bid = json.loads(urlopen('http://127.0.0.1:1801/json/bids/{}'.format(bid_id.hex())).read())
js_0_bid = read_json_api(1800, 'bids/{}'.format(bid_id.hex()))
js_1_bid = read_json_api(1801, 'bids/{}'.format(bid_id.hex()))
assert(js_0_bid['itx_state'] == 'Refunded')
assert(js_1_bid['ptx_state'] == 'Unknown')
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read())
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
@ -220,7 +232,7 @@ class Test(BaseTest):
logging.info('---------- Test same client, BTC to LTC')
swap_clients = self.swap_clients
js_0_before = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_0_before = read_json_api(1800)
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 10 * COIN, 10 * COIN, 10 * COIN, SwapTypes.SELLER_FIRST)
@ -235,7 +247,7 @@ class Test(BaseTest):
wait_for_bid_tx_state(test_delay_event, swap_clients[0], bid_id, TxStates.TX_REDEEMED, TxStates.TX_REDEEMED, wait_for=60)
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_0 = read_json_api(1800)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_0['num_recv_bids'] == js_0_before['num_recv_bids'] + 1 and js_0['num_sent_bids'] == js_0_before['num_sent_bids'] + 1)
@ -243,7 +255,7 @@ class Test(BaseTest):
logging.info('---------- Test error, BTC to LTC, set fee above bid value')
swap_clients = self.swap_clients
js_0_before = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_0_before = read_json_api(1800)
offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.LTC, 0.001 * COIN, 1.0 * COIN, 0.001 * COIN, SwapTypes.SELLER_FIRST)
@ -307,13 +319,13 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=120)
js_0_bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read())
js_1_bid = json.loads(urlopen('http://127.0.0.1:1801/json/bids/{}'.format(bid_id.hex())).read())
js_0_bid = read_json_api(1800, 'bids/{}'.format(bid_id.hex()))
js_1_bid = read_json_api(1801, 'bids/{}'.format(bid_id.hex()))
assert(js_0_bid['itx_state'] == 'Refunded')
assert(js_1_bid['ptx_state'] == 'Refunded')
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read())
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
@ -339,13 +351,13 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=120)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.BID_ABANDONED, sent=True, wait_for=120)
js_0_bid = json.loads(urlopen('http://127.0.0.1:1800/json/bids/{}'.format(bid_id.hex())).read())
js_1_bid = json.loads(urlopen('http://127.0.0.1:1801/json/bids/{}'.format(bid_id.hex())).read())
js_0_bid = read_json_api(1800, 'bids/{}'.format(bid_id.hex()))
js_1_bid = read_json_api(1801, 'bids/{}'.format(bid_id.hex()))
assert(js_0_bid['itx_state'] == 'Refunded')
assert(js_1_bid['ptx_state'] == 'Unknown')
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json').read())
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json').read())
js_0 = read_json_api(1800)
js_1 = read_json_api(1801)
assert(js_0['num_swapping'] == 0 and js_0['num_watched_outputs'] == 0)
assert(js_1['num_swapping'] == 0 and js_1['num_watched_outputs'] == 0)
'''
@ -354,7 +366,7 @@ class Test(BaseTest):
logging.info('---------- Test LTC withdrawals')
ltc_addr = callnoderpc(0, 'getnewaddress', ['Withdrawal test', 'legacy'], base_rpc_port=LTC_BASE_RPC_PORT)
wallets0 = json.loads(urlopen('http://127.0.0.1:{}/json/wallets'.format(TEST_HTTP_PORT + 0)).read())
wallets0 = read_json_api(TEST_HTTP_PORT + 0, 'wallets')
assert(float(wallets0['3']['balance']) > 100)
post_json = {
@ -371,8 +383,8 @@ class Test(BaseTest):
# Participant loses PTX value without gaining ITX value
swap_clients = self.swap_clients
js_w0_before = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w1_before = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read())
js_w0_before = read_json_api(1800, 'wallets')
js_w1_before = read_json_api(1801, 'wallets')
swap_value = make_int(random.uniform(2.0, 20.0), scale=8, r=1)
logging.info('swap_value {}'.format(format_amount(swap_value, 8)))
@ -389,8 +401,8 @@ class Test(BaseTest):
wait_for_bid_tx_state(test_delay_event, swap_clients[0], bid_id, TxStates.TX_REFUNDED, TxStates.TX_REDEEMED, wait_for=60)
js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w1_after = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read())
js_w0_after = read_json_api(1800, 'wallets')
js_w1_after = read_json_api(1801, 'wallets')
ltc_swap_value = swap_value
btc_swap_value = swap_value // 2

View file

@ -16,7 +16,6 @@ import unittest
import traceback
import threading
import subprocess
from urllib.request import urlopen
import basicswap.config as cfg
from basicswap.db import (
@ -70,6 +69,9 @@ from tests.basicswap.common import (
wait_for_none_active,
wait_for_balance,
post_json_req,
read_json_api,
compare_bid_states,
extract_states_from_xu_file,
TEST_HTTP_HOST,
TEST_HTTP_PORT,
BASE_RPC_PORT,
@ -339,6 +341,10 @@ class BaseTest(unittest.TestCase):
cls.stream_fp.setFormatter(formatter)
logger.addHandler(cls.stream_fp)
diagrams_dir = 'doc/protocols/sequence_diagrams'
cls.states_bidder = extract_states_from_xu_file(os.path.join(diagrams_dir, 'xmr.bidder.alt.xu'))
cls.states_offerer = extract_states_from_xu_file(os.path.join(diagrams_dir, 'xmr.offerer.alt.xu'))
try:
logging.info('Preparing coin nodes.')
for i in range(NUM_NODES):
@ -547,7 +553,7 @@ class Test(BaseTest):
logging.info('---------- Test PART to XMR')
swap_clients = self.swap_clients
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read())
js_1 = read_json_api(1801, 'wallets')
assert(make_int(js_1[str(int(Coins.XMR))]['balance'], scale=12) > 0)
assert(make_int(js_1[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0)
@ -569,14 +575,22 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
js_0_end = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_0_end = read_json_api(1800, 'wallets')
end_xmr = float(js_0_end['6']['balance']) + float(js_0_end['6']['unconfirmed'])
assert(end_xmr > 10.9 and end_xmr < 11.0)
bid_id_hex = bid_id.hex()
path = f'bids/{bid_id_hex}/states'
offerer_states = read_json_api(1800, path)
bidder_states = read_json_api(1801, path)
assert(compare_bid_states(offerer_states, self.states_offerer[0]) is True)
assert(compare_bid_states(bidder_states, self.states_bidder[0]) is True)
def test_011_smsgaddresses(self):
logging.info('---------- Test address management and private offers')
swap_clients = self.swap_clients
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/smsgaddresses').read())
js_1 = read_json_api(1801, 'smsgaddresses')
post_json = {
'addressnote': 'testing',
@ -585,7 +599,7 @@ class Test(BaseTest):
new_address = json_rv['new_address']
new_address_pk = json_rv['pubkey']
js_2 = json.loads(urlopen('http://127.0.0.1:1801/json/smsgaddresses').read())
js_2 = read_json_api(1801, 'smsgaddresses')
assert(len(js_2) == len(js_1) + 1)
found = False
for addr in js_2:
@ -611,7 +625,7 @@ class Test(BaseTest):
json_rv = json.loads(post_json_req('http://127.0.0.1:1801/json/smsgaddresses/edit', post_json))
assert(json_rv['edited_address'] == new_address)
js_3 = json.loads(urlopen('http://127.0.0.1:1801/json/smsgaddresses').read())
js_3 = read_json_api(1801, 'smsgaddresses')
found = False
for addr in js_3:
if addr['addr'] == new_address:
@ -664,17 +678,17 @@ class Test(BaseTest):
wait_for_offer(test_delay_event, swap_clients[1], bytes.fromhex(offer_id_hex))
rv = json.loads(urlopen(f'http://127.0.0.1:1801/json/offers/{offer_id_hex}').read())
rv = read_json_api(1801, f'offers/{offer_id_hex}')
assert(rv[0]['addr_to'] == new_address)
rv = json.loads(urlopen(f'http://127.0.0.1:1800/json/offers/{offer_id_hex}').read())
rv = read_json_api(1800, f'offers/{offer_id_hex}')
assert(rv[0]['addr_to'] == new_address)
def test_02_leader_recover_a_lock_tx(self):
logging.info('---------- Test PART to XMR leader recovers coin a lock tx')
swap_clients = self.swap_clients
js_w0_before = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w0_before = read_json_api(1800, 'wallets')
offer_id = swap_clients[0].postOffer(
Coins.PART, Coins.XMR, 101 * COIN, 0.12 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
@ -696,13 +710,13 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, wait_for=180)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_REFUNDED, sent=True)
js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w0_after = read_json_api(1800, 'wallets')
def test_03_follower_recover_a_lock_tx(self):
logging.info('---------- Test PART to XMR follower recovers coin a lock tx')
swap_clients = self.swap_clients
js_w0_before = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w0_before = read_json_api(1800, 'wallets')
offer_id = swap_clients[0].postOffer(
Coins.PART, Coins.XMR, 101 * COIN, 0.13 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP,
@ -725,7 +739,7 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.BID_STALLED_FOR_TEST, wait_for=180)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.XMR_SWAP_FAILED_SWIPED, wait_for=80, sent=True)
js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w0_after = read_json_api(1800, 'wallets')
wait_for_none_active(test_delay_event, 1800)
wait_for_none_active(test_delay_event, 1801)
@ -782,8 +796,8 @@ class Test(BaseTest):
logging.info('---------- Test Multiple concurrent swaps')
swap_clients = self.swap_clients
js_w0_before = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w1_before = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read())
js_w0_before = read_json_api(1800, 'wallets')
js_w1_before = read_json_api(1801, 'wallets')
amt_1 = make_int(random.uniform(0.001, 49.0), scale=8, r=1)
amt_2 = make_int(random.uniform(0.001, 49.0), scale=8, r=1)
@ -831,8 +845,8 @@ class Test(BaseTest):
wait_for_none_active(test_delay_event, 1800)
wait_for_none_active(test_delay_event, 1801)
js_w0_after = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_w1_after = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read())
js_w0_after = read_json_api(1800, 'wallets')
js_w1_after = read_json_api(1801, 'wallets')
assert(make_int(js_w1_after['2']['balance'], scale=8, r=1) - (make_int(js_w1_before['2']['balance'], scale=8, r=1) + amt_1) < 1000)
def test_07_revoke_offer(self):
@ -848,10 +862,10 @@ class Test(BaseTest):
def test_08_withdraw(self):
logging.info('---------- Test XMR withdrawals')
swap_clients = self.swap_clients
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_0 = read_json_api(1800, 'wallets')
address_to = js_0[str(int(Coins.XMR))]['deposit_address']
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets').read())
js_1 = read_json_api(1801, 'wallets')
assert(float(js_1[str(int(Coins.XMR))]['balance']) > 0.0)
swap_clients[1].withdrawCoin(Coins.XMR, 1.1, address_to, False)
@ -961,12 +975,12 @@ class Test(BaseTest):
logging.info('---------- Test Particl anon transactions')
swap_clients = self.swap_clients
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
js_0 = read_json_api(1800, 'wallets/part')
assert(float(js_0['anon_balance']) == 0.0)
node0_anon_before = js_0['anon_balance'] + js_0['anon_pending']
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/part', 'balance', 200.0)
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
js_1 = read_json_api(1801, 'wallets/part')
assert(float(js_1['balance']) > 200.0)
node1_anon_before = js_1['anon_balance'] + js_1['anon_pending']
@ -982,7 +996,7 @@ class Test(BaseTest):
logging.info('Waiting for anon balance')
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/part', 'anon_balance', 100.0 + node1_anon_before)
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
js_1 = read_json_api(1801, 'wallets/part')
node1_anon_before = js_1['anon_balance'] + js_1['anon_pending']
callnoderpc(1, 'reservebalance', [False])
@ -1021,21 +1035,21 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[0], bid_id, BidStates.SWAP_COMPLETED, wait_for=180)
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
js_1 = read_json_api(1801, 'wallets/part')
assert(js_1['anon_balance'] < node1_anon_before - amount_to)
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
js_0 = read_json_api(1800, 'wallets/part')
assert(js_0['anon_balance'] + js_0['anon_pending'] > node0_anon_before + (amount_to - 0.05))
def test_12_particl_blind(self):
logging.info('---------- Test Particl blind transactions')
swap_clients = self.swap_clients
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
js_0 = read_json_api(1800, 'wallets/part')
node0_blind_before = js_0['blind_balance'] + js_0['blind_unconfirmed']
wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/part', 'balance', 200.0)
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
js_1 = read_json_api(1801, 'wallets/part')
assert(float(js_1['balance']) > 200.0)
node1_blind_before = js_1['blind_balance'] + js_1['blind_unconfirmed']
@ -1050,7 +1064,7 @@ class Test(BaseTest):
logging.info('Waiting for blind balance')
wait_for_balance(test_delay_event, 'http://127.0.0.1:1800/json/wallets/part', 'blind_balance', 100.0 + node0_blind_before)
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
js_0 = read_json_api(1800, 'wallets/part')
node0_blind_before = js_0['blind_balance'] + js_0['blind_unconfirmed']
amt_swap = make_int(random.uniform(0.1, 2.0), scale=8, r=1)
@ -1070,11 +1084,11 @@ class Test(BaseTest):
wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
amount_from = float(format_amount(amt_swap, 8))
js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
js_1 = read_json_api(1801, 'wallets/part')
node1_blind_after = js_1['blind_balance'] + js_1['blind_unconfirmed']
assert(node1_blind_after > node1_blind_before + (amount_from - 0.05))
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
js_0 = read_json_api(1800, 'wallets/part')
node0_blind_after = js_0['blind_balance'] + js_0['blind_unconfirmed']
assert(node0_blind_after < node0_blind_before - amount_from)
@ -1084,10 +1098,10 @@ class Test(BaseTest):
logging.info('Disabling XMR mining')
pause_event.clear()
js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets').read())
js_0 = read_json_api(1800, 'wallets')
address_to = js_0[str(int(Coins.XMR))]['deposit_address']
wallets1 = json.loads(urlopen('http://127.0.0.1:{}/json/wallets'.format(TEST_HTTP_PORT + 1)).read())
wallets1 = read_json_api(TEST_HTTP_PORT + 1, 'wallets')
xmr_total = float(wallets1[str(int(Coins.XMR))]['balance'])
assert(xmr_total > 10)