diff --git a/Tribler/Test/Community/Market/test_community.py b/Tribler/Test/Community/Market/test_community.py index afab6e57e94..0631cfbba99 100644 --- a/Tribler/Test/Community/Market/test_community.py +++ b/Tribler/Test/Community/Market/test_community.py @@ -184,13 +184,38 @@ def test_failing_payment(self): self.nodes[node_nr].overlay.wallets['DUM2'].transfer = lambda *_: fail(RuntimeError("oops")) yield self.nodes[0].overlay.create_ask(1, 'DUM1', 1, 'DUM2', 3600) - yield self.deliver_messages() yield self.nodes[1].overlay.create_bid(1, 'DUM1', 1, 'DUM2', 3600) + yield self.deliver_messages() self.assertEqual(self.nodes[0].overlay.transaction_manager.find_all()[0].status, "error") self.assertEqual(self.nodes[1].overlay.transaction_manager.find_all()[0].status, "error") + @twisted_wrapper + def test_proposed_trade_timeout(self): + """ + Test whether we unreserve the quantity if a proposed trade timeouts + """ + yield self.introduce_nodes() + + self.nodes[0].overlay.decode_map[chr(10)] = lambda *_: None + + ask_order = yield self.nodes[0].overlay.create_ask(1, 'DUM1', 1, 'DUM2', 3600) + bid_order = yield self.nodes[1].overlay.create_bid(1, 'DUM1', 1, 'DUM2', 3600) + + yield self.deliver_messages(timeout=.5) + + outstanding = self.nodes[1].overlay.get_outstanding_proposals(bid_order.order_id, ask_order.order_id) + self.assertTrue(outstanding) + outstanding[0][1].on_timeout() + + yield self.deliver_messages(timeout=.5) + + ask_tick_entry = self.nodes[2].overlay.order_book.get_tick(ask_order.order_id) + bid_tick_entry = self.nodes[2].overlay.order_book.get_tick(bid_order.order_id) + self.assertEqual(float(bid_tick_entry.reserved_for_matching), 0) + self.assertEqual(float(ask_tick_entry.reserved_for_matching), 0) + class TestMarketCommunityTwoNodes(TestMarketCommunityBase): __testing__ = True @@ -220,3 +245,36 @@ def test_e2e_trade(self): balance2 = yield self.nodes[1].overlay.wallets['DUM2'].get_balance() self.assertEqual(balance1['available'], 999) self.assertEqual(balance2['available'], 1001) + + @twisted_wrapper + def test_partial_trade(self): + """ + Test a partial trade + """ + yield self.introduce_nodes() + + yield self.nodes[0].overlay.create_ask(1, 'DUM1', 2, 'DUM2', 3600) + bid_order = yield self.nodes[1].overlay.create_bid(1, 'DUM1', 10, 'DUM2', 3600) + + yield self.deliver_messages(timeout=.5) + + # Verify that the trade has been made + self.assertEqual(len(self.nodes[0].overlay.transaction_manager.find_all()), 1) + self.assertEqual(len(self.nodes[1].overlay.transaction_manager.find_all()), 1) + + # There should be no reserved quantity for the bid tick + for node_nr in [0, 1]: + bid_tick_entry = self.nodes[node_nr].overlay.order_book.get_tick(bid_order.order_id) + self.assertEqual(float(bid_tick_entry.reserved_for_matching), 0) + + yield self.nodes[0].overlay.create_ask(1, 'DUM1', 8, 'DUM2', 3600) + + yield self.deliver_messages(timeout=.5) + + # Verify that the trade has been made + self.assertEqual(len(self.nodes[0].overlay.transaction_manager.find_all()), 2) + self.assertEqual(len(self.nodes[1].overlay.transaction_manager.find_all()), 2) + + for node_nr in [0, 1]: + self.assertEqual(len(self.nodes[node_nr].overlay.order_book.asks), 0) + self.assertEqual(len(self.nodes[node_nr].overlay.order_book.bids), 0) diff --git a/Tribler/Test/Community/Market/test_orderbook.py b/Tribler/Test/Community/Market/test_orderbook.py index 85400ba375c..1859d52a0a1 100644 --- a/Tribler/Test/Community/Market/test_orderbook.py +++ b/Tribler/Test/Community/Market/test_orderbook.py @@ -187,13 +187,15 @@ def test_update_ticks(self): "trader_id": str(self.ask.order_id.trader_id), "order_number": int(self.ask.order_id.order_number), "quantity": 3, - "quantity_type": self.ask.quantity.wallet_id + "quantity_type": self.ask.quantity.wallet_id, + "traded_quantity": 3 } bid_dict = { "trader_id": str(self.bid.order_id.trader_id), "order_number": int(self.bid.order_id.order_number), "quantity": 3, - "quantity_type": self.bid.quantity.wallet_id + "quantity_type": self.bid.quantity.wallet_id, + "traded_quantity": 3 } self.order_book.get_tick(self.ask.order_id).reserve_for_matching(Quantity(3, self.ask.quantity.wallet_id)) diff --git a/Tribler/community/market/community.py b/Tribler/community/market/community.py index 84de651fd26..8458e3a0ec0 100644 --- a/Tribler/community/market/community.py +++ b/Tribler/community/market/community.py @@ -1482,9 +1482,11 @@ def abort_transaction(self, transaction): """ self.logger.error("Aborting transaction %s", transaction.transaction_id) order = self.order_manager.order_repository.find_by_id(transaction.order_id) - order.release_quantity_for_tick(transaction.partner_order_id, - transaction.total_quantity - transaction.transferred_quantity) - self.order_manager.order_repository.update(order) + if (transaction.total_quantity - transaction.transferred_quantity) > \ + Quantity(0, transaction.total_quantity.wallet_id): + order.release_quantity_for_tick(transaction.partner_order_id, + transaction.total_quantity - transaction.transferred_quantity) + self.order_manager.order_repository.update(order) def notify_transaction_complete(self, tx_dict, mine=False): if self.tribler_session: diff --git a/Tribler/community/market/core/orderbook.py b/Tribler/community/market/core/orderbook.py index 5c41e62c2e4..cc5085979f2 100644 --- a/Tribler/community/market/core/orderbook.py +++ b/Tribler/community/market/core/orderbook.py @@ -117,9 +117,9 @@ def update_ticks(self, ask_order_dict, bid_order_dict, traded_quantity, unreserv str(ask_order_id), str(bid_order_id), str(traded_quantity)) # Update ask tick - new_ask_quantity = Quantity(ask_order_dict["quantity"] - float(traded_quantity), + new_ask_quantity = Quantity(ask_order_dict["quantity"] - ask_order_dict["traded_quantity"], ask_order_dict["quantity_type"]) - if self.tick_exists(ask_order_id) and new_ask_quantity < self.get_tick(ask_order_id).quantity: + if self.tick_exists(ask_order_id) and new_ask_quantity <= self.get_tick(ask_order_id).quantity: tick = self.get_tick(ask_order_id) tick.quantity = new_ask_quantity if unreserve: @@ -133,9 +133,9 @@ def update_ticks(self, ask_order_dict, bid_order_dict, traded_quantity, unreserv self.insert_ask(ask) # Update bid tick - new_bid_quantity = Quantity(bid_order_dict["quantity"] - float(traded_quantity), + new_bid_quantity = Quantity(bid_order_dict["quantity"] - bid_order_dict["traded_quantity"], bid_order_dict["quantity_type"]) - if self.tick_exists(bid_order_id) and new_bid_quantity < self.get_tick(bid_order_id).quantity: + if self.tick_exists(bid_order_id) and new_bid_quantity <= self.get_tick(bid_order_id).quantity: tick = self.get_tick(bid_order_id) tick.quantity = new_bid_quantity if unreserve: diff --git a/Tribler/community/market/core/side.py b/Tribler/community/market/core/side.py index d1d208429b0..19f5e3db3b6 100644 --- a/Tribler/community/market/core/side.py +++ b/Tribler/community/market/core/side.py @@ -117,11 +117,12 @@ def remove_tick(self, order_id): assert isinstance(order_id, OrderId), type(order_id) tick = self.get_tick(order_id) - tick.cancel_all_pending_tasks() - tick.price_level().remove_tick(tick) - if len(tick.price_level()) == 0: # Last tick for that price - self._remove_price_level(tick.price, tick.quantity.wallet_id) - del self._tick_map[order_id] + if tick: + tick.cancel_all_pending_tasks() + tick.price_level().remove_tick(tick) + if len(tick.price_level()) == 0: # Last tick for that price + self._remove_price_level(tick.price, tick.quantity.wallet_id) + del self._tick_map[order_id] def get_price_level_list(self, price_wallet_id, quantity_wallet_id): """