From cbb3d0ac020cb801a44ca7ed7bf3fde53a632e1f Mon Sep 17 00:00:00 2001 From: tecnovert Date: Tue, 6 Jun 2023 22:03:05 +0200 Subject: [PATCH] ui: Add option to remove expired offers and bids. --- basicswap/basicswap.py | 9 +++++- basicswap/basicswap_util.py | 3 ++ basicswap/db_util.py | 54 ++++++++++++++++++++++++++++++++ basicswap/http_server.py | 29 ++--------------- basicswap/templates/debug.html | 16 ++++++++-- basicswap/templates/wallets.html | 12 ++----- basicswap/ui/page_debug.py | 54 ++++++++++++++++++++++++++++++++ doc/release-notes.md | 1 + 8 files changed, 138 insertions(+), 40 deletions(-) create mode 100644 basicswap/db_util.py create mode 100644 basicswap/ui/page_debug.py diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 813fd10..44b81d9 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -145,6 +145,7 @@ from .basicswap_util import ( NotificationTypes as NT, AutomationOverrideOptions, VisibilityOverrideOptions, + inactive_states, ) @@ -6109,6 +6110,12 @@ class BasicSwap(BaseApp): session.remove() self.mxDB.release() + def activeBidsQueryStr(self, now: int, offer_table: str = 'offers', bids_table: str = 'bids'): + offers_inset = f' AND {offer_table}.expire_at > {now}' if offer_table != '' else '' + + inactive_states_str = ', '.join([str(int(s)) for s in inactive_states]) + return f' ({bids_table}.state NOT IN ({inactive_states_str}) AND ({bids_table}.state > {BidStates.BID_RECEIVED} OR ({bids_table}.expire_at > {now}{offers_inset}))) ' + def listBids(self, sent=False, offer_id=None, for_html=False, filters={}): self.mxDB.acquire() try: @@ -6139,7 +6146,7 @@ class BasicSwap(BaseApp): with_available_or_active = filters.get('with_available_or_active', False) with_expired = filters.get('with_expired', True) if with_available_or_active: - query_str += 'AND (bids.state NOT IN ({}, {}, {}, {}, {}) AND (bids.state > {} OR (bids.expire_at > {} AND offers.expire_at > {}))) '.format(BidStates.SWAP_COMPLETED, BidStates.BID_ERROR, BidStates.BID_REJECTED, BidStates.SWAP_TIMEDOUT, BidStates.BID_ABANDONED, BidStates.BID_RECEIVED, now, now) + query_str += ' AND ' + self.activeBidsQueryStr(now) else: if with_expired is not True: query_str += 'AND bids.expire_at > {} AND offers.expire_at > {} '.format(now, now) diff --git a/basicswap/basicswap_util.py b/basicswap/basicswap_util.py index 34a700c..cecabdb 100644 --- a/basicswap/basicswap_util.py +++ b/basicswap/basicswap_util.py @@ -506,3 +506,6 @@ def strSwapDesc(swap_type): if swap_type == SwapTypes.XMR_SWAP: return 'Adaptor Sig' return None + + +inactive_states = [BidStates.SWAP_COMPLETED, BidStates.BID_ERROR, BidStates.BID_REJECTED, BidStates.SWAP_TIMEDOUT, BidStates.BID_ABANDONED] diff --git a/basicswap/db_util.py b/basicswap/db_util.py new file mode 100644 index 0000000..971a22b --- /dev/null +++ b/basicswap/db_util.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 The BSX Developers +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +from .db import ( + Concepts, +) + + +def remove_expired_data(self): + self.log.warning('Removing expired data') + now: int = self.getTime() + try: + session = self.openSession() + + active_bids_insert = self.activeBidsQueryStr(now, '', 'b2') + query_str = f''' + SELECT o.offer_id FROM offers o + WHERE o.expire_at <= :now AND 0 = (SELECT COUNT(*) FROM bids b2 WHERE b2.offer_id = o.offer_id AND {active_bids_insert}) + ''' + num_offers = 0 + num_bids = 0 + offer_rows = session.execute(query_str, {'now': now}) + for offer_row in offer_rows: + num_offers += 1 + bid_rows = session.execute('SELECT bids.bid_id FROM bids WHERE bids.offer_id = :offer_id', {'offer_id': offer_row[0]}) + for bid_row in bid_rows: + num_bids += 1 + session.execute('DELETE FROM transactions WHERE transactions.bid_id = :bid_id', {'bid_id': bid_row[0]}) + session.execute('DELETE FROM eventlog WHERE eventlog.linked_type = :type_ind AND eventlog.linked_id = :bid_id', {'type_ind': int(Concepts.BID), 'bid_id': bid_row[0]}) + session.execute('DELETE FROM automationlinks WHERE automationlinks.linked_type = :type_ind AND automationlinks.linked_id = :bid_id', {'type_ind': int(Concepts.BID), 'bid_id': bid_row[0]}) + session.execute('DELETE FROM prefunded_transactions WHERE prefunded_transactions.linked_type = :type_ind AND prefunded_transactions.linked_id = :bid_id', {'type_ind': int(Concepts.BID), 'bid_id': bid_row[0]}) + session.execute('DELETE FROM history WHERE history.concept_type = :type_ind AND history.concept_id = :bid_id', {'type_ind': int(Concepts.BID), 'bid_id': bid_row[0]}) + session.execute('DELETE FROM xmr_swaps WHERE xmr_swaps.bid_id = :bid_id', {'bid_id': bid_row[0]}) + session.execute('DELETE FROM actions WHERE actions.linked_id = :bid_id', {'bid_id': bid_row[0]}) + session.execute('DELETE FROM addresspool WHERE addresspool.bid_id = :bid_id', {'bid_id': bid_row[0]}) + session.execute('DELETE FROM xmr_split_data WHERE xmr_split_data.bid_id = :bid_id', {'bid_id': bid_row[0]}) + session.execute('DELETE FROM bids WHERE bids.bid_id = :bid_id', {'bid_id': bid_row[0]}) + + session.execute('DELETE FROM eventlog WHERE eventlog.linked_type = :type_ind AND eventlog.linked_id = :offer_id', {'type_ind': int(Concepts.OFFER), 'offer_id': offer_row[0]}) + session.execute('DELETE FROM automationlinks WHERE automationlinks.linked_type = :type_ind AND automationlinks.linked_id = :offer_id', {'type_ind': int(Concepts.OFFER), 'offer_id': offer_row[0]}) + session.execute('DELETE FROM prefunded_transactions WHERE prefunded_transactions.linked_type = :type_ind AND prefunded_transactions.linked_id = :offer_id', {'type_ind': int(Concepts.OFFER), 'offer_id': offer_row[0]}) + session.execute('DELETE FROM history WHERE history.concept_type = :type_ind AND history.concept_id = :offer_id', {'type_ind': int(Concepts.OFFER), 'offer_id': offer_row[0]}) + session.execute('DELETE FROM xmr_offers WHERE xmr_offers.offer_id = :offer_id', {'offer_id': offer_row[0]}) + session.execute('DELETE FROM sentoffers WHERE sentoffers.offer_id = :offer_id', {'offer_id': offer_row[0]}) + session.execute('DELETE FROM actions WHERE actions.linked_id = :offer_id', {'offer_id': offer_row[0]}) + session.execute('DELETE FROM offers WHERE offers.offer_id = :offer_id', {'offer_id': offer_row[0]}) + + self.log.warning(f'Removed data for {num_offers} expired offers and {num_bids} bids.') + + finally: + self.closeSession(session) diff --git a/basicswap/http_server.py b/basicswap/http_server.py index 206e519..4fe91ec 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -38,7 +38,6 @@ from .ui.util import ( getCoinName, get_data_entry, get_data_entry_or, - have_data_entry, listAvailableCoins, ) from .ui.page_automation import ( @@ -55,6 +54,7 @@ from .ui.page_settings import page_settings from .ui.page_encryption import page_changepassword, page_unlock, page_lock from .ui.page_identity import page_identity from .ui.page_smsgaddresses import page_smsgaddresses +from .ui.page_debug import page_debug env = Environment(loader=PackageLoader('basicswap', 'templates')) env.filters['formatts'] = format_timestamp @@ -333,31 +333,6 @@ class HttpHandler(BaseHTTPRequestHandler): 'summary': summary, }) - def page_debug(self, url_split, post_string): - swap_client = self.server.swap_client - swap_client.checkSystemStatus() - summary = swap_client.getSummary() - - result = None - messages = [] - err_messages = [] - form_data = self.checkForm(post_string, 'wallets', err_messages) - if form_data: - if have_data_entry(form_data, 'reinit_xmr'): - try: - swap_client.initialiseWallet(Coins.XMR) - messages.append('Done.') - except Exception as a: - err_messages.append('Failed.') - - template = env.get_template('debug.html') - return self.render_template(template, { - 'messages': messages, - 'err_messages': err_messages, - 'result': result, - 'summary': summary, - }) - def page_active(self, url_split, post_string): swap_client = self.server.swap_client swap_client.checkSystemStatus() @@ -502,7 +477,7 @@ class HttpHandler(BaseHTTPRequestHandler): if page == 'rpc': return self.page_rpc(url_split, post_string) if page == 'debug': - return self.page_debug(url_split, post_string) + return page_debug(self, url_split, post_string) if page == 'explorers': return self.page_explorers(url_split, post_string) if page == 'offer': diff --git a/basicswap/templates/debug.html b/basicswap/templates/debug.html index c478e2c..261b022 100644 --- a/basicswap/templates/debug.html +++ b/basicswap/templates/debug.html @@ -67,6 +67,13 @@
+ + Remove expired offers and bids + + + + Reinitialise XMR wallet @@ -82,8 +89,8 @@ Yes - Start Process - +
@@ -121,4 +128,9 @@ {% include 'footer.html' %} - \ No newline at end of file + + diff --git a/basicswap/templates/wallets.html b/basicswap/templates/wallets.html index 2ed296a..05de34f 100644 --- a/basicswap/templates/wallets.html +++ b/basicswap/templates/wallets.html @@ -142,18 +142,10 @@ {% endif %} {% endif %} - {% endfor %} + {% endfor %} {% include 'footer.html' %} - \ No newline at end of file + diff --git a/basicswap/ui/page_debug.py b/basicswap/ui/page_debug.py new file mode 100644 index 0000000..04b8689 --- /dev/null +++ b/basicswap/ui/page_debug.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 The BSX Developers +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +import traceback +from .util import ( + have_data_entry, +) +from basicswap.chainparams import ( + Coins, +) +from basicswap.db_util import ( + remove_expired_data, +) + + +def page_debug(self, url_split, post_string): + server = self.server + swap_client = server.swap_client + swap_client.checkSystemStatus() + summary = swap_client.getSummary() + + result = None + messages = [] + err_messages = [] + form_data = self.checkForm(post_string, 'wallets', err_messages) + if form_data: + if have_data_entry(form_data, 'reinit_xmr'): + try: + swap_client.initialiseWallet(Coins.XMR) + messages.append('Done.') + except Exception as e: + err_messages.append('Failed.') + + if have_data_entry(form_data, 'remove_expired'): + try: + remove_expired_data(swap_client) + messages.append('Done.') + except Exception as e: + if swap_client.debug is True: + swap_client.log.error(traceback.format_exc()) + else: + swap_client.log.error(f'remove_expired_data: {e}') + err_messages.append('Failed.') + + template = server.env.get_template('debug.html') + return self.render_template(template, { + 'messages': messages, + 'err_messages': err_messages, + 'result': result, + 'summary': summary, + }) diff --git a/doc/release-notes.md b/doc/release-notes.md index a5e4582..9497958 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -3,6 +3,7 @@ ============== - cores: Raised Particl and Monero daemon version. +- ui: Add debug option to remove expired offers, bids and transactions. 0.0.62