Raise max signature size for fee estimate.
Fix logging. Valid sequence lock range settings. Bid debugind can be set through api.
This commit is contained in:
		
							parent
							
								
									4ea4e0656a
								
							
						
					
					
						commit
						2e0edef9da
					
				@ -1,3 +1,3 @@
 | 
			
		||||
name = "basicswap"
 | 
			
		||||
 | 
			
		||||
__version__ = "0.0.13"
 | 
			
		||||
__version__ = "0.0.14"
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,6 @@ import random
 | 
			
		||||
import shutil
 | 
			
		||||
import struct
 | 
			
		||||
import hashlib
 | 
			
		||||
import logging
 | 
			
		||||
import secrets
 | 
			
		||||
import datetime as dt
 | 
			
		||||
import traceback
 | 
			
		||||
@ -200,6 +199,7 @@ class EventLogTypes(IntEnum):
 | 
			
		||||
    LOCK_TX_A_CONFIRMED = auto()
 | 
			
		||||
    LOCK_TX_B_SEEN = auto()
 | 
			
		||||
    LOCK_TX_B_CONFIRMED = auto()
 | 
			
		||||
    DEBUG_TWEAK_APPLIED = auto()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XmrSplitMsgTypes(IntEnum):
 | 
			
		||||
@ -342,6 +342,8 @@ def describeEventEntry(event_type, event_msg):
 | 
			
		||||
        return 'Lock tx b seen in chain'
 | 
			
		||||
    if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED:
 | 
			
		||||
        return 'Lock tx b confirmed in chain'
 | 
			
		||||
    if event_type == EventLogTypes.DEBUG_TWEAK_APPLIED:
 | 
			
		||||
        return 'Debug tweak applied ' + event_msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def getExpectedSequence(lockType, lockVal, coin_type):
 | 
			
		||||
@ -445,6 +447,9 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self.min_delay_retry = self.settings.get('min_delay_retry', 60)
 | 
			
		||||
        self.max_delay_retry = self.settings.get('max_delay_retry', 5 * 60)
 | 
			
		||||
 | 
			
		||||
        self.min_sequence_lock_seconds = self.settings.get('min_sequence_lock_seconds', 1 * 60 * 60)
 | 
			
		||||
        self.max_sequence_lock_seconds = self.settings.get('max_sequence_lock_seconds', 96 * 60 * 60)
 | 
			
		||||
 | 
			
		||||
        self._bid_expired_leeway = 5
 | 
			
		||||
 | 
			
		||||
        self.swaps_in_progress = dict()
 | 
			
		||||
@ -595,15 +600,15 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
    def createInterface(self, coin):
 | 
			
		||||
        if coin == Coins.PART:
 | 
			
		||||
            return PARTInterface(self.coin_clients[coin], self.chain)
 | 
			
		||||
            return PARTInterface(self.coin_clients[coin], self.chain, self)
 | 
			
		||||
        elif coin == Coins.BTC:
 | 
			
		||||
            return BTCInterface(self.coin_clients[coin], self.chain)
 | 
			
		||||
            return BTCInterface(self.coin_clients[coin], self.chain, self)
 | 
			
		||||
        elif coin == Coins.LTC:
 | 
			
		||||
            return LTCInterface(self.coin_clients[coin], self.chain)
 | 
			
		||||
            return LTCInterface(self.coin_clients[coin], self.chain, self)
 | 
			
		||||
        elif coin == Coins.NMC:
 | 
			
		||||
            return NMCInterface(self.coin_clients[coin], self.chain)
 | 
			
		||||
            return NMCInterface(self.coin_clients[coin], self.chain, self)
 | 
			
		||||
        elif coin == Coins.XMR:
 | 
			
		||||
            xmr_i = XMRInterface(self.coin_clients[coin], self.chain)
 | 
			
		||||
            xmr_i = XMRInterface(self.coin_clients[coin], self.chain, self)
 | 
			
		||||
            chain_client_settings = self.getChainClientSettings(coin)
 | 
			
		||||
            xmr_i.setWalletFilename(chain_client_settings['walletfile'])
 | 
			
		||||
            return xmr_i
 | 
			
		||||
@ -735,6 +740,20 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self.log.info('Upgrading database from version %d to %d.', db_version, CURRENT_DB_VERSION)
 | 
			
		||||
 | 
			
		||||
        while True:
 | 
			
		||||
            if db_version == 6:
 | 
			
		||||
                session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
                session.execute('ALTER TABLE bids ADD COLUMN security_token BLOB')
 | 
			
		||||
                session.execute('ALTER TABLE offers ADD COLUMN security_token BLOB')
 | 
			
		||||
 | 
			
		||||
                db_version += 1
 | 
			
		||||
                self.db_version = db_version
 | 
			
		||||
                self.setIntKVInSession('db_version', db_version, session)
 | 
			
		||||
                session.commit()
 | 
			
		||||
                session.close()
 | 
			
		||||
                session.remove()
 | 
			
		||||
                self.log.info('Upgraded database to version {}'.format(self.db_version))
 | 
			
		||||
                continue
 | 
			
		||||
            if db_version == 4:
 | 
			
		||||
                session = scoped_session(self.session_factory)
 | 
			
		||||
 | 
			
		||||
@ -743,12 +762,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
                db_version += 1
 | 
			
		||||
                self.db_version = db_version
 | 
			
		||||
                kv = session.query(DBKVInt).filter_by(key='db_version').first()
 | 
			
		||||
                if not kv:
 | 
			
		||||
                    kv = DBKVInt(key='db_version', value=db_version)
 | 
			
		||||
                else:
 | 
			
		||||
                    kv.value = db_version
 | 
			
		||||
                session.add(kv)
 | 
			
		||||
                self.setIntKVInSession('db_version', db_version, session)
 | 
			
		||||
                session.commit()
 | 
			
		||||
                session.close()
 | 
			
		||||
                session.remove()
 | 
			
		||||
@ -804,16 +818,19 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        key_str = 'main_wallet_seedid_' + chainparams[coin_type]['name']
 | 
			
		||||
        self.setStringKV(key_str, root_hash.hex())
 | 
			
		||||
 | 
			
		||||
    def setIntKVInSession(self, str_key, int_val, session):
 | 
			
		||||
        kv = session.query(DBKVInt).filter_by(key=str_key).first()
 | 
			
		||||
        if not kv:
 | 
			
		||||
            kv = DBKVInt(key=str_key, value=int_val)
 | 
			
		||||
        else:
 | 
			
		||||
            kv.value = int_val
 | 
			
		||||
        session.add(kv)
 | 
			
		||||
 | 
			
		||||
    def setIntKV(self, str_key, int_val):
 | 
			
		||||
        self.mxDB.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
            kv = session.query(DBKVInt).filter_by(key=str_key).first()
 | 
			
		||||
            if not kv:
 | 
			
		||||
                kv = DBKVInt(key=str_key, value=int_val)
 | 
			
		||||
            else:
 | 
			
		||||
                kv.value = int_val
 | 
			
		||||
            session.add(kv)
 | 
			
		||||
            self.setIntKVInSession(str_key, int_val, session)
 | 
			
		||||
            session.commit()
 | 
			
		||||
        finally:
 | 
			
		||||
            session.close()
 | 
			
		||||
@ -1004,7 +1021,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 >= 1 * 60 * 60 and lock_value <= 96 * 60 * 60), 'Invalid lock_value time'
 | 
			
		||||
            assert(lock_value >= self.min_sequence_lock_seconds and lock_value <= self.max_sequence_lock_seconds), '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'
 | 
			
		||||
@ -1109,6 +1126,10 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
            offer_id = bytes.fromhex(msg_id)
 | 
			
		||||
 | 
			
		||||
            security_token = extra_options.get('security_token', None)
 | 
			
		||||
            if security_token is not None and len(security_token) != 20:
 | 
			
		||||
                raise ValueError('Security token must be 20 bytes long.')
 | 
			
		||||
 | 
			
		||||
            session = scoped_session(self.session_factory)
 | 
			
		||||
            offer = Offer(
 | 
			
		||||
                offer_id=offer_id,
 | 
			
		||||
@ -1128,7 +1149,8 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                created_at=offer_created_at,
 | 
			
		||||
                expire_at=offer_created_at + msg_buf.time_valid,
 | 
			
		||||
                was_sent=True,
 | 
			
		||||
                auto_accept_bids=auto_accept_bids,)
 | 
			
		||||
                auto_accept_bids=auto_accept_bids,
 | 
			
		||||
                security_token=security_token)
 | 
			
		||||
            offer.setState(OfferStates.OFFER_SENT)
 | 
			
		||||
 | 
			
		||||
            if swap_type == SwapTypes.XMR_SWAP:
 | 
			
		||||
@ -1149,7 +1171,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        self.log.info('Sent OFFER %s', offer_id.hex())
 | 
			
		||||
        return offer_id
 | 
			
		||||
 | 
			
		||||
    def revokeOffer(self, offer_id):
 | 
			
		||||
    def revokeOffer(self, offer_id, security_token=None):
 | 
			
		||||
        self.log.info('Revoking offer %s', offer_id.hex())
 | 
			
		||||
 | 
			
		||||
        session = None
 | 
			
		||||
@ -1159,6 +1181,9 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
            offer = session.query(Offer).filter_by(offer_id=offer_id).first()
 | 
			
		||||
 | 
			
		||||
            if len(offer.security_token > 0) and offer.security_token != security_token:
 | 
			
		||||
                raise ValueError('Mismatched security token')
 | 
			
		||||
 | 
			
		||||
            msg_buf = OfferRevokeMessage()
 | 
			
		||||
            msg_buf.offer_msg_id = offer_id
 | 
			
		||||
 | 
			
		||||
@ -2652,7 +2677,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                            self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
                            session.commit()
 | 
			
		||||
                        except Exception as ex:
 | 
			
		||||
                            logging.debug('Trying to publish coin a lock refund spend tx: %s', str(ex))
 | 
			
		||||
                            self.log.debug('Trying to publish coin a lock refund spend tx: %s', str(ex))
 | 
			
		||||
 | 
			
		||||
                if bid.was_sent:
 | 
			
		||||
                    if xmr_swap.a_lock_refund_swipe_tx is None:
 | 
			
		||||
@ -2672,7 +2697,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                            self.saveBidInSession(bid_id, bid, session, xmr_swap)
 | 
			
		||||
                            session.commit()
 | 
			
		||||
                        except Exception as ex:
 | 
			
		||||
                            logging.debug('Trying to publish coin a lock refund swipe tx: %s', str(ex))
 | 
			
		||||
                            self.log.debug('Trying to publish coin a lock refund swipe tx: %s', str(ex))
 | 
			
		||||
 | 
			
		||||
                if BidStates(bid.state) == BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED:
 | 
			
		||||
                    txid_hex = bid.xmr_b_lock_tx.spend_txid.hex()
 | 
			
		||||
@ -3271,9 +3296,9 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                    num_removed += 1
 | 
			
		||||
 | 
			
		||||
            if num_messages + num_removed > 0:
 | 
			
		||||
                logging.info('Expired {} / {} messages.'.format(num_removed, num_messages))
 | 
			
		||||
                self.log.info('Expired {} / {} messages.'.format(num_removed, num_messages))
 | 
			
		||||
 | 
			
		||||
            logging.debug('TODO: Expire records from db')
 | 
			
		||||
            self.log.debug('TODO: Expire records from db')
 | 
			
		||||
 | 
			
		||||
        finally:
 | 
			
		||||
            self.mxDB.release()
 | 
			
		||||
@ -3410,7 +3435,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        elif offer_data.swap_type == SwapTypes.XMR_SWAP:
 | 
			
		||||
            assert(coin_from != Coins.XMR)
 | 
			
		||||
            assert(coin_to == Coins.XMR)
 | 
			
		||||
            logging.debug('TODO - More restrictions')
 | 
			
		||||
            self.log.debug('TODO - More restrictions')
 | 
			
		||||
        else:
 | 
			
		||||
            raise ValueError('Unknown swap type {}.'.format(offer_data.swap_type))
 | 
			
		||||
 | 
			
		||||
@ -3788,7 +3813,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        ci_from = self.ci(Coins(offer.coin_from))
 | 
			
		||||
        ci_to = self.ci(Coins(offer.coin_to))
 | 
			
		||||
 | 
			
		||||
        logging.debug('TODO: xmr bid validation')
 | 
			
		||||
        self.log.debug('TODO: xmr bid validation')
 | 
			
		||||
        assert(ci_to.verifyKey(bid_data.kbvf))
 | 
			
		||||
        assert(ci_from.verifyPubkey(bid_data.pkaf))
 | 
			
		||||
 | 
			
		||||
@ -3892,7 +3917,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                xmr_swap.a_swap_refund_value, xmr_offer.a_fee_rate
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            logging.info('Checking leader\'s lock refund tx signature')
 | 
			
		||||
            self.log.info('Checking leader\'s lock refund tx signature')
 | 
			
		||||
            v = ci_from.verifyTxSig(xmr_swap.a_lock_refund_tx, xmr_swap.al_lock_refund_tx_sig, xmr_swap.pkal, 0, xmr_swap.a_lock_tx_script, bid.amount)
 | 
			
		||||
 | 
			
		||||
            bid.setState(BidStates.BID_RECEIVING_ACC)
 | 
			
		||||
@ -4056,7 +4081,9 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
        if bid.debug_ind == DebugTypes.BID_STOP_AFTER_COIN_A_LOCK:
 | 
			
		||||
            self.log.debug('XMR bid %s: Abandoning bid for testing: %d.', bid_id.hex(), bid.debug_ind)
 | 
			
		||||
            # bid.setState(BidStates.BID_ABANDONED) # TODO: Retry if state
 | 
			
		||||
            bid.setState(BidStates.BID_ABANDONED)
 | 
			
		||||
            self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
 | 
			
		||||
            self.logBidEvent(bid, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK:
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ from sqlalchemy.ext.declarative import declarative_base
 | 
			
		||||
from enum import IntEnum, auto
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CURRENT_DB_VERSION = 6
 | 
			
		||||
CURRENT_DB_VERSION = 7
 | 
			
		||||
Base = declarative_base()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -62,6 +62,7 @@ class Offer(Base):
 | 
			
		||||
    # Local fields
 | 
			
		||||
    auto_accept_bids = sa.Column(sa.Boolean)
 | 
			
		||||
    withdraw_to_addr = sa.Column(sa.String)  # Address to spend lock tx to - address from wallet if empty TODO
 | 
			
		||||
    security_token = sa.Column(sa.LargeBinary)
 | 
			
		||||
 | 
			
		||||
    state = sa.Column(sa.Integer)
 | 
			
		||||
    states = sa.Column(sa.LargeBinary)  # Packed states and times
 | 
			
		||||
@ -114,6 +115,7 @@ class Bid(Base):
 | 
			
		||||
    state_note = sa.Column(sa.String)
 | 
			
		||||
 | 
			
		||||
    debug_ind = sa.Column(sa.Integer)
 | 
			
		||||
    security_token = sa.Column(sa.LargeBinary)
 | 
			
		||||
 | 
			
		||||
    initiate_tx = None
 | 
			
		||||
    participate_tx = None
 | 
			
		||||
 | 
			
		||||
@ -393,6 +393,8 @@ class HttpHandler(BaseHTTPRequestHandler):
 | 
			
		||||
        if have_data_entry(form_data, 'lockhrs'):
 | 
			
		||||
            page_data['lockhrs'] = int(get_data_entry(form_data, 'lockhrs'))
 | 
			
		||||
            parsed_data['lock_seconds'] = page_data['lockhrs'] * 60 * 60
 | 
			
		||||
        elif have_data_entry(form_data, 'lockseconds'):
 | 
			
		||||
            parsed_data['lock_seconds'] = int(get_data_entry(form_data, 'lockseconds'))
 | 
			
		||||
 | 
			
		||||
        page_data['autoaccept'] = True if have_data_entry(form_data, 'autoaccept') else False
 | 
			
		||||
        parsed_data['autoaccept'] = page_data['autoaccept']
 | 
			
		||||
 | 
			
		||||
@ -117,14 +117,19 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
    def xmr_swap_alock_spend_tx_vsize():
 | 
			
		||||
        return 147
 | 
			
		||||
 | 
			
		||||
    def __init__(self, coin_settings, network):
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def txoType():
 | 
			
		||||
        return CTxOut
 | 
			
		||||
 | 
			
		||||
    def __init__(self, coin_settings, network, swap_client=None):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        rpc_host = coin_settings.get('rpchost', '127.0.0.1')
 | 
			
		||||
        self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host)
 | 
			
		||||
        self.txoType = CTxOut
 | 
			
		||||
        self._network = network
 | 
			
		||||
        self.blocks_confirmed = coin_settings['blocks_confirmed']
 | 
			
		||||
        self.setConfTarget(coin_settings['conf_target'])
 | 
			
		||||
        self._sc = swap_client
 | 
			
		||||
        self._log = self._sc.log if self._sc.log else logging
 | 
			
		||||
 | 
			
		||||
    def setConfTarget(self, new_conf_target):
 | 
			
		||||
        assert(new_conf_target >= 1 and new_conf_target < 33), 'Invalid conf_target value'
 | 
			
		||||
@ -153,7 +158,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
            self.rpc_callback('sethdseed', [True, key_wif])
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            # <  0.21: Cannot set a new HD seed while still in Initial Block Download.
 | 
			
		||||
            logging.error('sethdseed failed: {}'.format(str(e)))
 | 
			
		||||
            self._log.error('sethdseed failed: {}'.format(str(e)))
 | 
			
		||||
 | 
			
		||||
    def getWalletInfo(self):
 | 
			
		||||
        return self.rpc_callback('getwalletinfo')
 | 
			
		||||
@ -252,7 +257,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        script = self.genScriptLockTxScript(Kal, Kaf)
 | 
			
		||||
        tx = CTransaction()
 | 
			
		||||
        tx.nVersion = self.txVersion()
 | 
			
		||||
        tx.vout.append(self.txoType(value, self.getScriptDest(script)))
 | 
			
		||||
        tx.vout.append(self.txoType()(value, self.getScriptDest(script)))
 | 
			
		||||
 | 
			
		||||
        return tx.serialize(), script
 | 
			
		||||
 | 
			
		||||
@ -316,10 +321,10 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx = CTransaction()
 | 
			
		||||
        tx.nVersion = self.txVersion()
 | 
			
		||||
        tx.vin.append(CTxIn(COutPoint(tx_lock_hash_int, locked_n), nSequence=lock1_value))
 | 
			
		||||
        tx.vout.append(self.txoType(locked_coin, CScript([OP_0, hashlib.sha256(refund_script).digest()])))
 | 
			
		||||
        tx.vout.append(self.txoType()(locked_coin, CScript([OP_0, hashlib.sha256(refund_script).digest()])))
 | 
			
		||||
 | 
			
		||||
        witness_bytes = len(script_lock)
 | 
			
		||||
        witness_bytes += 73 * 2  # 2 signatures (72 + 1 byts size)
 | 
			
		||||
        witness_bytes += 74 * 2  # 2 signatures (72 + 1 byte sighashtype + 1 byte size) - Use maximum txn size for estimate
 | 
			
		||||
        witness_bytes += 2  # 2 empty witness stack values
 | 
			
		||||
        witness_bytes += getCompactSizeLen(witness_bytes)
 | 
			
		||||
        vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
 | 
			
		||||
@ -327,8 +332,8 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.vout[0].nValue = locked_coin - pay_fee
 | 
			
		||||
 | 
			
		||||
        tx.rehash()
 | 
			
		||||
        logging.info('createScriptLockRefundTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                     i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
        self._log.info('createScriptLockRefundTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                       i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
 | 
			
		||||
        return tx.serialize(), refund_script, tx.vout[0].nValue
 | 
			
		||||
 | 
			
		||||
@ -351,7 +356,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.nVersion = self.txVersion()
 | 
			
		||||
        tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=0))
 | 
			
		||||
 | 
			
		||||
        tx.vout.append(self.txoType(locked_coin, self.getScriptForPubkeyHash(pkh_refund_to)))
 | 
			
		||||
        tx.vout.append(self.txoType()(locked_coin, self.getScriptForPubkeyHash(pkh_refund_to)))
 | 
			
		||||
 | 
			
		||||
        witness_bytes = len(script_lock_refund)
 | 
			
		||||
        witness_bytes += 73 * 2  # 2 signatures (72 + 1 byte size)
 | 
			
		||||
@ -362,8 +367,8 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.vout[0].nValue = locked_coin - pay_fee
 | 
			
		||||
 | 
			
		||||
        tx.rehash()
 | 
			
		||||
        logging.info('createScriptLockRefundSpendTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                     i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
        self._log.info('createScriptLockRefundSpendTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                       i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
 | 
			
		||||
        return tx.serialize()
 | 
			
		||||
 | 
			
		||||
@ -386,7 +391,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.nVersion = self.txVersion()
 | 
			
		||||
        tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=lock2_value))
 | 
			
		||||
 | 
			
		||||
        tx.vout.append(self.txoType(locked_coin, self.getScriptForPubkeyHash(pkh_dest)))
 | 
			
		||||
        tx.vout.append(self.txoType()(locked_coin, self.getScriptForPubkeyHash(pkh_dest)))
 | 
			
		||||
 | 
			
		||||
        witness_bytes = len(script_lock_refund)
 | 
			
		||||
        witness_bytes += 73  # signature (72 + 1 byte size)
 | 
			
		||||
@ -397,8 +402,8 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.vout[0].nValue = locked_coin - pay_fee
 | 
			
		||||
 | 
			
		||||
        tx.rehash()
 | 
			
		||||
        logging.info('createScriptLockRefundSpendToFTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                     i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
        self._log.info('createScriptLockRefundSpendToFTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                       i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
 | 
			
		||||
        return tx.serialize()
 | 
			
		||||
 | 
			
		||||
@ -416,7 +421,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.nVersion = self.txVersion()
 | 
			
		||||
        tx.vin.append(CTxIn(COutPoint(tx_lock_hash_int, locked_n)))
 | 
			
		||||
 | 
			
		||||
        tx.vout.append(self.txoType(locked_coin, self.getScriptForPubkeyHash(pkh_dest)))
 | 
			
		||||
        tx.vout.append(self.txoType()(locked_coin, self.getScriptForPubkeyHash(pkh_dest)))
 | 
			
		||||
 | 
			
		||||
        witness_bytes = len(script_lock)
 | 
			
		||||
        witness_bytes += 33  # sv, size
 | 
			
		||||
@ -428,8 +433,8 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx.vout[0].nValue = locked_coin - pay_fee
 | 
			
		||||
 | 
			
		||||
        tx.rehash()
 | 
			
		||||
        logging.info('createScriptLockSpendTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                     i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
        self._log.info('createScriptLockSpendTx %s:\n    fee_rate, vsize, fee: %ld, %ld, %ld.',
 | 
			
		||||
                       i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
 | 
			
		||||
 | 
			
		||||
        return tx.serialize()
 | 
			
		||||
 | 
			
		||||
@ -447,7 +452,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
        tx = self.loadTx(tx_bytes)
 | 
			
		||||
        tx_hash = self.getTxHash(tx)
 | 
			
		||||
        logging.info('Verifying lock tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
        self._log.info('Verifying lock tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
 | 
			
		||||
        assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
 | 
			
		||||
        assert_cond(tx.nLockTime == 0, 'Bad nLockTime')
 | 
			
		||||
@ -491,10 +496,10 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
            vsize = self.getTxVSize(tx, add_bytes, add_witness_bytes)
 | 
			
		||||
            fee_rate_paid = fee_paid * 1000 / vsize
 | 
			
		||||
 | 
			
		||||
            logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
 | 
			
		||||
            self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
 | 
			
		||||
 | 
			
		||||
            if not self.compareFeeRates(fee_rate_paid, feerate):
 | 
			
		||||
                logging.warning('feerate paid doesn\'t match expected: %ld, %ld', fee_rate_paid, feerate)
 | 
			
		||||
                self._log.warning('feerate paid doesn\'t match expected: %ld, %ld', fee_rate_paid, feerate)
 | 
			
		||||
                # TODO: Display warning to user
 | 
			
		||||
 | 
			
		||||
        return tx_hash, locked_n
 | 
			
		||||
@ -509,7 +514,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
        tx = self.loadTx(tx_bytes)
 | 
			
		||||
        tx_hash = self.getTxHash(tx)
 | 
			
		||||
        logging.info('Verifying lock refund tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
        self._log.info('Verifying lock refund tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
 | 
			
		||||
        assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
 | 
			
		||||
        assert_cond(tx.nLockTime == 0, 'nLockTime not 0')
 | 
			
		||||
@ -543,7 +548,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
 | 
			
		||||
        fee_rate_paid = fee_paid * 1000 / vsize
 | 
			
		||||
 | 
			
		||||
        logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
 | 
			
		||||
        self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
 | 
			
		||||
 | 
			
		||||
        if not self.compareFeeRates(fee_rate_paid, feerate):
 | 
			
		||||
            raise ValueError('Bad fee rate')
 | 
			
		||||
@ -559,7 +564,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        #   Must have only one output sending lock refund tx value - fee to leader's address, TODO: follower shouldn't need to verify destination addr
 | 
			
		||||
        tx = self.loadTx(tx_bytes)
 | 
			
		||||
        tx_hash = self.getTxHash(tx)
 | 
			
		||||
        logging.info('Verifying lock refund spend tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
        self._log.info('Verifying lock refund spend tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
 | 
			
		||||
        assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
 | 
			
		||||
        assert_cond(tx.nLockTime == 0, 'nLockTime not 0')
 | 
			
		||||
@ -589,7 +594,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
 | 
			
		||||
        fee_rate_paid = fee_paid * 1000 / vsize
 | 
			
		||||
 | 
			
		||||
        logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx_value, vsize, fee_rate_paid)
 | 
			
		||||
        self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx_value, vsize, fee_rate_paid)
 | 
			
		||||
 | 
			
		||||
        if not self.compareFeeRates(fee_rate_paid, feerate):
 | 
			
		||||
            raise ValueError('Bad fee rate')
 | 
			
		||||
@ -605,7 +610,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
        tx = self.loadTx(tx_bytes)
 | 
			
		||||
        tx_hash = self.getTxHash(tx)
 | 
			
		||||
        logging.info('Verifying lock spend tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
        self._log.info('Verifying lock spend tx: {}.'.format(b2h(tx_hash)))
 | 
			
		||||
 | 
			
		||||
        assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
 | 
			
		||||
        assert_cond(tx.nLockTime == 0, 'nLockTime not 0')
 | 
			
		||||
@ -638,7 +643,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
 | 
			
		||||
        fee_rate_paid = fee_paid * 1000 / vsize
 | 
			
		||||
 | 
			
		||||
        logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx.vout[0].nValue, vsize, fee_rate_paid)
 | 
			
		||||
        self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx.vout[0].nValue, vsize, fee_rate_paid)
 | 
			
		||||
 | 
			
		||||
        if not self.compareFeeRates(fee_rate_paid, feerate):
 | 
			
		||||
            raise ValueError('Bad fee rate')
 | 
			
		||||
@ -768,7 +773,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        tx = CTransaction()
 | 
			
		||||
        tx.nVersion = self.txVersion()
 | 
			
		||||
        p2wpkh = self.getPkDest(Kbs)
 | 
			
		||||
        tx.vout.append(self.txoType(output_amount, p2wpkh))
 | 
			
		||||
        tx.vout.append(self.txoType()(output_amount, p2wpkh))
 | 
			
		||||
        return tx.serialize()
 | 
			
		||||
 | 
			
		||||
    def publishBLockTx(self, Kbv, Kbs, output_amount, feerate):
 | 
			
		||||
@ -799,7 +804,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        for utxo in rv['unspents']:
 | 
			
		||||
            if 'height' in utxo and utxo['height'] > 0 and rv['height'] - utxo['height'] > cb_block_confirmed:
 | 
			
		||||
                if self.make_int(utxo['amount']) != cb_swap_value:
 | 
			
		||||
                    logging.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount']))
 | 
			
		||||
                    self._log.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount']))
 | 
			
		||||
                else:
 | 
			
		||||
                    return {'txid': utxo['txid'], 'vout': utxo['vout'], 'amount': utxo['amount'], 'height': utxo['height']}
 | 
			
		||||
        return None
 | 
			
		||||
@ -817,7 +822,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
                if 'height' in utxo and utxo['height'] > 0 and rv['height'] - utxo['height'] > cb_block_confirmed:
 | 
			
		||||
 | 
			
		||||
                    if self.make_int(utxo['amount']) != cb_swap_value:
 | 
			
		||||
                        logging.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount']))
 | 
			
		||||
                        self._log.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount']))
 | 
			
		||||
                    else:
 | 
			
		||||
                        return True
 | 
			
		||||
        return False
 | 
			
		||||
@ -873,7 +878,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        try:
 | 
			
		||||
            pubkey = PublicKey.from_signature_and_message(signature_bytes, message_hash, hasher=None)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logging.info('verifyMessage failed: ' + str(e))
 | 
			
		||||
            self._log.info('verifyMessage failed: ' + str(e))
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        address_hash = self.decodeAddress(address)
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,6 @@ from .contrib.test_framework.script import (
 | 
			
		||||
 | 
			
		||||
from .interface_btc import BTCInterface
 | 
			
		||||
from .chainparams import Coins
 | 
			
		||||
from .rpc import make_rpc_func
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PARTInterface(BTCInterface):
 | 
			
		||||
@ -35,13 +34,9 @@ class PARTInterface(BTCInterface):
 | 
			
		||||
    def xmr_swap_alock_spend_tx_vsize():
 | 
			
		||||
        return 213
 | 
			
		||||
 | 
			
		||||
    def __init__(self, coin_settings, network):
 | 
			
		||||
        rpc_host = coin_settings.get('rpchost', '127.0.0.1')
 | 
			
		||||
        self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host)
 | 
			
		||||
        self.txoType = CTxOutPart
 | 
			
		||||
        self._network = network
 | 
			
		||||
        self.blocks_confirmed = coin_settings['blocks_confirmed']
 | 
			
		||||
        self._conf_target = coin_settings['conf_target']
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def txoType():
 | 
			
		||||
        return CTxOutPart
 | 
			
		||||
 | 
			
		||||
    def knownWalletSeed(self):
 | 
			
		||||
        # TODO: Double check
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
    def nbK():  # No. of bytes requires to encode a public key
 | 
			
		||||
        return 32
 | 
			
		||||
 | 
			
		||||
    def __init__(self, coin_settings, network):
 | 
			
		||||
    def __init__(self, coin_settings, network, swap_client=None):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        self.rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', '127.0.0.1'))
 | 
			
		||||
        self.rpc_cb2 = make_xmr_rpc2_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', '127.0.0.1'))  # non-json endpoint
 | 
			
		||||
@ -68,6 +68,8 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        self.blocks_confirmed = coin_settings['blocks_confirmed']
 | 
			
		||||
        self._restore_height = coin_settings.get('restore_height', 0)
 | 
			
		||||
        self.setFeePriority(coin_settings.get('fee_priority', 0))
 | 
			
		||||
        self._sc = swap_client
 | 
			
		||||
        self._log = self._sc.log if self._sc.log else logging
 | 
			
		||||
 | 
			
		||||
    def setFeePriority(self, new_priority):
 | 
			
		||||
        assert(new_priority >= 0 and new_priority < 4), 'Invalid fee_priority value'
 | 
			
		||||
@ -96,7 +98,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
            'restore_height': self._restore_height,
 | 
			
		||||
        }
 | 
			
		||||
        rv = self.rpc_wallet_cb('generate_from_keys', params)
 | 
			
		||||
        logging.info('generate_from_keys %s', dumpj(rv))
 | 
			
		||||
        self._log.info('generate_from_keys %s', dumpj(rv))
 | 
			
		||||
        self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
 | 
			
		||||
 | 
			
		||||
    def ensureWalletExists(self):
 | 
			
		||||
@ -137,12 +139,12 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        return self.rpc_wallet_cb('get_address')['address']
 | 
			
		||||
 | 
			
		||||
    def getNewAddress(self, placeholder):
 | 
			
		||||
        logging.warning('TODO - subaddress?')
 | 
			
		||||
        self._log.warning('TODO - subaddress?')
 | 
			
		||||
        self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
 | 
			
		||||
        return self.rpc_wallet_cb('get_address')['address']
 | 
			
		||||
 | 
			
		||||
    def get_fee_rate(self, conf_target=2):
 | 
			
		||||
        logging.warning('TODO - estimate fee rate?')
 | 
			
		||||
        self._log.warning('TODO - estimate fee rate?')
 | 
			
		||||
        return 0.0, 'unused'
 | 
			
		||||
 | 
			
		||||
    def isValidKey(self, key_bytes):
 | 
			
		||||
@ -208,14 +210,14 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        if self._fee_priority > 0:
 | 
			
		||||
            params['priority'] = self._fee_priority
 | 
			
		||||
        rv = self.rpc_wallet_cb('transfer', params)
 | 
			
		||||
        logging.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr)
 | 
			
		||||
        self._log.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr)
 | 
			
		||||
        tx_hash = bytes.fromhex(rv['tx_hash'])
 | 
			
		||||
 | 
			
		||||
        # Debug
 | 
			
		||||
        for i in range(10):
 | 
			
		||||
            params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
 | 
			
		||||
            rv = self.rpc_wallet_cb('get_transfers', params)
 | 
			
		||||
            logging.info('[rm] get_transfers {}'.format(dumpj(rv)))
 | 
			
		||||
            self._log.info('[rm] get_transfers {}'.format(dumpj(rv)))
 | 
			
		||||
            if 'pending' not in rv:
 | 
			
		||||
                break
 | 
			
		||||
            time.sleep(1)
 | 
			
		||||
@ -229,7 +231,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        try:
 | 
			
		||||
            self.rpc_wallet_cb('close_wallet')
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logging.warning('close_wallet failed %s', str(e))
 | 
			
		||||
            self._log.warning('close_wallet failed %s', str(e))
 | 
			
		||||
 | 
			
		||||
        kbv_le = kbv[::-1]
 | 
			
		||||
        params = {
 | 
			
		||||
@ -243,7 +245,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
            rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58})
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            rv = self.rpc_wallet_cb('generate_from_keys', params)
 | 
			
		||||
            logging.info('generate_from_keys %s', dumpj(rv))
 | 
			
		||||
            self._log.info('generate_from_keys %s', dumpj(rv))
 | 
			
		||||
            rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58})
 | 
			
		||||
 | 
			
		||||
        rv = self.rpc_wallet_cb('refresh', timeout=600)
 | 
			
		||||
@ -252,9 +254,9 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        # Debug
 | 
			
		||||
        try:
 | 
			
		||||
            current_height = self.rpc_wallet_cb('get_height')['height']
 | 
			
		||||
            logging.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58)
 | 
			
		||||
            self._log.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logging.info('rpc_cb failed %s', str(e))
 | 
			
		||||
            self._log.info('rpc_cb failed %s', str(e))
 | 
			
		||||
            current_height = None  # If the transfer is available it will be deep enough
 | 
			
		||||
            #   and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
 | 
			
		||||
        '''
 | 
			
		||||
@ -265,7 +267,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
                if transfer['amount'] == cb_swap_value:
 | 
			
		||||
                    return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
 | 
			
		||||
                else:
 | 
			
		||||
                    logging.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
 | 
			
		||||
                    self._log.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
 | 
			
		||||
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
@ -277,7 +279,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        try:
 | 
			
		||||
            self.rpc_wallet_cb('close_wallet')
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logging.warning('close_wallet failed %s', str(e))
 | 
			
		||||
            self._log.warning('close_wallet failed %s', str(e))
 | 
			
		||||
 | 
			
		||||
        params = {
 | 
			
		||||
            'filename': address_b58,
 | 
			
		||||
@ -296,7 +298,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
                current_height = self.rpc_cb2('get_height')['height']
 | 
			
		||||
                print('current_height', current_height)
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                logging.warning('rpc_cb failed %s', str(e))
 | 
			
		||||
                self._log.warning('rpc_cb failed %s', str(e))
 | 
			
		||||
                current_height = None  # If the transfer is available it will be deep enough
 | 
			
		||||
 | 
			
		||||
            # TODO: Make accepting current_height == None a user selectable option
 | 
			
		||||
@ -336,9 +338,9 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            current_height = self.rpc_cb2('get_height')['height']
 | 
			
		||||
            logging.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid)
 | 
			
		||||
            self._log.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logging.info('rpc_cb failed %s', str(e))
 | 
			
		||||
            self._log.info('rpc_cb failed %s', str(e))
 | 
			
		||||
            current_height = None  # If the transfer is available it will be deep enough
 | 
			
		||||
 | 
			
		||||
        params = {'transfer_type': 'available'}
 | 
			
		||||
@ -361,7 +363,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
        try:
 | 
			
		||||
            self.rpc_wallet_cb('close_wallet')
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logging.warning('close_wallet failed %s', str(e))
 | 
			
		||||
            self._log.warning('close_wallet failed %s', str(e))
 | 
			
		||||
 | 
			
		||||
        wallet_filename = address_b58 + '_spend'
 | 
			
		||||
 | 
			
		||||
@ -377,7 +379,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
            self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename})
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            rv = self.rpc_wallet_cb('generate_from_keys', params)
 | 
			
		||||
            logging.info('generate_from_keys %s', dumpj(rv))
 | 
			
		||||
            self._log.info('generate_from_keys %s', dumpj(rv))
 | 
			
		||||
            self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename})
 | 
			
		||||
 | 
			
		||||
        # For a while after opening the wallet rpc cmds return empty data
 | 
			
		||||
@ -389,10 +391,10 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
            time.sleep(1 + i)
 | 
			
		||||
        if rv['balance'] < cb_swap_value:
 | 
			
		||||
            logging.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value))
 | 
			
		||||
            self._log.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value))
 | 
			
		||||
            raise ValueError('Invalid balance')
 | 
			
		||||
        if rv['unlocked_balance'] < cb_swap_value:
 | 
			
		||||
            logging.error('wallet {} balance {}, expected {}, blocks_to_unlock {}'.format(wallet_filename, rv['unlocked_balance'], cb_swap_value, rv['blocks_to_unlock']))
 | 
			
		||||
            self._log.error('wallet {} balance {}, expected {}, blocks_to_unlock {}'.format(wallet_filename, rv['unlocked_balance'], cb_swap_value, rv['blocks_to_unlock']))
 | 
			
		||||
            raise ValueError('Invalid unlocked_balance')
 | 
			
		||||
 | 
			
		||||
        params = {'address': address_to}
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ from .ui import (
 | 
			
		||||
    describeBid,
 | 
			
		||||
    setCoinFilter,
 | 
			
		||||
    get_data_entry,
 | 
			
		||||
    have_data_entry,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -70,11 +71,11 @@ def js_offers(self, url_split, post_string, is_json, sent=False):
 | 
			
		||||
        filters['coin_from'] = setCoinFilter(post_data, 'coin_from')
 | 
			
		||||
        filters['coin_to'] = setCoinFilter(post_data, 'coin_to')
 | 
			
		||||
 | 
			
		||||
        if b'sort_by' in post_data:
 | 
			
		||||
        if have_data_entry(post_data, 'sort_by'):
 | 
			
		||||
            sort_by = get_data_entry(post_data, 'sort_by')
 | 
			
		||||
            assert(sort_by in ['created_at', 'rate']), 'Invalid sort by'
 | 
			
		||||
            filters['sort_by'] = sort_by
 | 
			
		||||
        if b'sort_dir' in post_data:
 | 
			
		||||
        if have_data_entry(post_data, 'sort_dir'):
 | 
			
		||||
            sort_dir = get_data_entry(post_data, 'sort_dir')
 | 
			
		||||
            assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir'
 | 
			
		||||
            filters['sort_dir'] = sort_dir
 | 
			
		||||
@ -113,38 +114,51 @@ def js_bids(self, url_split, post_string, is_json):
 | 
			
		||||
        if url_split[3] == 'new':
 | 
			
		||||
            if post_string == '':
 | 
			
		||||
                raise ValueError('No post data')
 | 
			
		||||
            post_data = urllib.parse.parse_qs(post_string)
 | 
			
		||||
            if is_json:
 | 
			
		||||
                post_data = json.loads(post_string)
 | 
			
		||||
                post_data['is_json'] = True
 | 
			
		||||
            else:
 | 
			
		||||
                post_data = urllib.parse.parse_qs(post_string)
 | 
			
		||||
 | 
			
		||||
            offer_id = bytes.fromhex(post_data[b'offer_id'][0].decode('utf-8'))
 | 
			
		||||
            offer_id = bytes.fromhex(get_data_entry(post_data, 'offer_id'))
 | 
			
		||||
            assert(len(offer_id) == 28)
 | 
			
		||||
 | 
			
		||||
            offer = swap_client.getOffer(offer_id)
 | 
			
		||||
            assert(offer), 'Offer not found.'
 | 
			
		||||
 | 
			
		||||
            ci_from = swap_client.ci(offer.coin_from)
 | 
			
		||||
            amount_from = inputAmount(post_data[b'amount_from'][0].decode('utf-8'), ci_from)
 | 
			
		||||
            amount_from = inputAmount(get_data_entry(post_data, 'amount_from'), ci_from)
 | 
			
		||||
 | 
			
		||||
            addr_from = None
 | 
			
		||||
            if b'addr_from' in post_data:
 | 
			
		||||
                addr_from = post_data[b'addr_from'][0].decode('utf-8')
 | 
			
		||||
            if have_data_entry(post_data, 'addr_from'):
 | 
			
		||||
                addr_from = get_data_entry(post_data, 'addr_from')
 | 
			
		||||
                if addr_from == '-1':
 | 
			
		||||
                    addr_from = None
 | 
			
		||||
 | 
			
		||||
            if offer.swap_type == SwapTypes.XMR_SWAP:
 | 
			
		||||
                bid_id = swap_client.postXmrBid(offer_id, amount_from, addr_send_from=addr_from).hex()
 | 
			
		||||
                bid_id = swap_client.postXmrBid(offer_id, amount_from, addr_send_from=addr_from)
 | 
			
		||||
            else:
 | 
			
		||||
                bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from).hex()
 | 
			
		||||
                bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from)
 | 
			
		||||
 | 
			
		||||
            rv = {'bid_id': bid_id}
 | 
			
		||||
            if have_data_entry(post_data, 'debugind'):
 | 
			
		||||
                swap_client.setBidDebugInd(bid_id, int(get_data_entry(post_data, 'debugind')))
 | 
			
		||||
 | 
			
		||||
            rv = {'bid_id': bid_id.hex()}
 | 
			
		||||
            return bytes(json.dumps(rv), 'UTF-8')
 | 
			
		||||
 | 
			
		||||
        bid_id = bytes.fromhex(url_split[3])
 | 
			
		||||
        assert(len(bid_id) == 28)
 | 
			
		||||
 | 
			
		||||
        if post_string != '':
 | 
			
		||||
            post_data = urllib.parse.parse_qs(post_string)
 | 
			
		||||
            if b'accept' in post_data:
 | 
			
		||||
            if is_json:
 | 
			
		||||
                post_data = json.loads(post_string)
 | 
			
		||||
                post_data['is_json'] = True
 | 
			
		||||
            else:
 | 
			
		||||
                post_data = urllib.parse.parse_qs(post_string)
 | 
			
		||||
            if have_data_entry(post_data, 'accept'):
 | 
			
		||||
                swap_client.acceptBid(bid_id)
 | 
			
		||||
            elif have_data_entry(post_data, 'debugind'):
 | 
			
		||||
                swap_client.setBidDebugInd(bid_id, int(get_data_entry(post_data, 'debugind')))
 | 
			
		||||
 | 
			
		||||
        bid, xmr_swap, offer, xmr_offer, events = swap_client.getXmrBidAndOffer(bid_id)
 | 
			
		||||
        assert(bid), 'Unknown bid ID'
 | 
			
		||||
 | 
			
		||||
@ -206,6 +206,7 @@ class Test(unittest.TestCase):
 | 
			
		||||
                settings['max_delay_event'] = 4
 | 
			
		||||
                settings['min_delay_retry'] = 10
 | 
			
		||||
                settings['max_delay_retry'] = 20
 | 
			
		||||
                settings['min_sequence_lock_seconds'] = 60
 | 
			
		||||
 | 
			
		||||
                settings['check_progress_seconds'] = 5
 | 
			
		||||
                settings['check_watched_seconds'] = 5
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user