Raise versions, add release notes.
Add event log table. Offers can be revoked. Added separate range for retry delays.
This commit is contained in:
		
							parent
							
								
									dca9f08833
								
							
						
					
					
						commit
						8c9105ce01
					
				@ -1,3 +1,3 @@
 | 
			
		||||
name = "basicswap"
 | 
			
		||||
 | 
			
		||||
__version__ = "0.0.5"
 | 
			
		||||
__version__ = "0.0.6"
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import re
 | 
			
		||||
import zmq
 | 
			
		||||
import json
 | 
			
		||||
import time
 | 
			
		||||
import base64
 | 
			
		||||
import shutil
 | 
			
		||||
import random
 | 
			
		||||
import logging
 | 
			
		||||
@ -59,9 +60,11 @@ from .messages_pb2 import (
 | 
			
		||||
    XmrBidLockTxSigsMessage,
 | 
			
		||||
    XmrBidLockSpendTxMessage,
 | 
			
		||||
    XmrBidSecretMessage,
 | 
			
		||||
    OfferRevokeMessage,
 | 
			
		||||
)
 | 
			
		||||
from .db import (
 | 
			
		||||
    CURRENT_DB_VERSION,
 | 
			
		||||
    TableTypes,
 | 
			
		||||
    Base,
 | 
			
		||||
    DBKVInt,
 | 
			
		||||
    DBKVString,
 | 
			
		||||
@ -72,6 +75,7 @@ from .db import (
 | 
			
		||||
    SentOffer,
 | 
			
		||||
    SmsgAddress,
 | 
			
		||||
    EventQueue,
 | 
			
		||||
    EventLog,
 | 
			
		||||
    XmrOffer,
 | 
			
		||||
    XmrSwap,
 | 
			
		||||
    XmrSplitData,
 | 
			
		||||
@ -100,6 +104,7 @@ class MessageTypes(IntEnum):
 | 
			
		||||
    XMR_BID_TXN_SIGS_FL = auto()
 | 
			
		||||
    XMR_BID_LOCK_SPEND_TX_LF = auto()
 | 
			
		||||
    XMR_BID_SECRET_LF = auto()
 | 
			
		||||
    OFFER_REVOKE = auto()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SwapTypes(IntEnum):
 | 
			
		||||
@ -176,6 +181,10 @@ class EventTypes(IntEnum):
 | 
			
		||||
    RECOVER_XMR_SWAP_LOCK_TX_B = auto()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EventLogTypes(IntEnum):
 | 
			
		||||
    FAILED_TX_B_PUBLISH = auto()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XmrSplitMsgTypes(IntEnum):
 | 
			
		||||
    BID = auto()
 | 
			
		||||
    BID_ACCEPT = auto()
 | 
			
		||||
@ -404,8 +413,11 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self._last_checked_xmr_swaps = 0
 | 
			
		||||
 | 
			
		||||
        # TODO: Adjust ranges
 | 
			
		||||
        self.min_delay_auto_accept = self.settings.get('min_delay_auto_accept', 10)
 | 
			
		||||
        self.max_delay_auto_accept = self.settings.get('max_delay_auto_accept', 60)
 | 
			
		||||
        self.min_delay_event = self.settings.get('min_delay_event', 10)
 | 
			
		||||
        self.max_delay_event = self.settings.get('max_delay_event', 60)
 | 
			
		||||
 | 
			
		||||
        self.min_delay_retry = self.settings.get('min_delay_retry', 20)
 | 
			
		||||
        self.max_delay_retry = self.settings.get('max_delay_retry', 120)
 | 
			
		||||
 | 
			
		||||
        self.swaps_in_progress = dict()
 | 
			
		||||
 | 
			
		||||
@ -922,6 +934,35 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self.log.info('Sent OFFER %s', offer_id.hex())
 | 
			
		||||
        return offer_id
 | 
			
		||||
 | 
			
		||||
    def revokeOffer(self, offer_id):
 | 
			
		||||
        self.log.info('Revoking offer %s', offer_id.hex())
 | 
			
		||||
 | 
			
		||||
        session = None
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            offer = session.query(Offer).filter_by(offer_id=offer_id).first()
 | 
			
		||||
 | 
			
		||||
            msg_buf = OfferRevokeMessage()
 | 
			
		||||
            msg_buf.offer_msg_id = offer_id
 | 
			
		||||
 | 
			
		||||
            signature_enc = self.callcoinrpc(Coins.PART, 'signmessage', [offer.addr_from, offer_id.hex() + '_revoke'])
 | 
			
		||||
 | 
			
		||||
            msg_buf.signature = base64.b64decode(signature_enc)
 | 
			
		||||
 | 
			
		||||
            msg_bytes = msg_buf.SerializeToString()
 | 
			
		||||
            payload_hex = str.format('{:02x}', MessageTypes.OFFER_REVOKE) + msg_bytes.hex()
 | 
			
		||||
 | 
			
		||||
            options = {'decodehex': True, 'ttl_is_seconds': True}
 | 
			
		||||
            ro = self.callrpc('smsgsend', [offer.addr_from, self.network_addr, payload_hex, False, offer.time_valid, False, options])
 | 
			
		||||
            msg_id = ro['msgid']
 | 
			
		||||
        finally:
 | 
			
		||||
            if session:
 | 
			
		||||
                session.close()
 | 
			
		||||
                session.remove()
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_xmr=False):
 | 
			
		||||
        account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
 | 
			
		||||
        evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
 | 
			
		||||
@ -1141,7 +1182,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
        return (sign_for_addr, signature)
 | 
			
		||||
 | 
			
		||||
    def saveBidInSession(self, bid_id, bid, session, xmr_swap=None):
 | 
			
		||||
    def saveBidInSession(self, bid_id, bid, session, xmr_swap=None, save_in_progress=None):
 | 
			
		||||
        session.add(bid)
 | 
			
		||||
        if bid.initiate_tx:
 | 
			
		||||
            session.add(bid.initiate_tx)
 | 
			
		||||
@ -1158,6 +1199,11 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        if xmr_swap is not None:
 | 
			
		||||
            session.add(xmr_swap)
 | 
			
		||||
 | 
			
		||||
        if save_in_progress is not None:
 | 
			
		||||
            if not isinstance(save_in_progress, Offer):
 | 
			
		||||
                raise ValueError('Must specify offer for save_in_progress')
 | 
			
		||||
            self.swaps_in_progress[bid_id] = (bid, save_in_progress)  # (bid, offer)
 | 
			
		||||
 | 
			
		||||
    def saveBid(self, bid_id, bid, xmr_swap=None):
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
@ -1182,12 +1228,13 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
    def createEventInSession(self, delay, event_type, linked_id, session):
 | 
			
		||||
        self.log.debug('createEvent %d %s', event_type, linked_id.hex())
 | 
			
		||||
        event = EventQueue()
 | 
			
		||||
        event.active_ind = 1
 | 
			
		||||
        event.created_at = int(time.time())
 | 
			
		||||
        event.trigger_at = event.created_at + delay
 | 
			
		||||
        event.event_type = event_type
 | 
			
		||||
        event.linked_id = linked_id
 | 
			
		||||
        now = int(time.time())
 | 
			
		||||
        event = EventQueue(
 | 
			
		||||
            active_ind=1,
 | 
			
		||||
            created_at=now,
 | 
			
		||||
            trigger_at=now + delay,
 | 
			
		||||
            event_type=event_type,
 | 
			
		||||
            linked_id=linked_id)
 | 
			
		||||
        session.add(event)
 | 
			
		||||
 | 
			
		||||
    def createEvent(self, delay, event_type, linked_id):
 | 
			
		||||
@ -1202,6 +1249,21 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        finally:
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
 | 
			
		||||
    def logBidEvent(self, bid, event_type, event_msg, session):
 | 
			
		||||
        self.log.debug('logBidEvent %s %s', bid.bid_id.hex(), event_type)
 | 
			
		||||
        entry = EventLog(
 | 
			
		||||
            active_ind=1,
 | 
			
		||||
            created_at=int(time.time()),
 | 
			
		||||
            linked_type=TableTypes.BID,
 | 
			
		||||
            linked_id=bid.bid_id,
 | 
			
		||||
            event_type=int(event_type),
 | 
			
		||||
            event_msg=event_msg)
 | 
			
		||||
        session.add(entry)
 | 
			
		||||
 | 
			
		||||
    def countBidEvents(self, bid, event_type, session):
 | 
			
		||||
        q = session.execute('SELECT COUNT(*) FROM eventlog WHERE linked_type = {} AND linked_id = x\'{}\' AND event_type = {}'.format(int(TableTypes.BID), bid.bid_id.hex(), int(event_type))).first()
 | 
			
		||||
        return q[0]
 | 
			
		||||
 | 
			
		||||
    def postBid(self, offer_id, amount, addr_send_from=None):
 | 
			
		||||
        # Bid to send bid.amount * offer.rate of coin_to in exchange for bid.amount of coin_from
 | 
			
		||||
        self.log.debug('postBid %s %s', offer_id.hex(), format8(amount))
 | 
			
		||||
@ -2370,7 +2432,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                    self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
 | 
			
		||||
                    if bid.was_sent:
 | 
			
		||||
                        delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
                        delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                        self.log.info('Sending xmr swap chain B lock tx for bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                        self.createEventInSession(delay, EventTypes.SEND_XMR_SWAP_LOCK_TX_B, bid_id, session)
 | 
			
		||||
                        # bid.setState(BidStates.SWAP_DELAYING)
 | 
			
		||||
@ -2398,7 +2460,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                    self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
 | 
			
		||||
                    if bid.was_received:
 | 
			
		||||
                        delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
                        delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                        self.log.info('Releasing xmr swap secret for bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                        self.createEventInSession(delay, EventTypes.SEND_XMR_SECRET, bid_id, session)
 | 
			
		||||
 | 
			
		||||
@ -2697,7 +2759,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                    if not bid.was_received:
 | 
			
		||||
                        bid.setState(BidStates.SWAP_COMPLETED)
 | 
			
		||||
                    if bid.was_received:
 | 
			
		||||
                        delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
                        delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                        self.log.info('Redeeming coin b lock tx for bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                        self.createEventInSession(delay, EventTypes.REDEEM_XMR_SWAP_LOCK_TX_B, bid_id, session)
 | 
			
		||||
                else:
 | 
			
		||||
@ -2710,9 +2772,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            else:
 | 
			
		||||
                self.setBidError(bid.bid_id, bid, 'Unexpected txn spent coin a lock tx: {}'.format(spend_txid_hex), save_bid=False)
 | 
			
		||||
 | 
			
		||||
            self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
            # Update copy of bid in swaps_in_progress
 | 
			
		||||
            self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
            self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
            session.commit()
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
            self.log.error('process_XMR_SWAP_A_LOCK_tx_spend %s', str(ex))
 | 
			
		||||
@ -2753,7 +2813,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                            txid=xmr_swap.a_lock_refund_spend_tx_id,
 | 
			
		||||
                        )
 | 
			
		||||
                    if bid.xmr_b_lock_tx is not None:
 | 
			
		||||
                        delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
                        delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                        self.log.info('Recovering xmr swap chain B lock tx for bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                        self.createEventInSession(delay, EventTypes.RECOVER_XMR_SWAP_LOCK_TX_B, bid_id, session)
 | 
			
		||||
                    else:
 | 
			
		||||
@ -2767,9 +2827,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                self.log.info('Coin a lock refund spent by unknown tx, bid {}'.format(bid_id.hex()))
 | 
			
		||||
                bid.setState(BidStates.XMR_SWAP_FAILED_SWIPED)
 | 
			
		||||
 | 
			
		||||
            self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
            # Update copy of bid in swaps_in_progress
 | 
			
		||||
            self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
            self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
            session.commit()
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
            self.log.error('process_XMR_SWAP_A_LOCK_REFUND_tx_spend %s', str(ex))
 | 
			
		||||
@ -2990,6 +3048,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        if existing_offer is None:
 | 
			
		||||
            offer = Offer(
 | 
			
		||||
                offer_id=offer_id,
 | 
			
		||||
                active_ind=1,
 | 
			
		||||
 | 
			
		||||
                coin_from=offer_data.coin_from,
 | 
			
		||||
                coin_to=offer_data.coin_to,
 | 
			
		||||
@ -3028,6 +3087,44 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        session.close()
 | 
			
		||||
        session.remove()
 | 
			
		||||
 | 
			
		||||
    def processOfferRevoke(self, msg):
 | 
			
		||||
        assert(msg['to'] == self.network_addr), 'Message received on wrong address'
 | 
			
		||||
 | 
			
		||||
        msg_bytes = bytes.fromhex(msg['hex'][2:-2])
 | 
			
		||||
        msg_data = OfferRevokeMessage()
 | 
			
		||||
        msg_data.ParseFromString(msg_bytes)
 | 
			
		||||
 | 
			
		||||
        now = int(time.time())
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        session = None
 | 
			
		||||
        try:
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
            offer = session.query(Offer).filter_by(offer_id=msg_data.offer_msg_id).first()
 | 
			
		||||
            if offer is None:
 | 
			
		||||
                raise ValueError('Offer not found: {}'.format(msg_data.offer_msg_id.hex()))
 | 
			
		||||
 | 
			
		||||
            if offer.expire_at <= now:
 | 
			
		||||
                raise ValueError('Offer already expired: {}'.format(msg_data.offer_msg_id.hex()))
 | 
			
		||||
 | 
			
		||||
            if len(msg_data.signature) != 65:
 | 
			
		||||
                raise ValueError('Invalid signature length')
 | 
			
		||||
 | 
			
		||||
            signature_enc = base64.b64encode(msg_data.signature).decode('utf-8')
 | 
			
		||||
 | 
			
		||||
            passed = self.callcoinrpc(Coins.PART, 'verifymessage', [offer.addr_from, signature_enc, msg_data.offer_msg_id.hex() + '_revoke'])
 | 
			
		||||
            assert(passed is True), 'Proof of funds signature invalid'
 | 
			
		||||
 | 
			
		||||
            offer.active_ind = 2
 | 
			
		||||
            # TODO: Remove message, or wait for expire
 | 
			
		||||
 | 
			
		||||
            session.add(offer)
 | 
			
		||||
            session.commit()
 | 
			
		||||
        finally:
 | 
			
		||||
            if session:
 | 
			
		||||
                session.close()
 | 
			
		||||
                session.remove()
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
    def processBid(self, msg):
 | 
			
		||||
        self.log.debug('Processing bid msg %s', msg['msgid'])
 | 
			
		||||
        now = int(time.time())
 | 
			
		||||
@ -3110,7 +3207,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            if self.countAcceptedBids(offer_id) > 0:
 | 
			
		||||
                self.log.info('Not auto accepting bid %s, already have', bid_id.hex())
 | 
			
		||||
            else:
 | 
			
		||||
                delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
                delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
                self.log.info('Auto accepting bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                self.createEvent(delay, EventTypes.ACCEPT_BID, bid_id)
 | 
			
		||||
 | 
			
		||||
@ -3275,7 +3372,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        bid.setState(BidStates.SWAP_DELAYING)
 | 
			
		||||
        self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
 | 
			
		||||
 | 
			
		||||
        delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
        delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
        self.log.info('Responding to xmr bid accept %s in %d seconds', bid.bid_id.hex(), delay)
 | 
			
		||||
        self.createEventInSession(delay, EventTypes.SIGN_XMR_SWAP_LOCK_TX_A, bid.bid_id, session)
 | 
			
		||||
 | 
			
		||||
@ -3573,15 +3670,22 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        try:
 | 
			
		||||
            b_lock_tx_id = ci_to.publishBLockTx(xmr_swap.pkbv, xmr_swap.pkbs, bid.amount_to, xmr_offer.b_fee_rate)
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
            self.log.error('publishBLockTx failed for bid {} with error {}'.format(bid_id.hex(), str(ex)))
 | 
			
		||||
            error_msg = 'publishBLockTx failed for bid {} with error {}'.format(bid_id.hex(), str(ex))
 | 
			
		||||
            num_retries = self.countBidEvents(bid, EventLogTypes.FAILED_TX_B_PUBLISH, session)
 | 
			
		||||
            if num_retries > 0:
 | 
			
		||||
                error_msg += ', retry no. {}'.format(num_retries)
 | 
			
		||||
            self.log.error(error_msg)
 | 
			
		||||
 | 
			
		||||
            if 'not enough unlocked money' in str(ex):
 | 
			
		||||
                delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)  # TODO: New delay range
 | 
			
		||||
            str_error = str(ex)
 | 
			
		||||
            if num_retries < 5 and 'not enough unlocked money' in str_error or 'transaction was rejected by daemon' in str_error:
 | 
			
		||||
                delay = random.randrange(self.min_delay_retry, self.max_delay_retry)
 | 
			
		||||
                self.log.info('Retrying sending xmr swap chain B lock tx for bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
                self.createEventInSession(delay, EventTypes.SEND_XMR_SWAP_LOCK_TX_B, bid_id, session)
 | 
			
		||||
            else:
 | 
			
		||||
                self.setBidError(bid_id, bid, 'publishBLockTx failed: ' + str(ex), save_bid=False)
 | 
			
		||||
                self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
                self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
 | 
			
		||||
            self.logBidEvent(bid, EventLogTypes.FAILED_TX_B_PUBLISH, str_error, session)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self.log.debug('Submitted lock txn %s to %s chain for bid %s', b_lock_tx_id.hex(), chainparams[coin_to]['name'], bid_id.hex())
 | 
			
		||||
@ -3592,10 +3696,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        )
 | 
			
		||||
        bid.xmr_b_lock_tx.setState(TxStates.TX_NONE)
 | 
			
		||||
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
 | 
			
		||||
        # Update copy of bid in swaps_in_progress
 | 
			
		||||
        self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
 | 
			
		||||
    def sendXmrBidSecret(self, bid_id, session):
 | 
			
		||||
        # Leader sending lock tx a release secret (MSG5F)
 | 
			
		||||
@ -3627,9 +3728,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        xmr_swap.coin_a_lock_refund_spend_tx_msg_id = bytes.fromhex(ro['msgid'])
 | 
			
		||||
 | 
			
		||||
        bid.setState(BidStates.XMR_SWAP_SECRET_SHARED)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
        # Update copy of bid in swaps_in_progress
 | 
			
		||||
        self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
 | 
			
		||||
    def redeemXmrBidCoinALockTx(self, bid_id, session):
 | 
			
		||||
        # Follower redeeming A lock tx
 | 
			
		||||
@ -3678,9 +3777,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        )
 | 
			
		||||
        bid.xmr_a_lock_spend_tx.setState(TxStates.TX_NONE)
 | 
			
		||||
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
        # Update copy of bid in swaps_in_progress
 | 
			
		||||
        self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
 | 
			
		||||
    def redeemXmrBidCoinBLockTx(self, bid_id, session):
 | 
			
		||||
        # Leader redeeming B lock tx
 | 
			
		||||
@ -3714,9 +3811,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        bid.xmr_b_lock_tx.spend_txid = txid
 | 
			
		||||
        bid.setState(BidStates.XMR_SWAP_NOSCRIPT_TX_REDEEMED)
 | 
			
		||||
        # TODO: Why does using bid.txns error here?
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
        # Update copy of bid in swaps_in_progress
 | 
			
		||||
        self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
 | 
			
		||||
    def recoverXmrBidCoinBLockTx(self, bid_id, session):
 | 
			
		||||
        # Follower recovering B lock tx
 | 
			
		||||
@ -3750,9 +3845,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        bid.xmr_b_lock_tx.spend_txid = txid
 | 
			
		||||
 | 
			
		||||
        bid.setState(BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
        # Update copy of bid in swaps_in_progress
 | 
			
		||||
        self.swaps_in_progress[bid_id] = (bid, offer)
 | 
			
		||||
        self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
 | 
			
		||||
    def processXmrBidCoinALockSigs(self, msg):
 | 
			
		||||
        # Leader processing MSG3L
 | 
			
		||||
@ -3803,7 +3896,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            assert(v), 'Invalid signature for lock refund spend txn'
 | 
			
		||||
            self.addLockRefundSigs(xmr_swap, ci_from)
 | 
			
		||||
 | 
			
		||||
            delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
            delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
            self.log.info('Sending coin A lock tx for xmr bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
            self.createEvent(delay, EventTypes.SEND_XMR_SWAP_LOCK_TX_A, bid_id)
 | 
			
		||||
 | 
			
		||||
@ -3902,7 +3995,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
        xmr_swap.sv = msg_data.secret_value
 | 
			
		||||
 | 
			
		||||
        delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
 | 
			
		||||
        delay = random.randrange(self.min_delay_event, self.max_delay_event)
 | 
			
		||||
        self.log.info('Redeeming coin A lock tx for xmr bid %s in %d seconds', bid_id.hex(), delay)
 | 
			
		||||
        self.createEvent(delay, EventTypes.REDEEM_XMR_SWAP_LOCK_TX_A, bid_id)
 | 
			
		||||
 | 
			
		||||
@ -3934,6 +4027,8 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                self.processXmrSplitMessage(msg)
 | 
			
		||||
            elif msg_type == MessageTypes.XMR_BID_SECRET_LF:
 | 
			
		||||
                self.processXmrSecretMessage(msg)
 | 
			
		||||
            if msg_type == MessageTypes.OFFER_REVOKE:
 | 
			
		||||
                self.processOfferRevoke(msg)
 | 
			
		||||
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
            self.log.error('processMsg %s', str(ex))
 | 
			
		||||
@ -4143,7 +4238,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            if sent:
 | 
			
		||||
                q = session.query(Offer).filter(Offer.was_sent == True)  # noqa E712
 | 
			
		||||
            else:
 | 
			
		||||
                q = session.query(Offer).filter(Offer.expire_at > now)
 | 
			
		||||
                q = session.query(Offer).filter(sa.and_(Offer.expire_at > now, Offer.active_ind == 1))
 | 
			
		||||
 | 
			
		||||
            filter_offer_id = filters.get('offer_id', None)
 | 
			
		||||
            if filter_offer_id is not None:
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,18 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2019 tecnovert
 | 
			
		||||
# Copyright (c) 2019-2020 tecnovert
 | 
			
		||||
# Distributed under the MIT software license, see the accompanying
 | 
			
		||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
 | 
			
		||||
 | 
			
		||||
import struct
 | 
			
		||||
import time
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
 | 
			
		||||
from sqlalchemy.ext.declarative import declarative_base
 | 
			
		||||
from enum import IntEnum, auto
 | 
			
		||||
 | 
			
		||||
CURRENT_DB_VERSION = 2
 | 
			
		||||
 | 
			
		||||
CURRENT_DB_VERSION = 3
 | 
			
		||||
Base = declarative_base()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -32,6 +34,7 @@ class Offer(Base):
 | 
			
		||||
    __tablename__ = 'offers'
 | 
			
		||||
 | 
			
		||||
    offer_id = sa.Column(sa.LargeBinary, primary_key=True)
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    coin_from = sa.Column(sa.Integer)
 | 
			
		||||
    coin_to = sa.Column(sa.Integer)
 | 
			
		||||
@ -75,6 +78,7 @@ class Bid(Base):
 | 
			
		||||
 | 
			
		||||
    bid_id = sa.Column(sa.LargeBinary, primary_key=True)
 | 
			
		||||
    offer_id = sa.Column(sa.LargeBinary, sa.ForeignKey('offers.offer_id'))
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
 | 
			
		||||
    was_sent = sa.Column(sa.Boolean)
 | 
			
		||||
    was_received = sa.Column(sa.Boolean)
 | 
			
		||||
@ -212,6 +216,20 @@ class EventQueue(Base):
 | 
			
		||||
    event_data = sa.Column(sa.LargeBinary)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EventLog(Base):
 | 
			
		||||
    __tablename__ = 'eventlog'
 | 
			
		||||
 | 
			
		||||
    event_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
 | 
			
		||||
    active_ind = sa.Column(sa.Integer)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
    linked_type = sa.Column(sa.Integer)
 | 
			
		||||
    linked_id = sa.Column(sa.LargeBinary)
 | 
			
		||||
    event_type = sa.Column(sa.Integer)
 | 
			
		||||
    event_msg = sa.Column(sa.String)
 | 
			
		||||
 | 
			
		||||
    __table_args__ = (sa.Index('main_index', 'linked_type', 'linked_id'), )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XmrOffer(Base):
 | 
			
		||||
    __tablename__ = 'xmr_offers'
 | 
			
		||||
 | 
			
		||||
@ -310,3 +328,8 @@ class XmrSplitData(Base):
 | 
			
		||||
    msg_sequence = sa.Column(sa.Integer)
 | 
			
		||||
    dleag = sa.Column(sa.LargeBinary)
 | 
			
		||||
    created_at = sa.Column(sa.BigInteger)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TableTypes(IntEnum):
 | 
			
		||||
    OFFER = auto()
 | 
			
		||||
    BID = auto()
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,11 @@ message BidAcceptMessage {
 | 
			
		||||
    bytes contract_script = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message OfferRevokeMessage {
 | 
			
		||||
    bytes offer_msg_id = 1;
 | 
			
		||||
    bytes signature = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
message XmrBidMessage {
 | 
			
		||||
    /* MSG1L, F -> L */
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
 | 
			
		||||
  syntax='proto3',
 | 
			
		||||
  serialized_options=None,
 | 
			
		||||
  create_key=_descriptor._internal_create_key,
 | 
			
		||||
  serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\xd8\x03\n\x0cOfferMessage\x12\x11\n\tcoin_from\x18\x01 \x01(\r\x12\x0f\n\x07\x63oin_to\x18\x02 \x01(\r\x12\x13\n\x0b\x61mount_from\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x16\n\x0emin_bid_amount\x18\x05 \x01(\x04\x12\x12\n\ntime_valid\x18\x06 \x01(\x04\x12\x33\n\tlock_type\x18\x07 \x01(\x0e\x32 .basicswap.OfferMessage.LockType\x12\x12\n\nlock_value\x18\x08 \x01(\r\x12\x11\n\tswap_type\x18\t \x01(\r\x12\x15\n\rproof_address\x18\n \x01(\t\x12\x17\n\x0fproof_signature\x18\x0b \x01(\t\x12\x15\n\rpkhash_seller\x18\x0c \x01(\x0c\x12\x13\n\x0bsecret_hash\x18\r \x01(\x0c\x12\x15\n\rfee_rate_from\x18\x0e \x01(\x04\x12\x13\n\x0b\x66\x65\x65_rate_to\x18\x0f \x01(\x04\"q\n\x08LockType\x12\x0b\n\x07NOT_SET\x10\x00\x12\x18\n\x14SEQUENCE_LOCK_BLOCKS\x10\x01\x12\x16\n\x12SEQUENCE_LOCK_TIME\x10\x02\x12\x13\n\x0f\x41\x42S_LOCK_BLOCKS\x10\x03\x12\x11\n\rABS_LOCK_TIME\x10\x04\"\x8c\x01\n\nBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x04 \x01(\x0c\x12\x15\n\rproof_address\x18\x05 \x01(\t\x12\x17\n\x0fproof_signature\x18\x06 \x01(\t\"V\n\x10\x42idAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x15\n\rinitiate_txid\x18\x02 \x01(\x0c\x12\x17\n\x0f\x63ontract_script\x18\x03 \x01(\x0c\"\x99\x01\n\rXmrBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04pkaf\x18\x04 \x01(\x0c\x12\r\n\x05pkarf\x18\x05 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x06 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x07 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\x08 \x01(\x0c\"T\n\x0fXmrSplitMessage\x12\x0e\n\x06msg_id\x18\x01 \x01(\x0c\x12\x10\n\x08msg_type\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\r\n\x05\x64leag\x18\x04 \x01(\x0c\"\x9b\x02\n\x13XmrBidAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\n\n\x02sh\x18\x02 \x01(\x0c\x12\x0c\n\x04pkal\x18\x03 \x01(\x0c\x12\r\n\x05pkarl\x18\x04 \x01(\x0c\x12\x0c\n\x04kbvl\x18\x05 \x01(\x0c\x12\x12\n\nkbsl_dleag\x18\x06 \x01(\x0c\x12\x11\n\ta_lock_tx\x18\x07 \x01(\x0c\x12\x18\n\x10\x61_lock_tx_script\x18\x08 \x01(\x0c\x12\x18\n\x10\x61_lock_refund_tx\x18\t \x01(\x0c\x12\x1f\n\x17\x61_lock_refund_tx_script\x18\n \x01(\x0c\x12\x1e\n\x16\x61_lock_refund_spend_tx\x18\x0b \x01(\x0c\x12\x1d\n\x15\x61l_lock_refund_tx_sig\x18\x0c \x01(\x0c\"r\n\x17XmrBidLockTxSigsMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12$\n\x1c\x61\x66_lock_refund_spend_tx_esig\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61\x66_lock_refund_tx_sig\x18\x03 \x01(\x0c\"f\n\x18XmrBidLockSpendTxMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x17\n\x0f\x61_lock_spend_tx\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61l_lock_spend_tx_esig\x18\x03 \x01(\x0c\"?\n\x13XmrBidSecretMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x14\n\x0csecret_value\x18\x02 \x01(\x0c\x62\x06proto3'
 | 
			
		||||
  serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\xd8\x03\n\x0cOfferMessage\x12\x11\n\tcoin_from\x18\x01 \x01(\r\x12\x0f\n\x07\x63oin_to\x18\x02 \x01(\r\x12\x13\n\x0b\x61mount_from\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x16\n\x0emin_bid_amount\x18\x05 \x01(\x04\x12\x12\n\ntime_valid\x18\x06 \x01(\x04\x12\x33\n\tlock_type\x18\x07 \x01(\x0e\x32 .basicswap.OfferMessage.LockType\x12\x12\n\nlock_value\x18\x08 \x01(\r\x12\x11\n\tswap_type\x18\t \x01(\r\x12\x15\n\rproof_address\x18\n \x01(\t\x12\x17\n\x0fproof_signature\x18\x0b \x01(\t\x12\x15\n\rpkhash_seller\x18\x0c \x01(\x0c\x12\x13\n\x0bsecret_hash\x18\r \x01(\x0c\x12\x15\n\rfee_rate_from\x18\x0e \x01(\x04\x12\x13\n\x0b\x66\x65\x65_rate_to\x18\x0f \x01(\x04\"q\n\x08LockType\x12\x0b\n\x07NOT_SET\x10\x00\x12\x18\n\x14SEQUENCE_LOCK_BLOCKS\x10\x01\x12\x16\n\x12SEQUENCE_LOCK_TIME\x10\x02\x12\x13\n\x0f\x41\x42S_LOCK_BLOCKS\x10\x03\x12\x11\n\rABS_LOCK_TIME\x10\x04\"\x8c\x01\n\nBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x04 \x01(\x0c\x12\x15\n\rproof_address\x18\x05 \x01(\t\x12\x17\n\x0fproof_signature\x18\x06 \x01(\t\"V\n\x10\x42idAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x15\n\rinitiate_txid\x18\x02 \x01(\x0c\x12\x17\n\x0f\x63ontract_script\x18\x03 \x01(\x0c\"=\n\x12OfferRevokeMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"\x99\x01\n\rXmrBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04pkaf\x18\x04 \x01(\x0c\x12\r\n\x05pkarf\x18\x05 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x06 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x07 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\x08 \x01(\x0c\"T\n\x0fXmrSplitMessage\x12\x0e\n\x06msg_id\x18\x01 \x01(\x0c\x12\x10\n\x08msg_type\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\r\n\x05\x64leag\x18\x04 \x01(\x0c\"\x9b\x02\n\x13XmrBidAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\n\n\x02sh\x18\x02 \x01(\x0c\x12\x0c\n\x04pkal\x18\x03 \x01(\x0c\x12\r\n\x05pkarl\x18\x04 \x01(\x0c\x12\x0c\n\x04kbvl\x18\x05 \x01(\x0c\x12\x12\n\nkbsl_dleag\x18\x06 \x01(\x0c\x12\x11\n\ta_lock_tx\x18\x07 \x01(\x0c\x12\x18\n\x10\x61_lock_tx_script\x18\x08 \x01(\x0c\x12\x18\n\x10\x61_lock_refund_tx\x18\t \x01(\x0c\x12\x1f\n\x17\x61_lock_refund_tx_script\x18\n \x01(\x0c\x12\x1e\n\x16\x61_lock_refund_spend_tx\x18\x0b \x01(\x0c\x12\x1d\n\x15\x61l_lock_refund_tx_sig\x18\x0c \x01(\x0c\"r\n\x17XmrBidLockTxSigsMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12$\n\x1c\x61\x66_lock_refund_spend_tx_esig\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61\x66_lock_refund_tx_sig\x18\x03 \x01(\x0c\"f\n\x18XmrBidLockSpendTxMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x17\n\x0f\x61_lock_spend_tx\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61l_lock_spend_tx_esig\x18\x03 \x01(\x0c\"?\n\x13XmrBidSecretMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x14\n\x0csecret_value\x18\x02 \x01(\x0c\x62\x06proto3'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -309,6 +309,45 @@ _BIDACCEPTMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_OFFERREVOKEMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  name='OfferRevokeMessage',
 | 
			
		||||
  full_name='basicswap.OfferRevokeMessage',
 | 
			
		||||
  filename=None,
 | 
			
		||||
  file=DESCRIPTOR,
 | 
			
		||||
  containing_type=None,
 | 
			
		||||
  create_key=_descriptor._internal_create_key,
 | 
			
		||||
  fields=[
 | 
			
		||||
    _descriptor.FieldDescriptor(
 | 
			
		||||
      name='offer_msg_id', full_name='basicswap.OfferRevokeMessage.offer_msg_id', index=0,
 | 
			
		||||
      number=1, type=12, cpp_type=9, label=1,
 | 
			
		||||
      has_default_value=False, default_value=b"",
 | 
			
		||||
      message_type=None, enum_type=None, containing_type=None,
 | 
			
		||||
      is_extension=False, extension_scope=None,
 | 
			
		||||
      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
 | 
			
		||||
    _descriptor.FieldDescriptor(
 | 
			
		||||
      name='signature', full_name='basicswap.OfferRevokeMessage.signature', index=1,
 | 
			
		||||
      number=2, type=12, cpp_type=9, label=1,
 | 
			
		||||
      has_default_value=False, default_value=b"",
 | 
			
		||||
      message_type=None, enum_type=None, containing_type=None,
 | 
			
		||||
      is_extension=False, extension_scope=None,
 | 
			
		||||
      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
 | 
			
		||||
  ],
 | 
			
		||||
  extensions=[
 | 
			
		||||
  ],
 | 
			
		||||
  nested_types=[],
 | 
			
		||||
  enum_types=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_options=None,
 | 
			
		||||
  is_extendable=False,
 | 
			
		||||
  syntax='proto3',
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=735,
 | 
			
		||||
  serialized_end=796,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_XMRBIDMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  name='XmrBidMessage',
 | 
			
		||||
  full_name='basicswap.XmrBidMessage',
 | 
			
		||||
@ -385,8 +424,8 @@ _XMRBIDMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=736,
 | 
			
		||||
  serialized_end=889,
 | 
			
		||||
  serialized_start=799,
 | 
			
		||||
  serialized_end=952,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -438,8 +477,8 @@ _XMRSPLITMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=891,
 | 
			
		||||
  serialized_end=975,
 | 
			
		||||
  serialized_start=954,
 | 
			
		||||
  serialized_end=1038,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -547,8 +586,8 @@ _XMRBIDACCEPTMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=978,
 | 
			
		||||
  serialized_end=1261,
 | 
			
		||||
  serialized_start=1041,
 | 
			
		||||
  serialized_end=1324,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -593,8 +632,8 @@ _XMRBIDLOCKTXSIGSMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=1263,
 | 
			
		||||
  serialized_end=1377,
 | 
			
		||||
  serialized_start=1326,
 | 
			
		||||
  serialized_end=1440,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -639,8 +678,8 @@ _XMRBIDLOCKSPENDTXMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=1379,
 | 
			
		||||
  serialized_end=1481,
 | 
			
		||||
  serialized_start=1442,
 | 
			
		||||
  serialized_end=1544,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -678,8 +717,8 @@ _XMRBIDSECRETMESSAGE = _descriptor.Descriptor(
 | 
			
		||||
  extension_ranges=[],
 | 
			
		||||
  oneofs=[
 | 
			
		||||
  ],
 | 
			
		||||
  serialized_start=1483,
 | 
			
		||||
  serialized_end=1546,
 | 
			
		||||
  serialized_start=1546,
 | 
			
		||||
  serialized_end=1609,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
_OFFERMESSAGE.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE
 | 
			
		||||
@ -687,6 +726,7 @@ _OFFERMESSAGE_LOCKTYPE.containing_type = _OFFERMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['OfferMessage'] = _OFFERMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['BidMessage'] = _BIDMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['BidAcceptMessage'] = _BIDACCEPTMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['OfferRevokeMessage'] = _OFFERREVOKEMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['XmrBidMessage'] = _XMRBIDMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['XmrSplitMessage'] = _XMRSPLITMESSAGE
 | 
			
		||||
DESCRIPTOR.message_types_by_name['XmrBidAcceptMessage'] = _XMRBIDACCEPTMESSAGE
 | 
			
		||||
@ -716,6 +756,13 @@ BidAcceptMessage = _reflection.GeneratedProtocolMessageType('BidAcceptMessage',
 | 
			
		||||
  })
 | 
			
		||||
_sym_db.RegisterMessage(BidAcceptMessage)
 | 
			
		||||
 | 
			
		||||
OfferRevokeMessage = _reflection.GeneratedProtocolMessageType('OfferRevokeMessage', (_message.Message,), {
 | 
			
		||||
  'DESCRIPTOR' : _OFFERREVOKEMESSAGE,
 | 
			
		||||
  '__module__' : 'messages_pb2'
 | 
			
		||||
  # @@protoc_insertion_point(class_scope:basicswap.OfferRevokeMessage)
 | 
			
		||||
  })
 | 
			
		||||
_sym_db.RegisterMessage(OfferRevokeMessage)
 | 
			
		||||
 | 
			
		||||
XmrBidMessage = _reflection.GeneratedProtocolMessageType('XmrBidMessage', (_message.Message,), {
 | 
			
		||||
  'DESCRIPTOR' : _XMRBIDMESSAGE,
 | 
			
		||||
  '__module__' : 'messages_pb2'
 | 
			
		||||
 | 
			
		||||
@ -12,3 +12,10 @@ TODO:
 | 
			
		||||
 | 
			
		||||
class Peer:
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Network:
 | 
			
		||||
    def __init__(self, network_port, network_key):
 | 
			
		||||
        self._network_port = network_port
 | 
			
		||||
        self._network_key = network_key
 | 
			
		||||
        self._peers = []
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								doc/release-notes.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								doc/release-notes.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
 | 
			
		||||
0.0.6
 | 
			
		||||
==============
 | 
			
		||||
- Experimental support for XMR swaps.
 | 
			
		||||
  - Single direction only, scriptless -> XMR
 | 
			
		||||
@ -176,8 +176,8 @@ def prepareDir(datadir, nodeId, network_key, network_pubkey):
 | 
			
		||||
        'check_watched_seconds': 4,
 | 
			
		||||
        'check_expired_seconds': 60,
 | 
			
		||||
        'check_events_seconds': 1,
 | 
			
		||||
        'min_delay_auto_accept': 1,
 | 
			
		||||
        'max_delay_auto_accept': 5
 | 
			
		||||
        'min_delay_event': 1,
 | 
			
		||||
        'max_delay_event': 5
 | 
			
		||||
    }
 | 
			
		||||
    with open(settings_path, 'w') as fp:
 | 
			
		||||
        json.dump(settings, fp, indent=4)
 | 
			
		||||
 | 
			
		||||
@ -235,8 +235,10 @@ def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
 | 
			
		||||
        'check_expired_seconds': 60,
 | 
			
		||||
        'check_events_seconds': 1,
 | 
			
		||||
        'check_xmr_swaps_seconds': 1,
 | 
			
		||||
        'min_delay_auto_accept': 1,
 | 
			
		||||
        'max_delay_auto_accept': 5
 | 
			
		||||
        'min_delay_event': 1,
 | 
			
		||||
        'max_delay_event': 5,
 | 
			
		||||
        'min_delay_retry': 2,
 | 
			
		||||
        'max_delay_retry': 10
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    with open(settings_path, 'w') as fp:
 | 
			
		||||
@ -521,6 +523,22 @@ class Test(unittest.TestCase):
 | 
			
		||||
                    return
 | 
			
		||||
        raise ValueError('wait_for_offer timed out.')
 | 
			
		||||
 | 
			
		||||
    def wait_for_no_offer(self, swap_client, offer_id, wait_for=20):
 | 
			
		||||
        logging.info('wait_for_no_offer %s', offer_id.hex())
 | 
			
		||||
        for i in range(wait_for):
 | 
			
		||||
            if stop_test:
 | 
			
		||||
                raise ValueError('Test stopped.')
 | 
			
		||||
            time.sleep(1)
 | 
			
		||||
            offers = swap_client.listOffers()
 | 
			
		||||
            found_offer = False
 | 
			
		||||
            for offer in offers:
 | 
			
		||||
                if offer.offer_id == offer_id:
 | 
			
		||||
                    found_offer = True
 | 
			
		||||
                    break
 | 
			
		||||
            if not found_offer:
 | 
			
		||||
                return True
 | 
			
		||||
        raise ValueError('wait_for_offer timed out.')
 | 
			
		||||
 | 
			
		||||
    def wait_for_bid(self, swap_client, bid_id, state=None, sent=False, wait_for=20):
 | 
			
		||||
        logging.info('wait_for_bid %s', bid_id.hex())
 | 
			
		||||
        for i in range(wait_for):
 | 
			
		||||
@ -688,18 +706,39 @@ class Test(unittest.TestCase):
 | 
			
		||||
        bid1_id = swap_clients[1].postXmrBid(offer1_id, offer1.amount_from)
 | 
			
		||||
        bid2_id = swap_clients[1].postXmrBid(offer2_id, offer2.amount_from)
 | 
			
		||||
 | 
			
		||||
        offer3_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 11 * COIN, 0.15 * XMR_COIN, 11 * COIN, SwapTypes.XMR_SWAP)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid1_id, BidStates.BID_RECEIVED)
 | 
			
		||||
        swap_clients[0].acceptXmrBid(bid1_id)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_offer(swap_clients[1], offer3_id)
 | 
			
		||||
        offer3 = swap_clients[1].getOffer(offer3_id)
 | 
			
		||||
        bid3_id = swap_clients[1].postXmrBid(offer3_id, offer3.amount_from)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid2_id, BidStates.BID_RECEIVED)
 | 
			
		||||
        swap_clients[0].acceptXmrBid(bid2_id)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid3_id, BidStates.BID_RECEIVED)
 | 
			
		||||
        swap_clients[0].acceptXmrBid(bid3_id)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid1_id, BidStates.SWAP_COMPLETED, wait_for=180)
 | 
			
		||||
        self.wait_for_bid(swap_clients[1], bid1_id, BidStates.SWAP_COMPLETED, sent=True)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid2_id, BidStates.SWAP_COMPLETED, wait_for=180)
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid2_id, BidStates.SWAP_COMPLETED, wait_for=60)
 | 
			
		||||
        self.wait_for_bid(swap_clients[1], bid2_id, BidStates.SWAP_COMPLETED, sent=True)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_bid(swap_clients[0], bid3_id, BidStates.SWAP_COMPLETED, wait_for=60)
 | 
			
		||||
        self.wait_for_bid(swap_clients[1], bid3_id, BidStates.SWAP_COMPLETED, sent=True)
 | 
			
		||||
 | 
			
		||||
    def test_07_revoke_offer(self):
 | 
			
		||||
        logging.info('---------- Test offer revocaction')
 | 
			
		||||
        swap_clients = self.swap_clients
 | 
			
		||||
        offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.XMR, 10 * COIN, 100 * XMR_COIN, 10 * COIN, SwapTypes.XMR_SWAP)
 | 
			
		||||
        self.wait_for_offer(swap_clients[1], offer_id)
 | 
			
		||||
 | 
			
		||||
        swap_clients[0].revokeOffer(offer_id)
 | 
			
		||||
 | 
			
		||||
        self.wait_for_no_offer(swap_clients[1], offer_id)
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    unittest.main()
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user