diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 91ca90b..17d783d 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2019-2020 tecnovert +# Copyright (c) 2019-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -36,6 +36,7 @@ from .util import ( pubkeyToAddress, format8, format_amount, + format_timestamp, encodeAddress, decodeAddress, DeserialiseNum, @@ -895,6 +896,12 @@ class BasicSwap(BaseApp): if ptx_state is not None and ptx_state != TxStates.TX_REFUNDED: self.returnAddressToPool(bid.bid_id, TxTypes.PTX_REFUND) + # Remove any delayed events + if self.debug: + session.execute('UPDATE eventqueue SET active_ind = 2 WHERE linked_id = {}'.format(bid.bid_id)) + else: + session.execute('DELETE FROM eventqueue WHERE linked_id = {}'.format(bid.bid_id)) + def loadFromDB(self): self.log.info('Loading data from db') self.mxDB.acquire() @@ -955,7 +962,7 @@ class BasicSwap(BaseApp): def validateOfferLockValue(self, coin_from, coin_to, lock_type, lock_value): if lock_type == OfferMessage.SEQUENCE_LOCK_TIME: - assert(lock_value >= 2 * 60 * 60 and lock_value <= 96 * 60 * 60), 'Invalid lock_value time' + assert(lock_value >= 1 * 60 * 60 and lock_value <= 96 * 60 * 60), 'Invalid lock_value time' assert(self.coin_clients[coin_from]['use_csv'] and self.coin_clients[coin_to]['use_csv']), 'Both coins need CSV activated.' elif lock_type == OfferMessage.SEQUENCE_LOCK_BLOCKS: assert(lock_value >= 5 and lock_value <= 1000), 'Invalid lock_value blocks' @@ -1681,11 +1688,19 @@ class BasicSwap(BaseApp): def list_bid_events(self, bid_id, session): session = scoped_session(self.session_factory) query_str = 'SELECT created_at, event_type, event_msg FROM eventlog ' + \ - 'WHERE linked_type = {} AND linked_id = x\'{}\' '.format(TableTypes.BID, bid_id.hex()) + 'WHERE active_ind = 1 AND linked_type = {} AND linked_id = x\'{}\' '.format(TableTypes.BID, bid_id.hex()) q = self.engine.execute(query_str) events = [] for row in q: events.append({'at': row[0], 'desc': describeEventEntry(row[1], row[2])}) + + query_str = 'SELECT created_at, trigger_at FROM eventqueue ' + \ + 'WHERE active_ind = 1 AND linked_id = x\'{}\' '.format(bid_id.hex()) + q = self.engine.execute(query_str) + events = [] + for row in q: + events.append({'at': row[0], 'desc': 'Delaying until: {}'.format(format_timestamp(row[1]))}) + return events def acceptBid(self, bid_id): @@ -2037,24 +2052,6 @@ class BasicSwap(BaseApp): finally: self.mxDB.release() - def abandonOffer(self, offer_id): - self.log.info('Abandoning Offer %s', offer_id.hex()) - self.mxDB.acquire() - try: - session = scoped_session(self.session_factory) - offer = session.query(Offer).filter_by(offer_id=offer_id).first() - assert(offer), 'Offer not found' - - # TODO: abandon linked bids? - - # Mark bid as abandoned, no further processing will be done - offer.setState(OfferStates.OFFER_ABANDONED) - session.commit() - finally: - session.close() - session.remove() - self.mxDB.release() - def abandonBid(self, bid_id): self.log.info('Abandoning Bid %s', bid_id.hex()) self.mxDB.acquire() @@ -3289,6 +3286,7 @@ class BasicSwap(BaseApp): self.log.info('Verify xmr bid {} failed: {}'.format(bid.bid_id.hex(), str(ex))) bid.setState(BidStates.BID_ERROR, 'Failed validation: ' + str(ex)) session.add(bid) + self.updateBidInProgress(bid) continue if bid.created_at + ttl_xmr_split_messages < now: self.log.debug('Expiring partially received bid: {}'.format(bid.bid_id.hex())) @@ -4500,7 +4498,7 @@ class BasicSwap(BaseApp): else: self.log.debug('TODO - determine in-progress for manualBidUpdate') if offer.swap_type == SwapTypes.XMR_SWAP: - if bid.state and bid.state in (BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, BidStates.XMR_SWAP_LOCK_RELEASED, BidStates.XMR_SWAP_NOSCRIPT_TX_REDEEMED): + if bid.state and bid.state in (BidStates.XMR_SWAP_HAVE_SCRIPT_COIN_SPEND_TX, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, BidStates.XMR_SWAP_NOSCRIPT_COIN_LOCKED, BidStates.XMR_SWAP_LOCK_RELEASED, BidStates.XMR_SWAP_NOSCRIPT_TX_REDEEMED): activate_bid = True if activate_bid: @@ -4792,6 +4790,12 @@ class BasicSwap(BaseApp): return True if passed is True else False # _possibly_revoked_offers should not contain duplicates return False + def updateBidInProgress(self, bid): + swap_in_progress = self.swaps_in_progress.get(bid.bid_id, None) + if swap_in_progress is None: + return + self.swaps_in_progress[bid.bid_id] = (bid, swap_in_progress[1]) + def add_connection(self, host, port, peer_pubkey): self.log.info('add_connection %s %d %s', host, port, peer_pubkey.hex()) self._network.add_connection(host, port, peer_pubkey) diff --git a/basicswap/http_server.py b/basicswap/http_server.py index b2dec48..deb4d40 100644 --- a/basicswap/http_server.py +++ b/basicswap/http_server.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2019 tecnovert +# Copyright (c) 2019-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. import os -import time import struct import traceback import threading @@ -16,6 +15,7 @@ from jinja2 import Environment, PackageLoader from . import __version__ from .util import ( + format_timestamp, dumpj, ) from .chainparams import ( @@ -49,10 +49,6 @@ from .ui import ( ) -def format_timestamp(value): - return time.strftime('%Y-%m-%d %H:%M', time.localtime(value)) - - env = Environment(loader=PackageLoader('basicswap', 'templates')) env.filters['formatts'] = format_timestamp @@ -635,7 +631,7 @@ class HttpHandler(BaseHTTPRequestHandler): ci_from = swap_client.ci(Coins(o.coin_from)) ci_to = swap_client.ci(Coins(o.coin_to)) formatted_offers.append(( - time.strftime('%Y-%m-%d %H:%M', time.localtime(o.created_at)), + format_timestamp(o.created_at), o.offer_id.hex(), ci_from.coin_name(), ci_to.coin_name(), ci_from.format_amount(o.amount_from), @@ -758,7 +754,7 @@ class HttpHandler(BaseHTTPRequestHandler): title=self.server.title, h2=self.server.title, page_type='Sent' if sent else 'Received', - bids=[(time.strftime('%Y-%m-%d %H:%M', time.localtime(b[0])), + bids=[(format_timestamp(b[0]), b[1].hex(), b[2].hex(), strBidState(b[4]), strTxState(b[6]), strTxState(b[7])) for b in bids], ), 'UTF-8') diff --git a/basicswap/js_server.py b/basicswap/js_server.py index cb4339e..65d3f9c 100644 --- a/basicswap/js_server.py +++ b/basicswap/js_server.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -8,7 +8,10 @@ import json import time import urllib.parse -from .util import format8 +from .util import ( + format8, + format_timestamp, +) from .basicswap import ( strBidState, SwapTypes, @@ -143,7 +146,7 @@ def js_bids(self, url_split, post_string): return bytes(json.dumps([{ 'bid_id': b[1].hex(), 'offer_id': b[2].hex(), - 'created_at': time.strftime('%Y-%m-%d %H:%M', time.localtime(b[0])), + 'created_at': format_timestamp(b[0]), 'amount_from': format8(b[3]), 'bid_state': strBidState(b[4]) } for b in bids]), 'UTF-8') diff --git a/basicswap/templates/bid_xmr.html b/basicswap/templates/bid_xmr.html index b09241a..609cd49 100644 --- a/basicswap/templates/bid_xmr.html +++ b/basicswap/templates/bid_xmr.html @@ -40,10 +40,10 @@ {% else %} {% if data.was_received == 'True' %} -
+
{% endif %} {% if data.can_abandon == true %} - + {% endif %} {% if data.show_txns %} diff --git a/basicswap/templates/offer_new_2.html b/basicswap/templates/offer_new_2.html index 26902ea..b3394c1 100644 --- a/basicswap/templates/offer_new_2.html +++ b/basicswap/templates/offer_new_2.html @@ -51,7 +51,7 @@ {% endif %} -Contract locked (hrs)Participate txn will be locked for half the time. +Contract locked (hrs)Participate txn will be locked for half the time. Auto Accept Bids diff --git a/basicswap/ui.py b/basicswap/ui.py index d05f4c7..9480abf 100644 --- a/basicswap/ui.py +++ b/basicswap/ui.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2020 tecnovert +# Copyright (c) 2020-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. diff --git a/basicswap/util.py b/basicswap/util.py index d5f0c14..52111ff 100644 --- a/basicswap/util.py +++ b/basicswap/util.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2018-2020 tecnovert +# Copyright (c) 2018-2021 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. + import json +import time import decimal import hashlib @@ -304,6 +306,10 @@ def format_amount(i, display_scale, scale=None): return rv +def format_timestamp(value): + return time.strftime('%Y-%m-%d %H:%M', time.localtime(value)) + + def getP2SHScriptForHash(p2sh): return bytes([OpCodes.OP_HASH160, 0x14]) \ + p2sh \