particl: Can swap anon outputs
This commit is contained in:
		
							parent
							
								
									6dd6063182
								
							
						
					
					
						commit
						1ef71ea79b
					
				@ -1,3 +1,3 @@
 | 
			
		||||
name = "basicswap"
 | 
			
		||||
 | 
			
		||||
__version__ = "0.0.23"
 | 
			
		||||
__version__ = "0.0.24"
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,9 @@ from .rpc import (
 | 
			
		||||
from .util import (
 | 
			
		||||
    pubkeyToAddress,
 | 
			
		||||
)
 | 
			
		||||
from .basicswap_util import (
 | 
			
		||||
    TemporaryError,
 | 
			
		||||
)
 | 
			
		||||
from .chainparams import (
 | 
			
		||||
    Coins,
 | 
			
		||||
    chainparams,
 | 
			
		||||
@ -136,5 +139,7 @@ class BaseApp:
 | 
			
		||||
        return out[0].decode('utf-8').strip()
 | 
			
		||||
 | 
			
		||||
    def is_transient_error(self, ex):
 | 
			
		||||
        if isinstance(ex, TemporaryError):
 | 
			
		||||
            return True
 | 
			
		||||
        str_error = str(ex).lower()
 | 
			
		||||
        return 'read timed out' in str_error or 'no connection to daemon' in str_error
 | 
			
		||||
 | 
			
		||||
@ -1756,7 +1756,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                script = atomic_swap_1.buildContractScript(sequence, secret_hash, bid.pkhash_buyer, pkhash_refund)
 | 
			
		||||
            else:
 | 
			
		||||
                if offer.lock_type == ABS_LOCK_BLOCKS:
 | 
			
		||||
                    lock_value = self.callcoinrpc(coin_from, 'getblockchaininfo')['blocks'] + offer.lock_value
 | 
			
		||||
                    lock_value = self.callcoinrpc(coin_from, 'getblockcount') + offer.lock_value
 | 
			
		||||
                else:
 | 
			
		||||
                    lock_value = int(time.time()) + offer.lock_value
 | 
			
		||||
                self.log.debug('Initiate %s lock_value %d %d', coin_from, offer.lock_value, lock_value)
 | 
			
		||||
@ -2225,7 +2225,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        refund_txn = self.createRefundTxn(coin_to, txn_signed, offer, bid, participate_script, tx_type=TxTypes.PTX_REFUND)
 | 
			
		||||
        bid.participate_txn_refund = bytes.fromhex(refund_txn)
 | 
			
		||||
 | 
			
		||||
        chain_height = self.callcoinrpc(coin_to, 'getblockchaininfo')['blocks']
 | 
			
		||||
        chain_height = self.callcoinrpc(coin_to, 'getblockcount')
 | 
			
		||||
        txjs = self.callcoinrpc(coin_to, 'decoderawtransaction', [txn_signed])
 | 
			
		||||
        txid = txjs['txid']
 | 
			
		||||
 | 
			
		||||
@ -2554,7 +2554,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        return self.lookupUnspentByAddress(coin_type, address, sum_output=True)
 | 
			
		||||
 | 
			
		||||
    def lookupChainHeight(self, coin_type):
 | 
			
		||||
        return self.callcoinrpc(coin_type, 'getblockchaininfo')['blocks']
 | 
			
		||||
        return self.callcoinrpc(coin_type, 'getblockcount')
 | 
			
		||||
 | 
			
		||||
    def lookupUnspentByAddress(self, coin_type, address, sum_output=False, assert_amount=None, assert_txid=None):
 | 
			
		||||
 | 
			
		||||
@ -2589,7 +2589,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
            except Exception:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
        num_blocks = self.callcoinrpc(coin_type, 'getblockchaininfo')['blocks']
 | 
			
		||||
        num_blocks = self.callcoinrpc(coin_type, 'getblockcount')
 | 
			
		||||
 | 
			
		||||
        sum_unspent = 0
 | 
			
		||||
        self.log.debug('[rm] scantxoutset start')  # scantxoutset is slow
 | 
			
		||||
@ -2782,7 +2782,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
                bid_changed = False
 | 
			
		||||
                # Have to use findTxB instead of relying on the first seen height to detect chain reorgs
 | 
			
		||||
                found_tx = ci_to.findTxB(xmr_swap.vkbv, xmr_swap.pkbs, bid.amount_to, ci_to.blocks_confirmed, xmr_swap.b_restore_height)
 | 
			
		||||
                found_tx = ci_to.findTxB(xmr_swap.vkbv, xmr_swap.pkbs, bid.amount_to, ci_to.blocks_confirmed, xmr_swap.b_restore_height, bid.was_sent)
 | 
			
		||||
 | 
			
		||||
                if isinstance(found_tx, int) and found_tx == -1:
 | 
			
		||||
                    if self.countBidEvents(bid, EventLogTypes.LOCK_TX_B_INVALID, session) < 1:
 | 
			
		||||
@ -3249,7 +3249,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
                    spend_txn = self.callcoinrpc(Coins.PART, 'getrawtransaction', [spend_txid, True])
 | 
			
		||||
                    self.processSpentOutput(coin_type, o, spend_txid, spend_n, spend_txn)
 | 
			
		||||
        else:
 | 
			
		||||
            chain_blocks = self.callcoinrpc(coin_type, 'getblockchaininfo')['blocks']
 | 
			
		||||
            chain_blocks = self.callcoinrpc(coin_type, 'getblockcount')
 | 
			
		||||
            last_height_checked = c['last_height_checked']
 | 
			
		||||
            self.log.debug('chain_blocks, last_height_checked %s %s', chain_blocks, last_height_checked)
 | 
			
		||||
            while last_height_checked < chain_blocks:
 | 
			
		||||
@ -4288,8 +4288,11 @@ class BasicSwap(BaseApp):
 | 
			
		||||
        vkbs = ci_to.sumKeys(kbsl, kbsf)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            address_to = self.getCachedMainWalletAddress(ci_to)
 | 
			
		||||
            txid = ci_to.spendBLockTx(address_to, xmr_swap.vkbv, vkbs, bid.amount_to, xmr_offer.b_fee_rate, xmr_swap.b_restore_height)
 | 
			
		||||
            if coin_to == Coins.XMR:
 | 
			
		||||
                address_to = self.getCachedMainWalletAddress(ci_to)
 | 
			
		||||
            else:
 | 
			
		||||
                address_to = self.getCachedStealthAddressForCoin(coin_to)
 | 
			
		||||
            txid = ci_to.spendBLockTx(xmr_swap.b_lock_tx_id, address_to, xmr_swap.vkbv, vkbs, bid.amount_to, xmr_offer.b_fee_rate, xmr_swap.b_restore_height)
 | 
			
		||||
            self.log.debug('Submitted lock B spend txn %s to %s chain for bid %s', txid.hex(), ci_to.coin_name(), bid_id.hex())
 | 
			
		||||
            self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_SPEND_TX_PUBLISHED, '', session)
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
@ -4345,7 +4348,7 @@ class BasicSwap(BaseApp):
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            address_to = self.getCachedMainWalletAddress(ci_to)
 | 
			
		||||
            txid = ci_to.spendBLockTx(address_to, xmr_swap.vkbv, vkbs, bid.amount_to, xmr_offer.b_fee_rate, xmr_swap.b_restore_height)
 | 
			
		||||
            txid = ci_to.spendBLockTx(xmr_swap.b_lock_tx_id, address_to, xmr_swap.vkbv, vkbs, bid.amount_to, xmr_offer.b_fee_rate, xmr_swap.b_restore_height)
 | 
			
		||||
            self.log.debug('Submitted lock B refund txn %s to %s chain for bid %s', txid.hex(), ci_to.coin_name(), bid_id.hex())
 | 
			
		||||
            self.logBidEvent(bid.bid_id, EventLogTypes.LOCK_TX_B_REFUND_TX_PUBLISHED, '', session)
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
 | 
			
		||||
@ -371,3 +371,7 @@ def isActiveBidState(state):
 | 
			
		||||
    if state == BidStates.XMR_SWAP_SCRIPT_TX_REDEEMED:
 | 
			
		||||
        return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TemporaryError(ValueError):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
@ -175,7 +175,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        return self.rpc_callback('getblockchaininfo')
 | 
			
		||||
 | 
			
		||||
    def getChainHeight(self):
 | 
			
		||||
        return self.rpc_callback('getblockchaininfo')['blocks']
 | 
			
		||||
        return self.rpc_callback('getblockcount')
 | 
			
		||||
 | 
			
		||||
    def getMempoolTx(self, txid):
 | 
			
		||||
        return self.rpc_callback('getrawtransaction', [txid.hex()])
 | 
			
		||||
@ -866,7 +866,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
        weight = len_nwit * (wsf - 1) + len_full
 | 
			
		||||
        return (weight + wsf - 1) // wsf
 | 
			
		||||
 | 
			
		||||
    def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height):
 | 
			
		||||
    def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender):
 | 
			
		||||
        raw_dest = self.getPkDest(Kbs)
 | 
			
		||||
 | 
			
		||||
        rv = self.scanTxOutset(raw_dest)
 | 
			
		||||
@ -898,7 +898,7 @@ class BTCInterface(CoinInterface):
 | 
			
		||||
                        return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def spendBLockTx(self, address_to, kbv, kbs, cb_swap_value, b_fee, restore_height):
 | 
			
		||||
    def spendBLockTx(self, chain_b_lock_txid, address_to, kbv, kbs, cb_swap_value, b_fee, restore_height):
 | 
			
		||||
        print('TODO: spendBLockTx')
 | 
			
		||||
 | 
			
		||||
    def getOutput(self, txid, dest_script, expect_value):
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,13 @@ from .contrib.test_framework.script import (
 | 
			
		||||
    OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from .util import encodeStealthAddress
 | 
			
		||||
from .util import (
 | 
			
		||||
    encodeStealthAddress,
 | 
			
		||||
    toWIF,
 | 
			
		||||
    ensure,
 | 
			
		||||
    make_int)
 | 
			
		||||
from .basicswap_util import (
 | 
			
		||||
    TemporaryError)
 | 
			
		||||
from .chainparams import Coins, chainparams
 | 
			
		||||
from .interface_btc import BTCInterface
 | 
			
		||||
 | 
			
		||||
@ -117,8 +123,83 @@ class PARTInterfaceAnon(PARTInterface):
 | 
			
		||||
        txid = self.rpc_callback('sendtypeto', params)
 | 
			
		||||
        return bytes.fromhex(txid)
 | 
			
		||||
 | 
			
		||||
    def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height):
 | 
			
		||||
        raise ValueError('TODO - new core release')
 | 
			
		||||
    def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender):
 | 
			
		||||
        Kbv = self.getPubkey(kbv)
 | 
			
		||||
        sx_addr = self.formatStealthAddress(Kbv, Kbs)
 | 
			
		||||
        self._log.debug('sx_addr: {}'.format(sx_addr))
 | 
			
		||||
 | 
			
		||||
    def spendBLockTx(self, address_to, kbv, kbs, cb_swap_value, b_fee, restore_height):
 | 
			
		||||
        raise ValueError('TODO - new core release')
 | 
			
		||||
        # Tx recipient must import the stealth address as watch only
 | 
			
		||||
        if bid_sender:
 | 
			
		||||
            cb_swap_value *= -1
 | 
			
		||||
        else:
 | 
			
		||||
            addr_info = self.rpc_callback('getaddressinfo', [sx_addr])
 | 
			
		||||
            if not addr_info['iswatchonly']:
 | 
			
		||||
                wif_prefix = chainparams[self.coin_type()][self._network]['key_prefix']
 | 
			
		||||
                wif_scan_key = toWIF(wif_prefix, kbv)
 | 
			
		||||
                self.rpc_callback('importstealthaddress', [wif_scan_key, Kbs.hex()])
 | 
			
		||||
                self._log.info('Imported watch-only sx_addr: {}'.format(sx_addr))
 | 
			
		||||
                self._log.info('Rescanning chain from height: {}'.format(restore_height))
 | 
			
		||||
                self.rpc_callback('rescanblockchain', [restore_height])
 | 
			
		||||
 | 
			
		||||
        params = [{'include_watchonly': True, 'search': sx_addr}]
 | 
			
		||||
        txns = self.rpc_callback('filtertransactions', params)
 | 
			
		||||
 | 
			
		||||
        if len(txns) == 1:
 | 
			
		||||
            tx = txns[0]
 | 
			
		||||
            assert(tx['outputs'][0]['stealth_address'] == sx_addr)  # Should not be possible
 | 
			
		||||
            ensure(tx['outputs'][0]['type'] == 'anon', 'Output is not anon')
 | 
			
		||||
 | 
			
		||||
            if make_int(tx['outputs'][0]['amount']) == cb_swap_value:
 | 
			
		||||
                height = 0
 | 
			
		||||
                if tx['confirmations'] > 0:
 | 
			
		||||
                    chain_height = self.rpc_callback('getblockcount')
 | 
			
		||||
                    height = chain_height - (tx['confirmations'] - 1)
 | 
			
		||||
                return {'txid': tx['txid'], 'amount': cb_swap_value, 'height': height}
 | 
			
		||||
            else:
 | 
			
		||||
                self._log.warning('Incorrect amount detected for coin b lock txn: {}'.format(tx['txid']))
 | 
			
		||||
                return -1
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def spendBLockTx(self, chain_b_lock_txid, address_to, kbv, kbs, cb_swap_value, b_fee, restore_height):
 | 
			
		||||
        Kbv = self.getPubkey(kbv)
 | 
			
		||||
        Kbs = self.getPubkey(kbs)
 | 
			
		||||
        sx_addr = self.formatStealthAddress(Kbv, Kbs)
 | 
			
		||||
        addr_info = self.rpc_callback('getaddressinfo', [sx_addr])
 | 
			
		||||
        if not addr_info['ismine']:
 | 
			
		||||
            wif_prefix = chainparams[self.coin_type()][self._network]['key_prefix']
 | 
			
		||||
            wif_scan_key = toWIF(wif_prefix, kbv)
 | 
			
		||||
            wif_spend_key = toWIF(wif_prefix, kbs)
 | 
			
		||||
            self.rpc_callback('importstealthaddress', [wif_scan_key, wif_spend_key])
 | 
			
		||||
            self._log.info('Imported spend key for sx_addr: {}'.format(sx_addr))
 | 
			
		||||
            self._log.info('Rescanning chain from height: {}'.format(restore_height))
 | 
			
		||||
            self.rpc_callback('rescanblockchain', [restore_height])
 | 
			
		||||
 | 
			
		||||
        autxos = self.rpc_callback('listunspentanon')
 | 
			
		||||
        if len(autxos) < 1:
 | 
			
		||||
            raise TemporaryError('No spendable outputs')
 | 
			
		||||
        elif len(autxos) > 1:
 | 
			
		||||
            raise ValueError('Too many spendable outputs')
 | 
			
		||||
 | 
			
		||||
        utxo = autxos[0]
 | 
			
		||||
 | 
			
		||||
        inputs = [{'tx': utxo['txid'], 'n': utxo['vout']}, ]
 | 
			
		||||
        params = ['anon', 'anon',
 | 
			
		||||
                  [{'address': address_to, 'amount': self.format_amount(cb_swap_value), 'subfee': True}, ],
 | 
			
		||||
                  '', '', self._anon_tx_ring_size, 1, False,
 | 
			
		||||
                  {'conf_target': self._conf_target, 'inputs': inputs, 'show_fee': True}]
 | 
			
		||||
        rv = self.rpc_callback('sendtypeto', params)
 | 
			
		||||
        return bytes.fromhex(rv['txid'])
 | 
			
		||||
 | 
			
		||||
    def findTxnByHash(self, txid_hex):
 | 
			
		||||
        # txindex is enabled for Particl
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            rv = self.rpc_callback('getrawtransaction', [txid_hex, True])
 | 
			
		||||
        except Exception as ex:
 | 
			
		||||
            self._log.debug('findTxnByHash getrawtransaction failed: {}'.format(txid_hex))
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        if 'confirmations' in rv and rv['confirmations'] >= self.blocks_confirmed:
 | 
			
		||||
            return {'txid': txid_hex, 'amount': 0, 'height': rv['height']}
 | 
			
		||||
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,8 @@ from .util import (
 | 
			
		||||
    dumpj,
 | 
			
		||||
    make_int,
 | 
			
		||||
    format_amount)
 | 
			
		||||
from .basicswap_util import (
 | 
			
		||||
    TemporaryError)
 | 
			
		||||
from .rpc_xmr import (
 | 
			
		||||
    make_xmr_rpc_func,
 | 
			
		||||
    make_xmr_rpc2_func,
 | 
			
		||||
@ -232,7 +234,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
            return tx_hash
 | 
			
		||||
 | 
			
		||||
    def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height):
 | 
			
		||||
    def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender):
 | 
			
		||||
        with self._mx_wallet:
 | 
			
		||||
            Kbv = self.getPubkey(kbv)
 | 
			
		||||
            address_b58 = xmr_util.encode_address(Kbv, Kbs)
 | 
			
		||||
@ -363,7 +365,7 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def spendBLockTx(self, address_to, kbv, kbs, cb_swap_value, b_fee_rate, restore_height):
 | 
			
		||||
    def spendBLockTx(self, chain_b_lock_txid, address_to, kbv, kbs, cb_swap_value, b_fee_rate, restore_height):
 | 
			
		||||
        with self._mx_wallet:
 | 
			
		||||
            Kbv = self.getPubkey(kbv)
 | 
			
		||||
            Kbs = self.getPubkey(kbs)
 | 
			
		||||
@ -401,10 +403,10 @@ class XMRInterface(CoinInterface):
 | 
			
		||||
                time.sleep(1 + i)
 | 
			
		||||
            if rv['balance'] < cb_swap_value:
 | 
			
		||||
                self._log.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value))
 | 
			
		||||
                raise ValueError('Invalid balance')
 | 
			
		||||
                raise TemporaryError('Invalid balance')
 | 
			
		||||
            if rv['unlocked_balance'] < cb_swap_value:
 | 
			
		||||
                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')
 | 
			
		||||
                raise TemporaryError('Invalid unlocked_balance')
 | 
			
		||||
 | 
			
		||||
            params = {'address': address_to}
 | 
			
		||||
            if self._fee_priority > 0:
 | 
			
		||||
 | 
			
		||||
@ -246,6 +246,10 @@ def make_int(v, scale=8, r=0):  # r = 0, no rounding, fail, r > 0 round up, r <
 | 
			
		||||
    elif type(v) == int:
 | 
			
		||||
        return v * 10 ** scale
 | 
			
		||||
 | 
			
		||||
    sign = 1
 | 
			
		||||
    if v[0] == '-':
 | 
			
		||||
        v = v[1:]
 | 
			
		||||
        sign = -1
 | 
			
		||||
    ep = 10 ** scale
 | 
			
		||||
    have_dp = False
 | 
			
		||||
    rv = 0
 | 
			
		||||
@ -255,7 +259,6 @@ def make_int(v, scale=8, r=0):  # r = 0, no rounding, fail, r > 0 round up, r <
 | 
			
		||||
            have_dp = True
 | 
			
		||||
            continue
 | 
			
		||||
        if not c.isdigit():
 | 
			
		||||
 | 
			
		||||
            raise ValueError('Invalid char: ' + c)
 | 
			
		||||
        if have_dp:
 | 
			
		||||
            ep //= 10
 | 
			
		||||
@ -267,13 +270,12 @@ def make_int(v, scale=8, r=0):  # r = 0, no rounding, fail, r > 0 round up, r <
 | 
			
		||||
                    if int(c) > 4:
 | 
			
		||||
                        rv += 1
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
            rv += ep * int(c)
 | 
			
		||||
        else:
 | 
			
		||||
            rv = rv * 10 + int(c)
 | 
			
		||||
    if not have_dp:
 | 
			
		||||
        rv *= ep
 | 
			
		||||
    return rv
 | 
			
		||||
    return rv * sign
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_amount(amount, scale=8) -> bool:
 | 
			
		||||
 | 
			
		||||
@ -171,7 +171,6 @@ class Test(unittest.TestCase):
 | 
			
		||||
        cls.part_daemons = []
 | 
			
		||||
        cls.btc_daemons = []
 | 
			
		||||
 | 
			
		||||
        cls.part_stakelimit = 0
 | 
			
		||||
        cls.btc_addr = None
 | 
			
		||||
 | 
			
		||||
        logger.propagate = False
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,7 @@ from basicswap.util import (
 | 
			
		||||
    COIN,
 | 
			
		||||
    toWIF,
 | 
			
		||||
    make_int,
 | 
			
		||||
    format_amount,
 | 
			
		||||
)
 | 
			
		||||
from basicswap.rpc import (
 | 
			
		||||
    callrpc,
 | 
			
		||||
@ -279,7 +280,6 @@ class Test(unittest.TestCase):
 | 
			
		||||
        cls.xmr_daemons = []
 | 
			
		||||
        cls.xmr_wallet_auth = []
 | 
			
		||||
 | 
			
		||||
        cls.part_stakelimit = 0
 | 
			
		||||
        cls.xmr_addr = None
 | 
			
		||||
        cls.btc_addr = None
 | 
			
		||||
 | 
			
		||||
@ -395,6 +395,14 @@ class Test(unittest.TestCase):
 | 
			
		||||
                callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': num_blocks})
 | 
			
		||||
            logging.info('XMR blocks: %d', callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'])
 | 
			
		||||
 | 
			
		||||
            logging.info('Adding anon outputs')
 | 
			
		||||
            outputs = []
 | 
			
		||||
            for i in range(8):
 | 
			
		||||
                sx_addr = callnoderpc(1, 'getnewstealthaddress')
 | 
			
		||||
                outputs.append({'address': sx_addr, 'amount': 0.5})
 | 
			
		||||
            for i in range(6):
 | 
			
		||||
                callnoderpc(0, 'sendtypeto', ['part', 'anon', outputs])
 | 
			
		||||
 | 
			
		||||
            logging.info('Starting update thread.')
 | 
			
		||||
            signal.signal(signal.SIGINT, signal_handler)
 | 
			
		||||
            cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
 | 
			
		||||
@ -805,9 +813,12 @@ class Test(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
        js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
 | 
			
		||||
        assert(float(js_0['anon_balance']) == 0.0)
 | 
			
		||||
        node0_anon_before = js_0['anon_balance'] + js_0['anon_pending']
 | 
			
		||||
 | 
			
		||||
        wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/part', 'balance', 200.0)
 | 
			
		||||
        js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
 | 
			
		||||
        assert(float(js_1['balance']) > 200.0)
 | 
			
		||||
        node1_anon_before = js_1['anon_balance'] + js_1['anon_pending']
 | 
			
		||||
 | 
			
		||||
        callnoderpc(1, 'reservebalance', [True, 1000000])  # Stop staking to avoid conflicts (input used by tx->anon staked before tx gets in the chain)
 | 
			
		||||
        post_json = {
 | 
			
		||||
@ -819,17 +830,10 @@ class Test(unittest.TestCase):
 | 
			
		||||
        json_rv = json.loads(post_json_req('http://127.0.0.1:1801/json/wallets/part/withdraw', post_json))
 | 
			
		||||
        assert(len(json_rv['txid']) == 64)
 | 
			
		||||
 | 
			
		||||
        post_json['value'] = 0.5
 | 
			
		||||
        for i in range(22):
 | 
			
		||||
            json_rv = json.loads(post_json_req('http://127.0.0.1:1801/json/wallets/part/withdraw', post_json))
 | 
			
		||||
            assert(len(json_rv['txid']) == 64)
 | 
			
		||||
 | 
			
		||||
        logging.info('Waiting for anon balance')
 | 
			
		||||
        try:
 | 
			
		||||
            wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/part', 'anon_balance', 110.0)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            ft = callnoderpc(0, 'filtertransactions', [{'count': 0}])
 | 
			
		||||
            raise e
 | 
			
		||||
        wait_for_balance(test_delay_event, 'http://127.0.0.1:1801/json/wallets/part', 'anon_balance', 100.0 + node1_anon_before)
 | 
			
		||||
        js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
 | 
			
		||||
        node1_anon_before = js_1['anon_balance'] + js_1['anon_pending']
 | 
			
		||||
 | 
			
		||||
        callnoderpc(1, 'reservebalance', [False])
 | 
			
		||||
        post_json = {
 | 
			
		||||
@ -847,8 +851,6 @@ class Test(unittest.TestCase):
 | 
			
		||||
        if float(js_0['blind_balance']) >= 10.0:
 | 
			
		||||
            raise ValueError('Expect blind balance < 10')
 | 
			
		||||
 | 
			
		||||
        return  # TODO
 | 
			
		||||
 | 
			
		||||
        amt_swap = make_int(random.uniform(0.1, 2.0), scale=8, r=1)
 | 
			
		||||
        rate_swap = make_int(random.uniform(2.0, 20.0), scale=8, r=1)
 | 
			
		||||
        offer_id = swap_clients[0].postOffer(Coins.BTC, Coins.PART_ANON, amt_swap, rate_swap, amt_swap, SwapTypes.XMR_SWAP)
 | 
			
		||||
@ -862,6 +864,7 @@ class Test(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
        bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
 | 
			
		||||
        assert(xmr_swap)
 | 
			
		||||
        amount_to = float(format_amount(bid.amount_to, 8))
 | 
			
		||||
 | 
			
		||||
        swap_clients[0].acceptXmrBid(bid_id)
 | 
			
		||||
 | 
			
		||||
@ -869,7 +872,13 @@ class Test(unittest.TestCase):
 | 
			
		||||
        wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True)
 | 
			
		||||
 | 
			
		||||
        js_1 = json.loads(urlopen('http://127.0.0.1:1801/json/wallets/part').read())
 | 
			
		||||
        print('[rm] js_1', js_1)
 | 
			
		||||
        assert(js_1['anon_balance'] < node1_anon_before - amount_to)
 | 
			
		||||
 | 
			
		||||
        js_0 = json.loads(urlopen('http://127.0.0.1:1800/json/wallets/part').read())
 | 
			
		||||
        assert(js_0['anon_balance'] + js_0['anon_pending'] > node0_anon_before + (amount_to - 0.1))
 | 
			
		||||
 | 
			
		||||
    def test_12_particl_blind(self):
 | 
			
		||||
        return  # TODO
 | 
			
		||||
 | 
			
		||||
    def test_98_withdraw_all(self):
 | 
			
		||||
        logging.info('---------- Test XMR withdrawal all')
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user