From fa74b9982c49fe7ae7580c0d5c2256143a43b5bc Mon Sep 17 00:00:00 2001 From: tecnovert Date: Wed, 20 Jul 2022 00:24:14 +0200 Subject: [PATCH] tests: Add xmr swap failure states to tests. --- basicswap/basicswap.py | 5 +- .../sequence_diagrams/bidder.alt.xu.min.svg | 164 ++++++---- .../xmr.bidder.alt.xu.min.svg | 305 +++++++++--------- doc/protocols/sequence_diagrams/bidder.alt.xu | 1 - .../sequence_diagrams/xmr.bidder.alt.xu | 8 +- tests/basicswap/common.py | 11 +- tests/basicswap/test_run.py | 4 +- tests/basicswap/test_xmr.py | 35 +- 8 files changed, 303 insertions(+), 230 deletions(-) diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 36d229f..ca1d2b6 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -3424,7 +3424,8 @@ class BasicSwap(BaseApp): 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) else: - bid.setState(BidStates.XMR_SWAP_FAILED_REFUNDED) + # Other side refunded before swap lock tx was sent + bid.setState(BidStates.XMR_SWAP_FAILED) if bid.was_received: if not bid.was_sent: @@ -4472,8 +4473,8 @@ class BasicSwap(BaseApp): 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) - self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer) self.logBidEvent(bid.bid_id, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session) + self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer) return if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK: diff --git a/basicswap/static/sequence_diagrams/bidder.alt.xu.min.svg b/basicswap/static/sequence_diagrams/bidder.alt.xu.min.svg index df1f3ae..dd1a053 100644 --- a/basicswap/static/sequence_diagrams/bidder.alt.xu.min.svg +++ b/basicswap/static/sequence_diagrams/bidder.alt.xu.min.svg @@ -1,4 +1,4 @@ - + @@ -34,9 +34,12 @@ .mscgenjsreplaceme path,.mscgenjsreplaceme rect{fill:none}.mscgenjsreplaceme .label-text-background{fill:#fff;stroke:#fff;stroke-width:0}.mscgenjsreplaceme .return{stroke-dasharray:5,3}.mscgenjsreplaceme text{color:inherit;stroke:none;text-anchor:middle}.mscgenjsreplaceme text.anchor-start{text-anchor:start}.mscgenjsreplaceme .arrow-marker{overflow:visible}.mscgenjsreplaceme .arrow-style{stroke-width:1}.mscgenjsreplaceme .arcrow{stroke-linecap:butt}.mscgenjsreplaceme .box,.mscgenjsreplaceme .entity{fill:#fff;stroke-linejoin:round} - - - + + + + + + @@ -154,27 +157,55 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -225,9 +256,9 @@ Wait for PTX to confirm - - - Sends Participate Redeem Tx + + + Sends Participate Redeem Tx Detects Participate Redeem Tx @@ -237,61 +268,76 @@ Wait for ITX Redeem to confirm - + fail path - - - Wait for PTX locktime to expire - - - PTX Refund Tx - - - Wait for PTX Refund to confirm + + + Wait for ITX locktime to expire + + + ITX Refund Tx + + + Detects Initiate Tx refund Tx + + + Wait for PTX locktime to expire + + + PTX Refund Tx + + + Wait for PTX Refund to confirm - + Bid Sent - + User accepts bid - + Offerer generates secret_value and sends Hash(secret_value) to the Bidder - + ITX can be spent by knowledge of the secret_value and the bidder_redeem_key or after a timeout by the offerer_refund_key - + Bid Accepted - + ITX Sent - + Bid Initiated - + ITX Confirmed - + PTX can be spent by knowledge of the secret_value and the offerer_redeem_key or after a timeout by the bidder_refund_key - + PTX Sent - + PTX Confirmed - + Bid Participating - - Reveals secret_value - - alt: success path - + + alt: success path + + Reveals secret_value + PTX Redeemed - + ITX Redeemed - + Bid Completed - - PTX Refunded + + alt: offerer may reclaim ITX + + ITX Refunded + + PTX Refunded + + Bid Completed diff --git a/basicswap/static/sequence_diagrams/xmr.bidder.alt.xu.min.svg b/basicswap/static/sequence_diagrams/xmr.bidder.alt.xu.min.svg index ae54aed..f279e8a 100644 --- a/basicswap/static/sequence_diagrams/xmr.bidder.alt.xu.min.svg +++ b/basicswap/static/sequence_diagrams/xmr.bidder.alt.xu.min.svg @@ -1,4 +1,4 @@ - + @@ -35,10 +35,10 @@ - + - - + + @@ -93,15 +93,15 @@ - - - - - - - - - + + + + + + + + + @@ -117,15 +117,15 @@ - - - - - - - - - + + + + + + + + + @@ -145,15 +145,15 @@ - - - - - - - - - + + + + + + + + + @@ -169,19 +169,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -205,15 +205,15 @@ - - - - - - - - - + + + + + + + + + @@ -225,7 +225,11 @@ - + + + + + @@ -261,13 +265,13 @@ Sends script-coin-lock-tx - - - Wait for - - script-coin-lock-tx to - - confirm + + + Wait for + + script-coin-lock-tx to + + confirm Sends noscript-coin-lock-tx @@ -285,59 +289,59 @@ noscript-coin-lock-tx to confirm - - - Sends script-coin-lock-tx - - release message - - - Sends script-coin-lock-spend-tx - - - fail path - - - Wait for - - script-coin-lock-tx lock to - - expire - - - Sends - - script-coin-lock-pre-refund-tx - - - script-coin-lock-pre-refund-tx - - - Wait for - - pre-refund tx to confirm - - - Sends - - script-coin-lock-pre-refund-spend-tx - - - Detects script-coin-lock-pre-refund-spend-tx - - - Sends scriptless-coin-lock-recover-tx - - - bidder swipes script coin lock tx - - - Wait for - - pre-refund tx lock to expire - - - Sends script-coin-lock-pre-refund-swipe-tx + + + Sends script-coin-lock-tx + + release message + + + Sends script-coin-lock-spend-tx + + + fail path + + + Wait for + + script-coin-lock-tx lock to + + expire + + + Sends + + script-coin-lock-pre-refund-tx + + + script-coin-lock-pre-refund-tx + + + Wait for + + pre-refund tx to confirm + + + Sends + + script-coin-lock-pre-refund-spend-tx + + + Detects script-coin-lock-pre-refund-spend-tx + + + Sends scriptless-coin-lock-recover-tx + + + bidder swipes script coin lock tx + + + Wait for + + pre-refund tx lock to expire + + + Sends script-coin-lock-pre-refund-swipe-tx @@ -363,45 +367,48 @@ the offerer's signature for it. Bid Script coin spend tx valid - - Bid Script coin locked - - alt: success path + + Exchanged script lock spend tx + msg + + Bid Script coin locked Bid Scriptless coin locked - - The XmrBidLockReleaseMessage contains the offerer's OTVES for it. - The bidder decodes the offerer's signature - from the OTVES. When the offerer has the - plaintext signature, they can decode the bidder's noscript-coin-lock-tx - signature. - - Script coin lock released - - Script tx redeemed + + alt: success path + + The XmrBidLockReleaseMessage contains the offerer's OTVES for it. + The bidder decodes the offerer's signature + from the OTVES. When the offerer has the + plaintext signature, they can decode the bidder's noscript-coin-lock-tx + signature. + + Script coin lock released - Bid Completed - - tx can be sent by either party. - - Bid Script pre-refund tx in - chain - - alt: offerer refunds script coin lock tx - - Refunds the script lock tx, with the offerer's cleartext signature - the bidder can refund the noscript lock tx. - Once the lock expires the pre-refund tx can be spent by the bidder. - - Bid Failed, refunded - - Bidder recovers the offerer's scriptless chain key-shard. - - Bid Scriptless tx recovered + Script tx redeemed + + Bid Completed + + tx can be sent by either party. + + Bid Script pre-refund tx in + chain + + alt: offerer refunds script coin lock tx + + Refunds the script lock tx, with the offerer's cleartext signature + the bidder can refund the noscript lock tx. + Once the lock expires the pre-refund tx can be spent by the bidder. + + Bid Failed, refunded + + Bidder recovers the offerer's scriptless chain key-shard. - Bid Failed, refunded - - Bid Failed, swiped + Bid Scriptless tx recovered + + Bid Failed, refunded + + Bid Failed, swiped diff --git a/doc/protocols/sequence_diagrams/bidder.alt.xu b/doc/protocols/sequence_diagrams/bidder.alt.xu index ac77e04..558aeb3 100644 --- a/doc/protocols/sequence_diagrams/bidder.alt.xu +++ b/doc/protocols/sequence_diagrams/bidder.alt.xu @@ -64,4 +64,3 @@ xu { B abox B [label="Bid Completed"]; }; } - diff --git a/doc/protocols/sequence_diagrams/xmr.bidder.alt.xu b/doc/protocols/sequence_diagrams/xmr.bidder.alt.xu index 04de528..fb1239e 100644 --- a/doc/protocols/sequence_diagrams/xmr.bidder.alt.xu +++ b/doc/protocols/sequence_diagrams/xmr.bidder.alt.xu @@ -31,10 +31,11 @@ xu { 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"]; + # Bidder would only send noscript-coin-lock-tx if script-coin-lock-tx validates + B =>> N [label="Sends noscript-coin-lock-tx"]; + B => B [label="Wait for noscript-coin-lock-tx to confirm"], O => O [label="Wait for noscript-coin-lock-tx to confirm"]; + B abox B [label="Bid Scriptless coin locked"]; CB alt C [label="success path"] { - B =>> N [label="Sends noscript-coin-lock-tx"]; - B => B [label="Wait for noscript-coin-lock-tx to confirm"], O => O [label="Wait for noscript-coin-lock-tx to confirm"]; - B abox B [label="Bid Scriptless coin locked"]; O => B [label="Sends script-coin-lock-tx release message"], C note C2 [label="The XmrBidLockReleaseMessage contains the offerer's OTVES for it. @@ -78,4 +79,3 @@ xu { }; }; } - diff --git a/tests/basicswap/common.py b/tests/basicswap/common.py index 1f3c73c..a76a6f6 100644 --- a/tests/basicswap/common.py +++ b/tests/basicswap/common.py @@ -121,7 +121,12 @@ def wait_for_bid(delay_event, swap_client, bid_id, state=None, sent=False, wait_ assert(len(bids) < 2) for bid in bids: if bid[2] == bid_id: - if state is not None and state != bid[5]: + if type(state) == list: + if bid[5] in state: + return + else: + continue + elif state is not None and state != bid[5]: continue return raise ValueError('wait_for_bid timed out.') @@ -302,7 +307,7 @@ def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT): return rpc_func -def extract_states_from_xu_file(file_path): +def extract_states_from_xu_file(file_path, prefix): states = {} alt_counter = 0 @@ -342,6 +347,8 @@ def extract_states_from_xu_file(file_path): if definitions[1] != 'abox': continue + if definitions[0] != prefix: + continue tag_start = 'label="' tag_end = '"' diff --git a/tests/basicswap/test_run.py b/tests/basicswap/test_run.py index 4122e99..97d5446 100644 --- a/tests/basicswap/test_run.py +++ b/tests/basicswap/test_run.py @@ -73,8 +73,8 @@ class Test(BaseTest): 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')) + cls.states_bidder = extract_states_from_xu_file(os.path.join(diagrams_dir, 'bidder.alt.xu'), 'B') + cls.states_offerer = extract_states_from_xu_file(os.path.join(diagrams_dir, 'offerer.alt.xu'), 'O') @classmethod def tearDownClass(cls): diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py index 52be289..98a7dc9 100644 --- a/tests/basicswap/test_xmr.py +++ b/tests/basicswap/test_xmr.py @@ -342,8 +342,8 @@ class BaseTest(unittest.TestCase): 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')) + cls.states_bidder = extract_states_from_xu_file(os.path.join(diagrams_dir, 'xmr.bidder.alt.xu'), 'B') + cls.states_offerer = extract_states_from_xu_file(os.path.join(diagrams_dir, 'xmr.offerer.alt.xu'), 'O') try: logging.info('Preparing coin nodes.') @@ -689,8 +689,6 @@ class Test(BaseTest): logging.info('---------- Test PART to XMR leader recovers coin a lock tx') swap_clients = self.swap_clients - 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, lock_type=TxLockTypes.SEQUENCE_LOCK_BLOCKS, lock_value=12) @@ -709,16 +707,18 @@ class Test(BaseTest): swap_clients[0].acceptXmrBid(bid_id) 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) + wait_for_bid(test_delay_event, swap_clients[1], bid_id, [BidStates.BID_STALLED_FOR_TEST, BidStates.XMR_SWAP_FAILED_REFUNDED], sent=True) - js_w0_after = read_json_api(1800, 'wallets') + bid_id_hex = bid_id.hex() + path = f'bids/{bid_id_hex}/states' + offerer_states = read_json_api(1800, path) + + assert(compare_bid_states(offerer_states, self.states_offerer[1]) is True) 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 = 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, lock_type=TxLockTypes.SEQUENCE_LOCK_BLOCKS, lock_value=12) @@ -740,11 +740,16 @@ 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 = read_json_api(1800, 'wallets') - wait_for_none_active(test_delay_event, 1800) wait_for_none_active(test_delay_event, 1801) + bid_id_hex = bid_id.hex() + path = f'bids/{bid_id_hex}/states' + bidder_states = read_json_api(1801, path) + + bidder_states = [s for s in bidder_states if s[1] != 'Bid Stalled (debug)'] + assert(compare_bid_states(bidder_states, self.states_bidder[2]) is True) + def test_04_follower_recover_b_lock_tx(self): logging.info('---------- Test PART to XMR follower recovers coin b lock tx') @@ -752,7 +757,7 @@ class Test(BaseTest): offer_id = swap_clients[0].postOffer( Coins.PART, Coins.XMR, 101 * COIN, 0.14 * XMR_COIN, 101 * COIN, SwapTypes.XMR_SWAP, - lock_type=TxLockTypes.SEQUENCE_LOCK_BLOCKS, lock_value=18) + 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) @@ -769,6 +774,14 @@ 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) + 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[1]) is True) + assert(compare_bid_states(bidder_states, self.states_bidder[1]) is True) + def test_05_btc_xmr(self): logging.info('---------- Test BTC to XMR') swap_clients = self.swap_clients