Fix contract_count not inserted in db

2024-05-20_merge
tecnovert 4 years ago
parent 5d84d54e6f
commit acae8b4de3
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
  1. 2
      basicswap/__init__.py
  2. 80
      basicswap/basicswap.py
  3. 13
      basicswap/chainparams.py
  4. 4
      basicswap/config.py
  5. 51
      basicswap/contrib/rpcauth.py
  6. 18
      basicswap/interface_btc.py
  7. 12
      basicswap/interface_nmc.py
  8. 3
      basicswap/interface_part.py
  9. 28
      basicswap/interface_xmr.py
  10. 28
      basicswap/messages.proto
  11. 297
      basicswap/messages_pb2.py
  12. 9
      basicswap/rpc.py
  13. 32
      basicswap/util.py
  14. 10
      bin/basicswap_prepare.py
  15. 10
      bin/basicswap_run.py
  16. 1
      setup.py
  17. 7
      tests/basicswap/common.py
  18. 8
      tests/basicswap/test_nmc.py
  19. 25
      tests/basicswap/test_run.py
  20. 432
      tests/basicswap/test_xmr.py

@ -1,3 +1,3 @@
name = "basicswap" name = "basicswap"
__version__ = "0.0.4" __version__ = "0.0.5"

@ -22,6 +22,7 @@ from enum import IntEnum, auto
from .interface_part import PARTInterface from .interface_part import PARTInterface
from .interface_btc import BTCInterface from .interface_btc import BTCInterface
from .interface_ltc import LTCInterface from .interface_ltc import LTCInterface
from .interface_nmc import NMCInterface
from .interface_xmr import XMRInterface from .interface_xmr import XMRInterface
from . import __version__ from . import __version__
@ -29,6 +30,7 @@ from .util import (
COIN, COIN,
pubkeyToAddress, pubkeyToAddress,
format8, format8,
format_amount,
encodeAddress, encodeAddress,
decodeAddress, decodeAddress,
SerialiseNum, SerialiseNum,
@ -80,12 +82,15 @@ class MessageTypes(IntEnum):
BID = auto() BID = auto()
BID_ACCEPT = auto() BID_ACCEPT = auto()
XMR_OFFER = auto()
class SwapTypes(IntEnum): class SwapTypes(IntEnum):
SELLER_FIRST = auto() SELLER_FIRST = auto()
BUYER_FIRST = auto() BUYER_FIRST = auto()
SELLER_FIRST_2MSG = auto() SELLER_FIRST_2MSG = auto()
BUYER_FIRST_2MSG = auto() BUYER_FIRST_2MSG = auto()
XMR_SWAP = auto()
class OfferStates(IntEnum): class OfferStates(IntEnum):
@ -317,7 +322,7 @@ class BasicSwap(BaseApp):
self.network_pubkey = self.settings['network_pubkey'] self.network_pubkey = self.settings['network_pubkey']
self.network_addr = pubkeyToAddress(chainparams[Coins.PART][self.chain]['pubkey_address'], bytearray.fromhex(self.network_pubkey)) self.network_addr = pubkeyToAddress(chainparams[Coins.PART][self.chain]['pubkey_address'], bytearray.fromhex(self.network_pubkey))
self.wallet = self.settings.get('wallet', None) # TODO: Move to coin_clients #self.wallet = self.settings.get('wallet', None) # TODO: Move to coin_clients
self.sqlite_file = os.path.join(self.data_dir, 'db{}.sqlite'.format('' if self.chain == 'mainnet' else ('_' + self.chain))) self.sqlite_file = os.path.join(self.data_dir, 'db{}.sqlite'.format('' if self.chain == 'mainnet' else ('_' + self.chain)))
db_exists = os.path.exists(self.sqlite_file) db_exists = os.path.exists(self.sqlite_file)
@ -341,6 +346,20 @@ class BasicSwap(BaseApp):
self._contract_count = session.query(DBKVInt).filter_by(key='contract_count').first().value self._contract_count = session.query(DBKVInt).filter_by(key='contract_count').first().value
except Exception: except Exception:
self._contract_count = 0 self._contract_count = 0
session.add(DBKVInt(
key='contract_count',
value=self._contract_count
))
session.commit()
try:
self._offer_count = session.query(DBKVInt).filter_by(key='offer_count').first().value
except Exception:
self._offer_count = 0
session.add(DBKVInt(
key='offer_count',
value=self._offer_count
))
session.commit()
session.close() session.close()
session.remove() session.remove()
@ -426,7 +445,7 @@ class BasicSwap(BaseApp):
if coin == Coins.XMR: if coin == Coins.XMR:
self.coin_clients[coin]['walletrpcport'] = chain_client_settings.get('walletrpcport', chainparams[coin][self.chain]['walletrpcport']) self.coin_clients[coin]['walletrpcport'] = chain_client_settings.get('walletrpcport', chainparams[coin][self.chain]['walletrpcport'])
if 'walletrpcpassword' in chain_client_settings: if 'walletrpcpassword' in chain_client_settings:
self.coin_clients[coin]['walletrpcauth'] = chain_client_settings['walletrpcuser'] + ':' + chain_client_settings['walletrpcpassword'] self.coin_clients[coin]['walletrpcauth'] = (chain_client_settings['walletrpcuser'], chain_client_settings['walletrpcpassword'])
else: else:
raise ValueError('Missing XMR wallet rpc credentials.') raise ValueError('Missing XMR wallet rpc credentials.')
self.coin_clients[coin]['interface'] = self.createInterface(coin) self.coin_clients[coin]['interface'] = self.createInterface(coin)
@ -438,6 +457,8 @@ class BasicSwap(BaseApp):
return BTCInterface(self.coin_clients[coin]) return BTCInterface(self.coin_clients[coin])
elif coin == Coins.LTC: elif coin == Coins.LTC:
return LTCInterface(self.coin_clients[coin]) return LTCInterface(self.coin_clients[coin])
elif coin == Coins.NMC:
return NMCInterface(self.coin_clients[coin])
elif coin == Coins.XMR: elif coin == Coins.XMR:
return XMRInterface(self.coin_clients[coin]) return XMRInterface(self.coin_clients[coin])
else: else:
@ -445,6 +466,8 @@ class BasicSwap(BaseApp):
def setCoinRunParams(self, coin): def setCoinRunParams(self, coin):
cc = self.coin_clients[coin] cc = self.coin_clients[coin]
if coin == Coins.XMR:
return
if cc['connection_type'] == 'rpc' and cc['rpcauth'] is None: if cc['connection_type'] == 'rpc' and cc['rpcauth'] is None:
chain_client_settings = self.getChainClientSettings(coin) chain_client_settings = self.getChainClientSettings(coin)
authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie') authcookiepath = os.path.join(self.getChainDatadirPath(coin), '.cookie')
@ -474,6 +497,10 @@ class BasicSwap(BaseApp):
self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s', str(coin), authcookiepath, datadir_pid, cc['pid']) self.log.error('Unable to read authcookie for %s, %s, datadir pid %d, daemon pid %s', str(coin), authcookiepath, datadir_pid, cc['pid'])
raise ValueError('Error, terminating') raise ValueError('Error, terminating')
def createCoinInterface(self, coin):
if self.coin_clients[coin]['connection_type'] == 'rpc':
self.coin_clients[coin]['interface'] = self.createInterface(coin)
def start(self): def start(self):
self.log.info('Starting BasicSwap %s\n\n', __version__) self.log.info('Starting BasicSwap %s\n\n', __version__)
self.log.info('sqlalchemy version %s', sa.__version__) self.log.info('sqlalchemy version %s', sa.__version__)
@ -482,9 +509,11 @@ class BasicSwap(BaseApp):
for c in Coins: for c in Coins:
self.setCoinRunParams(c) self.setCoinRunParams(c)
self.createCoinInterface(c)
if self.coin_clients[c]['connection_type'] == 'rpc': if self.coin_clients[c]['connection_type'] == 'rpc':
self.waitForDaemonRPC(c) self.waitForDaemonRPC(c)
core_version = self.callcoinrpc(c, 'getnetworkinfo')['version'] core_version = self.coin_clients[c]['interface'].getDaemonVersion()
self.log.info('%s Core version %d', chainparams[c]['name'].capitalize(), core_version) self.log.info('%s Core version %d', chainparams[c]['name'].capitalize(), core_version)
self.coin_clients[c]['core_version'] = core_version self.coin_clients[c]['core_version'] = core_version
@ -540,7 +569,7 @@ class BasicSwap(BaseApp):
if not self.is_running: if not self.is_running:
return return
try: try:
self.callcoinrpc(coin_type, 'getwalletinfo', [], self.wallet) self.coin_clients[coin_type]['interface'].testDaemonRPC()
return return
except Exception as ex: except Exception as ex:
self.log.warning('Can\'t connect to %s RPC: %s. Trying again in %d second/s.', coin_type, str(ex), (1 + i)) self.log.warning('Can\'t connect to %s RPC: %s. Trying again in %d second/s.', coin_type, str(ex), (1 + i))
@ -707,10 +736,19 @@ class BasicSwap(BaseApp):
self.mxDB.acquire() self.mxDB.acquire()
try: try:
self.checkSynced(coin_from_t, coin_to_t) self.checkSynced(coin_from_t, coin_to_t)
# TODO: require proof of funds on offers?
proof_addr, proof_sig = self.getProofOfFunds(coin_from_t, amount) proof_addr, proof_sig = self.getProofOfFunds(coin_from_t, amount)
# TODO: require prrof of funds on offers? offer_addr = self.callrpc('getnewaddress') if addr_send_from is None else addr_send_from
offer_created_at = int(time.time())
if swap_type == SwapTypes.XMR_SWAP:
msg_buf = XmrOfferMessage()
key_path = "44445555h/999999/{}/{}/{}/{}".format(int(coin_from), int(coin_to), offer_created_at, )
else:
msg_buf = OfferMessage() msg_buf = OfferMessage()
msg_buf.coin_from = int(coin_from) msg_buf.coin_from = int(coin_from)
msg_buf.coin_to = int(coin_to) msg_buf.coin_to = int(coin_to)
msg_buf.amount_from = int(amount) msg_buf.amount_from = int(amount)
@ -725,10 +763,6 @@ class BasicSwap(BaseApp):
offer_bytes = msg_buf.SerializeToString() offer_bytes = msg_buf.SerializeToString()
payload_hex = str.format('{:02x}', MessageTypes.OFFER) + offer_bytes.hex() payload_hex = str.format('{:02x}', MessageTypes.OFFER) + offer_bytes.hex()
if addr_send_from is None:
offer_addr = self.callrpc('getnewaddress')
else:
offer_addr = addr_send_from
self.callrpc('smsgaddlocaladdress', [offer_addr]) # Enable receiving smsg self.callrpc('smsgaddlocaladdress', [offer_addr]) # Enable receiving smsg
options = {'decodehex': True, 'ttl_is_seconds': True} options = {'decodehex': True, 'ttl_is_seconds': True}
msg_valid = self.SMSG_SECONDS_IN_HOUR * 1 msg_valid = self.SMSG_SECONDS_IN_HOUR * 1
@ -752,8 +786,8 @@ class BasicSwap(BaseApp):
swap_type=msg_buf.swap_type, swap_type=msg_buf.swap_type,
addr_from=offer_addr, addr_from=offer_addr,
created_at=int(time.time()), created_at=offer_created_at,
expire_at=int(time.time()) + msg_buf.time_valid, expire_at=offer_created_at + msg_buf.time_valid,
was_sent=True, was_sent=True,
auto_accept_bids=auto_accept_bids,) auto_accept_bids=auto_accept_bids,)
offer.setState(OfferStates.OFFER_SENT) offer.setState(OfferStates.OFFER_SENT)
@ -850,15 +884,7 @@ class BasicSwap(BaseApp):
self.mxDB.release() self.mxDB.release()
def getReceiveAddressForCoin(self, coin_type): def getReceiveAddressForCoin(self, coin_type):
if coin_type == Coins.PART: new_addr = self.coin_clients[coin_type]['interface'].getNewAddress(self.coin_clients[coin_type]['use_segwit'])
new_addr = self.callcoinrpc(Coins.PART, 'getnewaddress')
elif coin_type == Coins.LTC or coin_type == Coins.BTC or coin_type == Coins.NMC:
args = []
if self.coin_clients[coin_type]['use_segwit']:
args = ['swap_receive', 'bech32']
new_addr = self.callcoinrpc(coin_type, 'getnewaddress', args)
else:
raise ValueError('Unknown coin type.')
self.log.debug('Generated new receive address %s for %s', new_addr, str(coin_type)) self.log.debug('Generated new receive address %s for %s', new_addr, str(coin_type))
return new_addr return new_addr
@ -2101,6 +2127,10 @@ class BasicSwap(BaseApp):
assert(len(offer_data.secret_hash) == 0), 'Unexpected data' assert(len(offer_data.secret_hash) == 0), 'Unexpected data'
elif offer_data.swap_type == SwapTypes.BUYER_FIRST: elif offer_data.swap_type == SwapTypes.BUYER_FIRST:
raise ValueError('TODO') raise ValueError('TODO')
elif offer_data.swap_type == SwapTypes.XMR_SWAP:
assert(coin_from != Coins.XMR)
assert(coin_to == Coins.XMR)
logging.debug('TODO - More restrictions')
else: else:
raise ValueError('Unknown swap type {}.'.format(offer_data.swap_type)) raise ValueError('Unknown swap type {}.'.format(offer_data.swap_type))
@ -2461,15 +2491,17 @@ class BasicSwap(BaseApp):
def getWalletInfo(self, coin): def getWalletInfo(self, coin):
blockchaininfo = self.callcoinrpc(coin, 'getblockchaininfo') blockchaininfo = self.coin_clients[coin]['interface'].getBlockchainInfo()
walletinfo = self.callcoinrpc(coin, 'getwalletinfo') walletinfo = self.coin_clients[coin]['interface'].getWalletInfo()
scale = chainparams[coin]['decimal_places']
rv = { rv = {
'version': self.coin_clients[coin]['core_version'], 'version': self.coin_clients[coin]['core_version'],
'deposit_address': self.getCachedAddressForCoin(coin), 'deposit_address': self.getCachedAddressForCoin(coin),
'name': chainparams[coin]['name'].capitalize(), 'name': chainparams[coin]['name'].capitalize(),
'blocks': blockchaininfo['blocks'], 'blocks': blockchaininfo['blocks'],
'balance': format8(make_int(walletinfo['balance'])), 'balance': format_amount(make_int(walletinfo['balance'], scale), scale),
'unconfirmed': format8(make_int(walletinfo.get('unconfirmed_balance'))), 'unconfirmed': format_amount(make_int(walletinfo.get('unconfirmed_balance'), scale), scale),
'synced': '{0:.2f}'.format(round(blockchaininfo['verificationprogress'], 2)), 'synced': '{0:.2f}'.format(round(blockchaininfo['verificationprogress'], 2)),
} }
return rv return rv

@ -9,6 +9,8 @@ from .util import (
COIN, COIN,
) )
XMR_COIN = 10 ** 12
class Coins(IntEnum): class Coins(IntEnum):
PART = 1 PART = 1
@ -25,6 +27,7 @@ chainparams = {
'ticker': 'PART', 'ticker': 'PART',
'message_magic': 'Bitcoin Signed Message:\n', 'message_magic': 'Bitcoin Signed Message:\n',
'blocks_target': 60 * 2, 'blocks_target': 60 * 2,
'decimal_places': 8,
'mainnet': { 'mainnet': {
'rpcport': 51735, 'rpcport': 51735,
'pubkey_address': 0x38, 'pubkey_address': 0x38,
@ -61,6 +64,7 @@ chainparams = {
'ticker': 'BTC', 'ticker': 'BTC',
'message_magic': 'Bitcoin Signed Message:\n', 'message_magic': 'Bitcoin Signed Message:\n',
'blocks_target': 60 * 10, 'blocks_target': 60 * 10,
'decimal_places': 8,
'mainnet': { 'mainnet': {
'rpcport': 8332, 'rpcport': 8332,
'pubkey_address': 0, 'pubkey_address': 0,
@ -95,6 +99,7 @@ chainparams = {
'ticker': 'LTC', 'ticker': 'LTC',
'message_magic': 'Litecoin Signed Message:\n', 'message_magic': 'Litecoin Signed Message:\n',
'blocks_target': 60 * 1, 'blocks_target': 60 * 1,
'decimal_places': 8,
'mainnet': { 'mainnet': {
'rpcport': 9332, 'rpcport': 9332,
'pubkey_address': 48, 'pubkey_address': 48,
@ -129,6 +134,7 @@ chainparams = {
'ticker': 'NMC', 'ticker': 'NMC',
'message_magic': 'Namecoin Signed Message:\n', 'message_magic': 'Namecoin Signed Message:\n',
'blocks_target': 60 * 10, 'blocks_target': 60 * 10,
'decimal_places': 8,
'mainnet': { 'mainnet': {
'rpcport': 8336, 'rpcport': 8336,
'pubkey_address': 52, 'pubkey_address': 52,
@ -162,17 +168,24 @@ chainparams = {
'name': 'monero', 'name': 'monero',
'ticker': 'XMR', 'ticker': 'XMR',
'client': 'xmr', 'client': 'xmr',
'decimal_places': 12,
'mainnet': { 'mainnet': {
'rpcport': 18081, 'rpcport': 18081,
'walletrpcport': 18082, 'walletrpcport': 18082,
'min_amount': 100000,
'max_amount': 10000 * XMR_COIN,
}, },
'testnet': { 'testnet': {
'rpcport': 28081, 'rpcport': 28081,
'walletrpcport': 28082, 'walletrpcport': 28082,
'min_amount': 100000,
'max_amount': 10000 * XMR_COIN,
}, },
'regtest': { 'regtest': {
'rpcport': 18081, 'rpcport': 18081,
'walletrpcport': 18082, 'walletrpcport': 18082,
'min_amount': 100000,
'max_amount': 10000 * XMR_COIN,
} }
} }
} }

@ -32,3 +32,7 @@ NAMECOIN_BINDIR = os.path.expanduser(os.getenv('NAMECOIN_BINDIR', ''))
NAMECOIND = os.getenv('NAMECOIND', 'namecoind' + bin_suffix) NAMECOIND = os.getenv('NAMECOIND', 'namecoind' + bin_suffix)
NAMECOIN_CLI = os.getenv('NAMECOIN_CLI', 'namecoin-cli' + bin_suffix) NAMECOIN_CLI = os.getenv('NAMECOIN_CLI', 'namecoin-cli' + bin_suffix)
NAMECOIN_TX = os.getenv('NAMECOIN_TX', 'namecoin-tx' + bin_suffix) NAMECOIN_TX = os.getenv('NAMECOIN_TX', 'namecoin-tx' + bin_suffix)
XMR_BINDIR = os.path.expanduser(os.getenv('XMR_BINDIR', ''))
XMRD = os.getenv('XMRD', 'monerod' + bin_suffix)
XMR_WALLET_RPC = os.getenv('XMR_WALLET_RPC', 'monero-wallet-rpc' + bin_suffix)

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from argparse import ArgumentParser
from base64 import urlsafe_b64encode
from binascii import hexlify
from getpass import getpass
from os import urandom
import hmac
def generate_salt(size):
"""Create size byte hex salt"""
return hexlify(urandom(size)).decode()
def generate_password():
"""Create 32 byte b64 password"""
return urlsafe_b64encode(urandom(32)).decode('utf-8')
def password_to_hmac(salt, password):
m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256')
return m.hexdigest()
def main():
parser = ArgumentParser(description='Create login credentials for a JSON-RPC user')
parser.add_argument('username', help='the username for authentication')
parser.add_argument('password', help='leave empty to generate a random password or specify "-" to prompt for password', nargs='?')
args = parser.parse_args()
if not args.password:
args.password = generate_password()
elif args.password == '-':
args.password = getpass()
# Create 16 byte hex salt
salt = generate_salt(16)
password_hmac = password_to_hmac(salt, args.password)
print('String to be appended to bitcoin.conf:')
print('rpcauth={0}:{1}${2}'.format(args.username, salt, password_hmac))
print('Your password:\n{0}'.format(args.password))
if __name__ == '__main__':
main()

@ -102,6 +102,24 @@ class BTCInterface(CoinInterface):
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth']) self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'])
self.txoType = CTxOut self.txoType = CTxOut
def testDaemonRPC(self):
self.rpc_callback('getwalletinfo', [])
def getDaemonVersion(self):
return self.rpc_callback('getnetworkinfo')['version']
def getBlockchainInfo(self):
return self.rpc_callback('getblockchaininfo')
def getWalletInfo(self):
return self.rpc_callback('getwalletinfo')
def getNewAddress(self, use_segwit):
args = ['swap_receive']
if use_segwit:
args.append('bech32')
return self.rpc_callback('getnewaddress', args)
def getNewSecretKey(self): def getNewSecretKey(self):
return getSecretInt() return getSecretInt()

@ -0,0 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2020 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
from .interface_btc import BTCInterface
class NMCInterface(BTCInterface):
pass

@ -26,3 +26,6 @@ class PARTInterface(BTCInterface):
def __init__(self, coin_settings): def __init__(self, coin_settings):
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth']) self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'])
self.txoType = CTxOutPart self.txoType = CTxOutPart
def getNewAddress(self, use_segwit):
return self.rpc_callback('getnewaddress', ['swap_receive'])

@ -10,6 +10,9 @@ import logging
from .chainparams import CoinInterface from .chainparams import CoinInterface
from .rpc_xmr import make_xmr_rpc_func, make_xmr_wallet_rpc_func from .rpc_xmr import make_xmr_rpc_func, make_xmr_wallet_rpc_func
from .util import (
format_amount
)
XMR_COIN = 10 ** 12 XMR_COIN = 10 ** 12
@ -31,9 +34,32 @@ class XMRInterface(CoinInterface):
rpc_cb = make_xmr_rpc_func(coin_settings['rpcport']) rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'])
rpc_wallet_cb = make_xmr_wallet_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth']) rpc_wallet_cb = make_xmr_wallet_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'])
self.rpc_cb = rpc_cb # Not essential self.rpc_cb = rpc_cb
self.rpc_wallet_cb = rpc_wallet_cb self.rpc_wallet_cb = rpc_wallet_cb
def testDaemonRPC(self):
self.rpc_wallet_cb('get_languages')
def getDaemonVersion(self):
return self.rpc_cb('get_version')['version']
def getBlockchainInfo(self):
rv = {}
rv['blocks'] = self.rpc_cb('get_block_count')['count']
rv['verificationprogress'] = 0 # TODO
return rv
def getWalletInfo(self):
rv = {}
balance_info = self.rpc_wallet_cb('get_balance')
rv['balance'] = format_amount(balance_info['unlocked_balance'], XMRInterface.exp())
rv['unconfirmed_balance'] = format_amount(balance_info['balance'] - balance_info['unlocked_balance'], XMRInterface.exp())
return rv
def getNewAddress(self, placeholder):
logging.debug('TODO - subaddress?')
return self.rpc_wallet_cb('get_address')['address']
def getNewSecretKey(self): def getNewSecretKey(self):
return edu.get_secret() return edu.get_secret()

@ -46,3 +46,31 @@ message BidAcceptMessage {
bytes initiate_txid = 2; bytes initiate_txid = 2;
bytes contract_script = 3; bytes contract_script = 3;
} }
message XmrOfferMessage {
uint32 coin_from = 1;
uint32 coin_to = 2;
uint64 amount_from = 3;
uint64 rate = 4;
uint64 min_bid_amount = 5;
uint64 time_valid = 6;
enum LockType {
NOT_SET = 0;
SEQUENCE_LOCK_BLOCKS = 1;
SEQUENCE_LOCK_TIME = 2;
ABS_LOCK_BLOCKS = 3;
ABS_LOCK_TIME = 4;
}
LockType lock_type = 7;
uint32 lock_value = 8;
uint32 swap_type = 9;
/* optional */
string proof_address = 10;
string proof_signature = 11;
bytes pkhash_seller = 12;
bytes secret_hash = 13;
}

@ -2,8 +2,6 @@
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: messages.proto # source: messages.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
@ -20,7 +18,8 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='basicswap', package='basicswap',
syntax='proto3', syntax='proto3',
serialized_options=None, serialized_options=None,
serialized_pb=_b('\n\x0emessages.proto\x12\tbasicswap\"\x84\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\"I\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\"\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\x62\x06proto3') create_key=_descriptor._internal_create_key,
serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\xac\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\"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\"\xb2\x03\n\x0fXmrOfferMessage\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\x36\n\tlock_type\x18\x07 \x01(\x0e\x32#.basicswap.XmrOfferMessage.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\"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\x62\x06proto3'
) )
@ -30,27 +29,81 @@ _OFFERMESSAGE_LOCKTYPE = _descriptor.EnumDescriptor(
full_name='basicswap.OfferMessage.LockType', full_name='basicswap.OfferMessage.LockType',
filename=None, filename=None,
file=DESCRIPTOR, file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[ values=[
_descriptor.EnumValueDescriptor( _descriptor.EnumValueDescriptor(
name='NOT_SET', index=0, number=0, name='NOT_SET', index=0, number=0,
serialized_options=None, serialized_options=None,
type=None), type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor( _descriptor.EnumValueDescriptor(
name='SEQUENCE_LOCK_BLOCKS', index=1, number=1, name='SEQUENCE_LOCK_BLOCKS', index=1, number=1,
serialized_options=None, serialized_options=None,
type=None), type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor( _descriptor.EnumValueDescriptor(
name='SEQUENCE_LOCK_TIME', index=2, number=2, name='SEQUENCE_LOCK_TIME', index=2, number=2,
serialized_options=None, serialized_options=None,
type=None), type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ABS_LOCK_BLOCKS', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ABS_LOCK_TIME', index=4, number=4,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
], ],
containing_type=None, containing_type=None,
serialized_options=None, serialized_options=None,
serialized_start=345, serialized_start=345,
serialized_end=418, serialized_end=458,
) )
_sym_db.RegisterEnumDescriptor(_OFFERMESSAGE_LOCKTYPE) _sym_db.RegisterEnumDescriptor(_OFFERMESSAGE_LOCKTYPE)
_XMROFFERMESSAGE_LOCKTYPE = _descriptor.EnumDescriptor(
name='LockType',
full_name='basicswap.XmrOfferMessage.LockType',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='NOT_SET', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SEQUENCE_LOCK_BLOCKS', index=1, number=1,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='SEQUENCE_LOCK_TIME', index=2, number=2,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ABS_LOCK_BLOCKS', index=3, number=3,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
name='ABS_LOCK_TIME', index=4, number=4,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=345,
serialized_end=458,
)
_sym_db.RegisterEnumDescriptor(_XMROFFERMESSAGE_LOCKTYPE)
_OFFERMESSAGE = _descriptor.Descriptor( _OFFERMESSAGE = _descriptor.Descriptor(
name='OfferMessage', name='OfferMessage',
@ -58,6 +111,7 @@ _OFFERMESSAGE = _descriptor.Descriptor(
filename=None, filename=None,
file=DESCRIPTOR, file=DESCRIPTOR,
containing_type=None, containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[ fields=[
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='coin_from', full_name='basicswap.OfferMessage.coin_from', index=0, name='coin_from', full_name='basicswap.OfferMessage.coin_from', index=0,
@ -65,91 +119,91 @@ _OFFERMESSAGE = _descriptor.Descriptor(
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='coin_to', full_name='basicswap.OfferMessage.coin_to', index=1, name='coin_to', full_name='basicswap.OfferMessage.coin_to', index=1,
number=2, type=13, cpp_type=3, label=1, number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='amount_from', full_name='basicswap.OfferMessage.amount_from', index=2, name='amount_from', full_name='basicswap.OfferMessage.amount_from', index=2,
number=3, type=4, cpp_type=4, label=1, number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='rate', full_name='basicswap.OfferMessage.rate', index=3, name='rate', full_name='basicswap.OfferMessage.rate', index=3,
number=4, type=4, cpp_type=4, label=1, number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='min_bid_amount', full_name='basicswap.OfferMessage.min_bid_amount', index=4, name='min_bid_amount', full_name='basicswap.OfferMessage.min_bid_amount', index=4,
number=5, type=4, cpp_type=4, label=1, number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='time_valid', full_name='basicswap.OfferMessage.time_valid', index=5, name='time_valid', full_name='basicswap.OfferMessage.time_valid', index=5,
number=6, type=4, cpp_type=4, label=1, number=6, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='lock_type', full_name='basicswap.OfferMessage.lock_type', index=6, name='lock_type', full_name='basicswap.OfferMessage.lock_type', index=6,
number=7, type=14, cpp_type=8, label=1, number=7, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='lock_value', full_name='basicswap.OfferMessage.lock_value', index=7, name='lock_value', full_name='basicswap.OfferMessage.lock_value', index=7,
number=8, type=13, cpp_type=3, label=1, number=8, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='swap_type', full_name='basicswap.OfferMessage.swap_type', index=8, name='swap_type', full_name='basicswap.OfferMessage.swap_type', index=8,
number=9, type=13, cpp_type=3, label=1, number=9, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='proof_address', full_name='basicswap.OfferMessage.proof_address', index=9, name='proof_address', full_name='basicswap.OfferMessage.proof_address', index=9,
number=10, type=9, cpp_type=9, label=1, number=10, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'), has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='proof_signature', full_name='basicswap.OfferMessage.proof_signature', index=10, name='proof_signature', full_name='basicswap.OfferMessage.proof_signature', index=10,
number=11, type=9, cpp_type=9, label=1, number=11, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'), has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='pkhash_seller', full_name='basicswap.OfferMessage.pkhash_seller', index=11, name='pkhash_seller', full_name='basicswap.OfferMessage.pkhash_seller', index=11,
number=12, type=12, cpp_type=9, label=1, number=12, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='secret_hash', full_name='basicswap.OfferMessage.secret_hash', index=12, name='secret_hash', full_name='basicswap.OfferMessage.secret_hash', index=12,
number=13, type=12, cpp_type=9, label=1, number=13, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
], ],
extensions=[ extensions=[
], ],
@ -164,7 +218,7 @@ _OFFERMESSAGE = _descriptor.Descriptor(
oneofs=[ oneofs=[
], ],
serialized_start=30, serialized_start=30,
serialized_end=418, serialized_end=458,
) )
@ -174,49 +228,50 @@ _BIDMESSAGE = _descriptor.Descriptor(
filename=None, filename=None,
file=DESCRIPTOR, file=DESCRIPTOR,
containing_type=None, containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[ fields=[
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='offer_msg_id', full_name='basicswap.BidMessage.offer_msg_id', index=0, name='offer_msg_id', full_name='basicswap.BidMessage.offer_msg_id', index=0,
number=1, type=12, cpp_type=9, label=1, number=1, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='time_valid', full_name='basicswap.BidMessage.time_valid', index=1, name='time_valid', full_name='basicswap.BidMessage.time_valid', index=1,
number=2, type=4, cpp_type=4, label=1, number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='amount', full_name='basicswap.BidMessage.amount', index=2, name='amount', full_name='basicswap.BidMessage.amount', index=2,
number=3, type=4, cpp_type=4, label=1, number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0, has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='pkhash_buyer', full_name='basicswap.BidMessage.pkhash_buyer', index=3, name='pkhash_buyer', full_name='basicswap.BidMessage.pkhash_buyer', index=3,
number=4, type=12, cpp_type=9, label=1, number=4, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='proof_address', full_name='basicswap.BidMessage.proof_address', index=4, name='proof_address', full_name='basicswap.BidMessage.proof_address', index=4,
number=5, type=9, cpp_type=9, label=1, number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'), has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='proof_signature', full_name='basicswap.BidMessage.proof_signature', index=5, name='proof_signature', full_name='basicswap.BidMessage.proof_signature', index=5,
number=6, type=9, cpp_type=9, label=1, number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'), has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
], ],
extensions=[ extensions=[
], ],
@ -229,8 +284,8 @@ _BIDMESSAGE = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=421, serialized_start=461,
serialized_end=561, serialized_end=601,
) )
@ -240,33 +295,151 @@ _BIDACCEPTMESSAGE = _descriptor.Descriptor(
filename=None, filename=None,
file=DESCRIPTOR, file=DESCRIPTOR,
containing_type=None, containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[ fields=[
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='bid_msg_id', full_name='basicswap.BidAcceptMessage.bid_msg_id', index=0, name='bid_msg_id', full_name='basicswap.BidAcceptMessage.bid_msg_id', index=0,
number=1, type=12, cpp_type=9, label=1, number=1, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='initiate_txid', full_name='basicswap.BidAcceptMessage.initiate_txid', index=1, name='initiate_txid', full_name='basicswap.BidAcceptMessage.initiate_txid', index=1,
number=2, type=12, cpp_type=9, label=1, number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor( _descriptor.FieldDescriptor(
name='contract_script', full_name='basicswap.BidAcceptMessage.contract_script', index=2, name='contract_script', full_name='basicswap.BidAcceptMessage.contract_script', index=2,
number=3, type=12, cpp_type=9, label=1, number=3, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""), 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=603,
serialized_end=689,
)
_XMROFFERMESSAGE = _descriptor.Descriptor(
name='XmrOfferMessage',
full_name='basicswap.XmrOfferMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='coin_from', full_name='basicswap.XmrOfferMessage.coin_from', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
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='coin_to', full_name='basicswap.XmrOfferMessage.coin_to', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
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='amount_from', full_name='basicswap.XmrOfferMessage.amount_from', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
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='rate', full_name='basicswap.XmrOfferMessage.rate', index=3,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
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='min_bid_amount', full_name='basicswap.XmrOfferMessage.min_bid_amount', index=4,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
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='time_valid', full_name='basicswap.XmrOfferMessage.time_valid', index=5,
number=6, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
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='lock_type', full_name='basicswap.XmrOfferMessage.lock_type', index=6,
number=7, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR), serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='lock_value', full_name='basicswap.XmrOfferMessage.lock_value', index=7,
number=8, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
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='swap_type', full_name='basicswap.XmrOfferMessage.swap_type', index=8,
number=9, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
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='proof_address', full_name='basicswap.XmrOfferMessage.proof_address', index=9,
number=10, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
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='proof_signature', full_name='basicswap.XmrOfferMessage.proof_signature', index=10,
number=11, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
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='pkhash_seller', full_name='basicswap.XmrOfferMessage.pkhash_seller', index=11,
number=12, 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='secret_hash', full_name='basicswap.XmrOfferMessage.secret_hash', index=12,
number=13, 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=[ extensions=[
], ],
nested_types=[], nested_types=[],
enum_types=[ enum_types=[
_XMROFFERMESSAGE_LOCKTYPE,
], ],
serialized_options=None, serialized_options=None,
is_extendable=False, is_extendable=False,
@ -274,37 +447,47 @@ _BIDACCEPTMESSAGE = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=563, serialized_start=692,
serialized_end=649, serialized_end=1126,
) )
_OFFERMESSAGE.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE _OFFERMESSAGE.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE
_OFFERMESSAGE_LOCKTYPE.containing_type = _OFFERMESSAGE _OFFERMESSAGE_LOCKTYPE.containing_type = _OFFERMESSAGE
_XMROFFERMESSAGE.fields_by_name['lock_type'].enum_type = _XMROFFERMESSAGE_LOCKTYPE
_XMROFFERMESSAGE_LOCKTYPE.containing_type = _XMROFFERMESSAGE
DESCRIPTOR.message_types_by_name['OfferMessage'] = _OFFERMESSAGE DESCRIPTOR.message_types_by_name['OfferMessage'] = _OFFERMESSAGE
DESCRIPTOR.message_types_by_name['BidMessage'] = _BIDMESSAGE DESCRIPTOR.message_types_by_name['BidMessage'] = _BIDMESSAGE
DESCRIPTOR.message_types_by_name['BidAcceptMessage'] = _BIDACCEPTMESSAGE DESCRIPTOR.message_types_by_name['BidAcceptMessage'] = _BIDACCEPTMESSAGE
DESCRIPTOR.message_types_by_name['XmrOfferMessage'] = _XMROFFERMESSAGE
_sym_db.RegisterFileDescriptor(DESCRIPTOR) _sym_db.RegisterFileDescriptor(DESCRIPTOR)
OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), dict( OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), {
DESCRIPTOR = _OFFERMESSAGE, 'DESCRIPTOR' : _OFFERMESSAGE,
__module__ = 'messages_pb2' '__module__' : 'messages_pb2'
# @@protoc_insertion_point(class_scope:basicswap.OfferMessage) # @@protoc_insertion_point(class_scope:basicswap.OfferMessage)
)) })
_sym_db.RegisterMessage(OfferMessage) _sym_db.RegisterMessage(OfferMessage)
BidMessage = _reflection.GeneratedProtocolMessageType('BidMessage', (_message.Message,), dict( BidMessage = _reflection.GeneratedProtocolMessageType('BidMessage', (_message.Message,), {
DESCRIPTOR = _BIDMESSAGE, 'DESCRIPTOR' : _BIDMESSAGE,
__module__ = 'messages_pb2' '__module__' : 'messages_pb2'
# @@protoc_insertion_point(class_scope:basicswap.BidMessage) # @@protoc_insertion_point(class_scope:basicswap.BidMessage)
)) })
_sym_db.RegisterMessage(BidMessage) _sym_db.RegisterMessage(BidMessage)
BidAcceptMessage = _reflection.GeneratedProtocolMessageType('BidAcceptMessage', (_message.Message,), dict( BidAcceptMessage = _reflection.GeneratedProtocolMessageType('BidAcceptMessage', (_message.Message,), {
DESCRIPTOR = _BIDACCEPTMESSAGE, 'DESCRIPTOR' : _BIDACCEPTMESSAGE,
__module__ = 'messages_pb2' '__module__' : 'messages_pb2'
# @@protoc_insertion_point(class_scope:basicswap.BidAcceptMessage) # @@protoc_insertion_point(class_scope:basicswap.BidAcceptMessage)
)) })
_sym_db.RegisterMessage(BidAcceptMessage) _sym_db.RegisterMessage(BidAcceptMessage)
XmrOfferMessage = _reflection.GeneratedProtocolMessageType('XmrOfferMessage', (_message.Message,), {
'DESCRIPTOR' : _XMROFFERMESSAGE,
'__module__' : 'messages_pb2'
# @@protoc_insertion_point(class_scope:basicswap.XmrOfferMessage)
})
_sym_db.RegisterMessage(XmrOfferMessage)
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

@ -18,14 +18,15 @@ from xmlrpc.client import (
from .util import jsonDecimal from .util import jsonDecimal
def waitForRPC(rpc_func, wallet=None): def waitForRPC(rpc_func, wallet=None, max_tries=7):
for i in range(5): for i in range(max_tries + 1):
try: try:
rpc_func('getwalletinfo') rpc_func('getwalletinfo')
return return
except Exception as ex: except Exception as ex:
logging.warning('Can\'t connect to daemon RPC: %s. Trying again in %d second/s.', str(ex), (1 + i)) if i < max_tries:
time.sleep(1 + i) logging.warning('Can\'t connect to RPC: %s. Retrying in %d second/s.', str(ex), (i + 1))
time.sleep(i + 1)
raise ValueError('waitForRPC failed') raise ValueError('waitForRPC failed')

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2018-2019 tecnovert # Copyright (c) 2018-2020 tecnovert
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php. # file LICENSE or http://www.opensource.org/licenses/mit-license.php.
import decimal
import json import json
import hashlib import hashlib
from .contrib.segwit_addr import bech32_decode, convertbits, bech32_encode from .contrib.segwit_addr import bech32_decode, convertbits, bech32_encode
@ -12,7 +11,6 @@ from .contrib.segwit_addr import bech32_decode, convertbits, bech32_encode
OP_1 = 0x51 OP_1 = 0x51
OP_16 = 0x60 OP_16 = 0x60
COIN = 100000000 COIN = 100000000
DCOIN = decimal.Decimal(COIN)
def assert_cond(v, err='Bad opcode'): def assert_cond(v, err='Bad opcode'):
@ -34,10 +32,6 @@ def toBool(s):
return s.lower() in ["1", "true"] return s.lower() in ["1", "true"]
def dquantize(n, places=8):
return n.quantize(decimal.Decimal(10) ** -places)
def jsonDecimal(obj): def jsonDecimal(obj):
if isinstance(obj, decimal.Decimal): if isinstance(obj, decimal.Decimal):
return str(obj) return str(obj)
@ -229,13 +223,13 @@ def getCompactSizeLen(v):
raise ValueError('Value too large') raise ValueError('Value too large')
def make_int(v, precision=8, r=0): # r = 0, no rounding, fail, r > 0 round up, r < 0 floor def make_int(v, scale=8, r=0): # r = 0, no rounding, fail, r > 0 round up, r < 0 floor
if type(v) == float: if type(v) == float:
v = str(v) v = str(v)
elif type(v) == int: elif type(v) == int:
return v * 10 ** precision return v * 10 ** scale
ep = 10 ** precision ep = 10 ** scale
have_dp = False have_dp = False
rv = 0 rv = 0
for c in v: for c in v:
@ -264,7 +258,7 @@ def make_int(v, precision=8, r=0): # r = 0, no rounding, fail, r > 0 round up,
return rv return rv
def validate_amount(amount, precision=8): def validate_amount(amount, scale=8):
str_amount = str(amount) str_amount = str(amount)
has_decimal = False has_decimal = False
for c in str_amount: for c in str_amount:
@ -275,21 +269,21 @@ def validate_amount(amount, precision=8):
raise ValueError('Invalid amount') raise ValueError('Invalid amount')
ar = str_amount.split('.') ar = str_amount.split('.')
if len(ar) > 1 and len(ar[1]) > precision: if len(ar) > 1 and len(ar[1]) > scale:
raise ValueError('Too many decimal places in amount {}'.format(str_amount)) raise ValueError('Too many decimal places in amount {}'.format(str_amount))
return True return True
def format_amount(i, display_precision, precision=None): def format_amount(i, display_scale, scale=None):
if precision is None: if scale is None:
precision = display_precision scale = display_scale
ep = 10 ** precision ep = 10 ** scale
n = abs(i) n = abs(i)
quotient = n // ep quotient = n // ep
remainder = n % ep remainder = n % ep
if display_precision != precision: if display_scale != scale:
remainder %= (10 ** display_precision) remainder %= (10 ** display_scale)
rv = '{}.{:0>{prec}}'.format(quotient, remainder, prec=display_precision) rv = '{}.{:0>{prec}}'.format(quotient, remainder, prec=display_scale)
if i < 0: if i < 0:
rv = '-' + rv rv = '-' + rv
return rv return rv

@ -46,6 +46,7 @@ known_coins = {
'litecoin': '0.18.1', 'litecoin': '0.18.1',
'bitcoin': '0.20.1', 'bitcoin': '0.20.1',
'namecoin': '0.18.0', 'namecoin': '0.18.0',
'monero': '0.17.0.1',
} }
logger = logging.getLogger() logger = logging.getLogger()
@ -124,6 +125,15 @@ def prepareCore(coin, version, settings, data_dir):
os_dir_name = 'linux' os_dir_name = 'linux'
os_name = 'linux' os_name = 'linux'
if coin == 'monero':
url = 'https://downloads.getmonero.org/cli/monero-linux-x64-v${}.tar.bz2'.format(version)
release_path = os.path.join(bin_dir, release_filename)
if not os.path.exists(release_path):
downloadFile(release_url, release_path)
raise ValueError('TODO')
release_filename = '{}-{}-{}'.format(coin, version, BIN_ARCH) release_filename = '{}-{}-{}'.format(coin, version, BIN_ARCH)
if coin == 'particl': if coin == 'particl':
signing_key_name = 'tecnovert' signing_key_name = 'tecnovert'

@ -45,7 +45,7 @@ def startDaemon(node_dir, bin_dir, daemon_bin, opts=[]):
daemon_bin = os.path.expanduser(os.path.join(bin_dir, daemon_bin)) daemon_bin = os.path.expanduser(os.path.join(bin_dir, daemon_bin))
args = [daemon_bin, '-datadir=' + os.path.expanduser(node_dir)] + opts args = [daemon_bin, '-datadir=' + os.path.expanduser(node_dir)] + opts
logger.info('Starting node ' + daemon_bin + ' ' + '-datadir=' + node_dir) logging.info('Starting node ' + daemon_bin + ' ' + '-datadir=' + node_dir)
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -118,9 +118,13 @@ def runClient(fp, data_dir, chain):
closed_pids = [] closed_pids = []
for d in daemons: for d in daemons:
int_pid = d.pid int_pid = d.pid
logger.info('Terminating {}'.format(int_pid)) logging.info('Interrupting {}'.format(int_pid))
try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in daemons:
try: try:
d.terminate()
d.wait(timeout=120) d.wait(timeout=120)
if d.stdout: if d.stdout:
d.stdout.close() d.stdout.close()

@ -24,6 +24,7 @@ setuptools.setup(
"Operating System :: Linux", "Operating System :: Linux",
], ],
install_requires=[ install_requires=[
"wheel",
"pyzmq", "pyzmq",
"protobuf", "protobuf",
"sqlalchemy", "sqlalchemy",

@ -5,6 +5,13 @@
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. # file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php.
import os
TEST_HTTP_HOST = os.getenv('TEST_HTTP_HOST', '127.0.0.1') # Set to 0.0.0.0 when used in docker
TEST_HTTP_PORT = 1800
def checkForks(ro): def checkForks(ro):
if 'bip9_softforks' in ro: if 'bip9_softforks' in ro:
assert(ro['bip9_softforks']['csv']['status'] == 'active') assert(ro['bip9_softforks']['csv']['status'] == 'active')

@ -44,6 +44,10 @@ from basicswap.contrib.key import (
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.common import (
TEST_HTTP_HOST,
TEST_HTTP_PORT,
)
from bin.basicswap_run import startDaemon from bin.basicswap_run import startDaemon
import basicswap.config as cfg import basicswap.config as cfg
@ -58,7 +62,6 @@ BASE_PORT = 14792
BASE_RPC_PORT = 19792 BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792 BASE_ZMQ_PORT = 20792
PREFIX_SECRET_KEY_REGTEST = 0x2e PREFIX_SECRET_KEY_REGTEST = 0x2e
TEST_HTML_PORT = 1800
NMC_NODE = 3 NMC_NODE = 3
BTC_NODE = 4 BTC_NODE = 4
stop_test = False stop_test = False
@ -278,9 +281,8 @@ class Test(unittest.TestCase):
print('nmcRpc', ro) print('nmcRpc', ro)
cls.http_threads = [] cls.http_threads = []
host = '0.0.0.0' # All interfaces (docker)
for i in range(3): for i in range(3):
t = HttpThread(cls.swap_clients[i].fp, host, TEST_HTML_PORT + i, False, cls.swap_clients[i]) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t) cls.http_threads.append(t)
t.start() t.start()

@ -50,6 +50,8 @@ from basicswap.http_server import (
) )
from tests.basicswap.common import ( from tests.basicswap.common import (
checkForks, checkForks,
TEST_HTTP_HOST,
TEST_HTTP_PORT,
) )
from bin.basicswap_run import startDaemon from bin.basicswap_run import startDaemon
@ -63,7 +65,6 @@ BASE_PORT = 14792
BASE_RPC_PORT = 19792 BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792 BASE_ZMQ_PORT = 20792
PREFIX_SECRET_KEY_REGTEST = 0x2e PREFIX_SECRET_KEY_REGTEST = 0x2e
TEST_HTML_PORT = 1800
LTC_NODE = 3 LTC_NODE = 3
BTC_NODE = 4 BTC_NODE = 4
stop_test = False stop_test = False
@ -247,11 +248,12 @@ class Test(unittest.TestCase):
with open(settings_path) as fs: with open(settings_path) as fs:
settings = json.load(fs) settings = json.load(fs)
fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w') fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w')
cls.swap_clients.append(BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i))) sc = BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i))
cls.swap_clients[-1].setDaemonPID(Coins.BTC, cls.daemons[0].pid) sc.setDaemonPID(Coins.BTC, cls.daemons[0].pid)
cls.swap_clients[-1].setDaemonPID(Coins.LTC, cls.daemons[1].pid) sc.setDaemonPID(Coins.LTC, cls.daemons[1].pid)
cls.swap_clients[-1].setDaemonPID(Coins.PART, cls.daemons[2 + i].pid) sc.setDaemonPID(Coins.PART, cls.daemons[2 + i].pid)
cls.swap_clients[-1].start() sc.start()
cls.swap_clients.append(sc)
cls.swap_clients[0].callrpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb']) cls.swap_clients[0].callrpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
cls.swap_clients[1].callrpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true']) cls.swap_clients[1].callrpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest']) cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest'])
@ -278,9 +280,8 @@ class Test(unittest.TestCase):
print('ltcRpc', ro) print('ltcRpc', ro)
cls.http_threads = [] cls.http_threads = []
host = '0.0.0.0' # All interfaces (docker)
for i in range(3): for i in range(3):
t = HttpThread(cls.swap_clients[i].fp, host, TEST_HTML_PORT + i, False, cls.swap_clients[i]) t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t) cls.http_threads.append(t)
t.start() t.start()
@ -300,8 +301,12 @@ class Test(unittest.TestCase):
for c in cls.swap_clients: for c in cls.swap_clients:
c.fp.close() c.fp.close()
for d in cls.daemons: for d in cls.daemons:
logging.info('Terminating %d', d.pid) logging.info('Interrupting %d', d.pid)
d.terminate() try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in cls.daemons:
d.wait(timeout=10) d.wait(timeout=10)
if d.stdout: if d.stdout:
d.stdout.close() d.stdout.close()

@ -7,13 +7,15 @@
import os import os
import sys import sys
import unittest
import json import json
import logging
import shutil
import time import time
import shutil
import signal import signal
import logging
import unittest
import traceback
import threading import threading
import subprocess
from urllib.request import urlopen from urllib.request import urlopen
from coincurve.ecdsaotves import ( from coincurve.ecdsaotves import (
ecdsaotves_enc_sign, ecdsaotves_enc_sign,
@ -37,71 +39,100 @@ from basicswap.util import (
COIN, COIN,
toWIF, toWIF,
dumpje, dumpje,
make_int,
) )
from basicswap.rpc import ( from basicswap.rpc import (
callrpc,
callrpc_cli, callrpc_cli,
waitForRPC, waitForRPC,
) )
from basicswap.rpc_xmr import (
callrpc_xmr_na,
callrpc_xmr,
)
from basicswap.interface_xmr import (
XMR_COIN,
)
from basicswap.contrib.key import ( from basicswap.contrib.key import (
ECKey, ECKey,
) )
from basicswap.http_server import ( from basicswap.http_server import (
HttpThread, HttpThread,
) )
from tests.basicswap.common import (
checkForks,
TEST_HTTP_HOST,
TEST_HTTP_PORT,
)
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
from bin.basicswap_run import startDaemon from bin.basicswap_run import startDaemon
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG
if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout))
NUM_NODES = 3 NUM_NODES = 3
NUM_XMR_NODES = 3
NUM_BTC_NODES = 3
TEST_DIR = cfg.TEST_DATADIRS
BASE_PORT = 14792 BASE_PORT = 14792
BASE_RPC_PORT = 19792 BASE_RPC_PORT = 19792
BASE_ZMQ_PORT = 20792 BASE_ZMQ_PORT = 20792
BTC_BASE_PORT = 114792
BTC_BASE_RPC_PORT = 119792
BTC_BASE_ZMQ_PORT = 120792
XMR_BASE_P2P_PORT = 17792
XMR_BASE_RPC_PORT = 21792
XMR_BASE_ZMQ_PORT = 22792
XMR_BASE_WALLET_RPC_PORT = 23792
PREFIX_SECRET_KEY_REGTEST = 0x2e PREFIX_SECRET_KEY_REGTEST = 0x2e
TEST_HTML_PORT = 1800
stop_test = False stop_test = False
def prepareXmrDataDir(datadir, node_id, conf_file):
def prepareOtherDir(datadir, nodeId, conf_file='litecoin.conf'): node_dir = os.path.join(datadir, 'xmr_' + str(node_id))
node_dir = os.path.join(datadir, str(nodeId))
if not os.path.exists(node_dir): if not os.path.exists(node_dir):
os.makedirs(node_dir) os.makedirs(node_dir)
filePath = os.path.join(node_dir, conf_file) cfg_file_path = os.path.join(node_dir, conf_file)
if os.path.exists(cfg_file_path):
with open(filePath, 'w+') as fp: return
with open(cfg_file_path, 'w+') as fp:
fp.write('regtest=1\n') fp.write('regtest=1\n')
fp.write('[regtest]\n') fp.write('keep-fakechain=1\n')
fp.write('port=' + str(BASE_PORT + nodeId) + '\n') fp.write('data-dir={}\n'.format(node_dir))
fp.write('rpcport=' + str(BASE_RPC_PORT + nodeId) + '\n') fp.write('fixed-difficulty=1\n')
# fp.write('offline=1\n')
fp.write('daemon=0\n') fp.write('p2p-bind-port={}\n'.format(XMR_BASE_P2P_PORT + node_id))
fp.write('printtoconsole=0\n') fp.write('rpc-bind-port={}\n'.format(XMR_BASE_RPC_PORT + node_id))
fp.write('server=1\n') fp.write('p2p-bind-ip=127.0.0.1\n')
fp.write('discover=0\n') fp.write('rpc-bind-ip=127.0.0.1\n')
fp.write('listenonion=0\n')
fp.write('bind=127.0.0.1\n') fp.write('zmq-rpc-bind-port={}\n'.format(XMR_BASE_ZMQ_PORT + node_id))
fp.write('findpeers=0\n') fp.write('zmq-rpc-bind-ip=127.0.0.1\n')
fp.write('debug=1\n')
fp.write('debugexclude=libevent\n') for i in range(0, NUM_XMR_NODES):
fp.write('fallbackfee=0.0002\n') if node_id == i:
continue
fp.write('acceptnonstdtxn=0\n') fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + i))
def prepareDir(datadir, nodeId, network_key, network_pubkey): def prepareDataDir(datadir, node_id, conf_file, dir_prefix, base_p2p_port=BASE_PORT, base_rpc_port=BASE_RPC_PORT):
node_dir = os.path.join(datadir, str(nodeId)) node_dir = os.path.join(datadir, dir_prefix + str(node_id))
if not os.path.exists(node_dir): if not os.path.exists(node_dir):
os.makedirs(node_dir) os.makedirs(node_dir)
filePath = os.path.join(node_dir, 'particl.conf') cfg_file_path = os.path.join(node_dir, conf_file)
if os.path.exists(cfg_file_path):
with open(filePath, 'w+') as fp: return
with open(cfg_file_path, 'w+') as fp:
fp.write('regtest=1\n') fp.write('regtest=1\n')
fp.write('[regtest]\n') fp.write('[regtest]\n')
fp.write('port=' + str(BASE_PORT + nodeId) + '\n') fp.write('port=' + str(base_p2p_port + node_id) + '\n')
fp.write('rpcport=' + str(BASE_RPC_PORT + nodeId) + '\n') fp.write('rpcport=' + str(base_rpc_port + node_id) + '\n')
salt = generate_salt(16)
fp.write('rpcauth={}:{}${}\n'.format('test' + str(node_id), salt, password_to_hmac(salt, 'test_pass' + str(node_id))))
fp.write('daemon=0\n') fp.write('daemon=0\n')
fp.write('printtoconsole=0\n') fp.write('printtoconsole=0\n')
@ -109,62 +140,100 @@ def prepareDir(datadir, nodeId, network_key, network_pubkey):
fp.write('discover=0\n') fp.write('discover=0\n')
fp.write('listenonion=0\n') fp.write('listenonion=0\n')
fp.write('bind=127.0.0.1\n') fp.write('bind=127.0.0.1\n')
fp.write('findpeers=0\n')
fp.write('debug=1\n') fp.write('debug=1\n')
fp.write('debugexclude=libevent\n') fp.write('debugexclude=libevent\n')
fp.write('zmqpubsmsg=tcp://127.0.0.1:' + str(BASE_ZMQ_PORT + nodeId) + '\n')
fp.write('fallbackfee=0.01\n')
fp.write('acceptnonstdtxn=0\n') fp.write('acceptnonstdtxn=0\n')
fp.write('minstakeinterval=5\n') fp.write('txindex=1\n')
fp.write('findpeers=0\n')
# minstakeinterval=5 # Using walletsettings stakelimit instead
if base_p2p_port == BASE_PORT: # Particl
fp.write('zmqpubsmsg=tcp://127.0.0.1:{}\n'.format(BASE_ZMQ_PORT + node_id))
for i in range(0, NUM_NODES): for i in range(0, NUM_NODES):
if nodeId == i: if node_id == i:
continue continue
fp.write('addnode=127.0.0.1:%d\n' % (BASE_PORT + i)) fp.write('addnode=127.0.0.1:{}\n'.format(base_p2p_port + i))
if nodeId < 2:
fp.write('spentindex=1\n')
fp.write('txindex=1\n')
basicswap_dir = os.path.join(datadir, str(nodeId), 'basicswap') def startXmrDaemon(node_dir, bin_dir, daemon_bin, opts=[]):
daemon_bin = os.path.expanduser(os.path.join(bin_dir, daemon_bin))
args = [daemon_bin, '--config-file=' + os.path.join(os.path.expanduser(node_dir), 'monerod.conf')] + opts
logging.info('Starting node {} --data-dir={}'.format(daemon_bin, node_dir))
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def startXmrWalletRPC(node_dir, bin_dir, wallet_bin, node_id, opts=[]):
daemon_bin = os.path.expanduser(os.path.join(bin_dir, wallet_bin))
data_dir = os.path.expanduser(node_dir)
args = [daemon_bin]
args += ['--daemon-address=localhost:{}'.format(XMR_BASE_RPC_PORT + node_id)]
args += ['--no-dns']
args += ['--rpc-bind-port={}'.format(XMR_BASE_WALLET_RPC_PORT + node_id)]
args += ['--wallet-dir={}'.format(os.path.join(data_dir, 'wallets'))]
args += ['--log-file={}'.format(os.path.join(data_dir, 'wallet.log'))]
args += ['--rpc-login=test{0}:test_pass{0}'.format(node_id)]
args += ['--shared-ringdb-dir={}'.format(os.path.join(data_dir, 'shared-ringdb'))]
args += opts
logging.info('Starting daemon {} --wallet-dir={}'.format(daemon_bin, node_dir))
wallet_stdout = open(os.path.join(data_dir, 'wallet_stdout.log'), 'w')
wallet_stderr = open(os.path.join(data_dir, 'wallet_stderr.log'), 'w')
return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=wallet_stdout, stderr=wallet_stderr, cwd=data_dir)
def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
basicswap_dir = os.path.join(datadir, 'basicswap_' + str(node_id))
if not os.path.exists(basicswap_dir): if not os.path.exists(basicswap_dir):
os.makedirs(basicswap_dir) os.makedirs(basicswap_dir)
ltcdatadir = os.path.join(datadir, str(LTC_NODE))
btcdatadir = os.path.join(datadir, str(BTC_NODE))
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME) settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
settings = { settings = {
'zmqhost': 'tcp://127.0.0.1', 'zmqhost': 'tcp://127.0.0.1',
'zmqport': BASE_ZMQ_PORT + nodeId, 'zmqport': BASE_ZMQ_PORT + node_id,
'htmlhost': 'localhost', 'htmlhost': 'localhost',
'htmlport': 12700 + nodeId, 'htmlport': 12700 + node_id,
'network_key': network_key, 'network_key': network_key,
'network_pubkey': network_pubkey, 'network_pubkey': network_pubkey,
'chainclients': { 'chainclients': {
'particl': { 'particl': {
'connection_type': 'rpc', 'connection_type': 'rpc',
'manage_daemon': False, 'manage_daemon': False,
'rpcport': BASE_RPC_PORT + nodeId, 'rpcport': BASE_RPC_PORT + node_id,
'datadir': node_dir, 'rpcuser': 'test' + str(node_id),
'rpcpassword': 'test_pass' + str(node_id),
'datadir': os.path.join(datadir, 'part_' + str(node_id)),
'bindir': cfg.PARTICL_BINDIR, 'bindir': cfg.PARTICL_BINDIR,
'blocks_confirmed': 2, # Faster testing 'blocks_confirmed': 2, # Faster testing
}, },
'litecoin': { 'monero': {
'connection_type': 'rpc', 'connection_type': 'rpc',
'manage_daemon': False, 'manage_daemon': False,
'rpcport': BASE_RPC_PORT + LTC_NODE, 'rpcport': XMR_BASE_RPC_PORT + node_id,
'datadir': ltcdatadir, 'walletrpcport': XMR_BASE_WALLET_RPC_PORT + node_id,
'bindir': cfg.LITECOIN_BINDIR, 'walletrpcuser': 'test' + str(node_id),
# 'use_segwit': True, 'walletrpcpassword': 'test_pass' + str(node_id),
'datadir': os.path.join(datadir, 'xmr_' + str(node_id)),
'bindir': cfg.XMR_BINDIR,
}, },
'bitcoin': { 'bitcoin': {
'connection_type': 'rpc', 'connection_type': 'rpc',
'manage_daemon': False, 'manage_daemon': False,
'rpcport': BASE_RPC_PORT + BTC_NODE, 'rpcport': BTC_BASE_RPC_PORT + node_id,
'datadir': btcdatadir, 'rpcuser': 'test' + str(node_id),
'rpcpassword': 'test_pass' + str(node_id),
'datadir': os.path.join(datadir, 'btc_' + str(node_id)),
'bindir': cfg.BITCOIN_BINDIR, 'bindir': cfg.BITCOIN_BINDIR,
'use_segwit': True, 'use_segwit': True,
} }
}, },
'check_progress_seconds': 2, 'check_progress_seconds': 2,
'check_watched_seconds': 4, 'check_watched_seconds': 4,
@ -173,16 +242,27 @@ def prepareDir(datadir, nodeId, network_key, network_pubkey):
'min_delay_auto_accept': 1, 'min_delay_auto_accept': 1,
'max_delay_auto_accept': 5 'max_delay_auto_accept': 5
} }
with open(settings_path, 'w') as fp: with open(settings_path, 'w') as fp:
json.dump(settings, fp, indent=4) json.dump(settings, fp, indent=4)
def partRpc(cmd, node_id=0): def partRpc(cmd, node_id=0):
return callrpc_cli(cfg.PARTICL_BINDIR, os.path.join(cfg.TEST_DATADIRS, str(node_id)), 'regtest', cmd, cfg.PARTICL_CLI) return callrpc_cli(cfg.PARTICL_BINDIR, os.path.join(TEST_DIR, 'part_' + str(node_id)), 'regtest', cmd, cfg.PARTICL_CLI)
def btcRpc(cmd, node_id=0):
return callrpc_cli(cfg.BITCOIN_BINDIR, os.path.join(TEST_DIR, 'btc_' + str(node_id)), 'regtest', cmd, cfg.BITCOIN_CLI)
def btcRpc(cmd): def make_rpc_func(node_id, base_rpc_port=BASE_RPC_PORT):
return callrpc_cli(cfg.BITCOIN_BINDIR, os.path.join(cfg.TEST_DATADIRS, str(BTC_NODE)), 'regtest', cmd, cfg.BITCOIN_CLI) node_id = node_id
auth = 'test{0}:test_pass{0}'.format(node_id)
def rpc_func(method, params=None, wallet=None):
nonlocal node_id, auth
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
return rpc_func
def signal_handler(sig, frame): def signal_handler(sig, frame):
@ -191,21 +271,47 @@ def signal_handler(sig, frame):
stop_test = True stop_test = True
def run_loop(self): def waitForXMRNode(rpc_offset, max_tries=7):
for i in range(max_tries + 1):
try:
callrpc_xmr_na(XMR_BASE_RPC_PORT + rpc_offset, 'get_block_count')
return
except Exception as ex:
if i < max_tries:
logging.warning('Can\'t connect to XMR RPC: %s. Retrying in %d second/s.', str(ex), (i + 1))
time.sleep(i + 1)
raise ValueError('waitForXMRNode failed')
def waitForXMRWallet(rpc_offset, auth, max_tries=7):
for i in range(max_tries + 1):
try:
callrpc_xmr(XMR_BASE_WALLET_RPC_PORT + rpc_offset, auth, 'get_languages')
return
except Exception as ex:
if i < max_tries:
logging.warning('Can\'t connect to XMR wallet RPC: %s. Retrying in %d second/s.', str(ex), (i + 1))
time.sleep(i + 1)
raise ValueError('waitForXMRWallet failed')
def callnoderpc(node_id, method, params=[], wallet=None, base_rpc_port=BASE_RPC_PORT):
auth = 'test{0}:test_pass{0}'.format(node_id)
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
def run_loop(cls):
global stop_test
while not stop_test: while not stop_test:
time.sleep(1) for c in cls.swap_clients:
for c in self.swap_clients:
c.update() c.update()
btcRpc('generatetoaddress 1 {}'.format(self.btc_addr))
if cls.btc_addr is not None:
btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr))
def checkForks(ro): if cls.xmr_addr is not None:
if 'bip9_softforks' in ro: callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': 1})
assert(ro['bip9_softforks']['csv']['status'] == 'active') time.sleep(1.0)
assert(ro['bip9_softforks']['segwit']['status'] == 'active')
else:
assert(ro['softforks']['csv']['active'])
assert(ro['softforks']['segwit']['active'])
class Test(unittest.TestCase): class Test(unittest.TestCase):
@ -214,32 +320,210 @@ class Test(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
super(Test, cls).setUpClass() super(Test, cls).setUpClass()
cls.update_thread = None
cls.http_threads = []
cls.swap_clients = [] cls.swap_clients = []
cls.part_daemons = []
cls.btc_daemons = []
cls.xmr_daemons = [] cls.xmr_daemons = []
cls.xmr_wallet_auth = [] cls.xmr_wallet_auth = []
cls.part_stakelimit = 0 cls.part_stakelimit = 0
cls.xmr_addr = None cls.xmr_addr = None
cls.btc_addr = None
logger.propagate = False
logger.handlers = []
logger.setLevel(logging.INFO) # DEBUG shows many messages from requests.post
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
stream_stdout = logging.StreamHandler()
stream_stdout.setFormatter(formatter)
logger.addHandler(stream_stdout)
if os.path.isdir(TEST_DIR):
logging.info('Removing ' + TEST_DIR)
shutil.rmtree(TEST_DIR)
if not os.path.exists(TEST_DIR):
os.makedirs(TEST_DIR)
cls.stream_fp = logging.FileHandler(os.path.join(TEST_DIR, 'test.log'))
cls.stream_fp.setFormatter(formatter)
logger.addHandler(cls.stream_fp)
try:
logging.info('Preparing coin nodes.')
for i in range(NUM_NODES):
prepareDataDir(TEST_DIR, i, 'particl.conf', 'part_')
cls.part_daemons.append(startDaemon(os.path.join(TEST_DIR, 'part_' + str(i)), cfg.PARTICL_BINDIR, cfg.PARTICLD))
logging.info('Started %s %d', cfg.PARTICLD, cls.part_daemons[-1].pid)
waitForRPC(make_rpc_func(i))
for i in range(NUM_BTC_NODES):
prepareDataDir(TEST_DIR, i, 'bitcoin.conf', 'btc_', base_p2p_port=BTC_BASE_PORT, base_rpc_port=BTC_BASE_RPC_PORT)
cls.btc_daemons.append(startDaemon(os.path.join(TEST_DIR, 'btc_' + str(i)), cfg.BITCOIN_BINDIR, cfg.BITCOIND))
logging.info('Started %s %d', cfg.BITCOIND, cls.part_daemons[-1].pid)
waitForRPC(make_rpc_func(i, base_rpc_port=BTC_BASE_RPC_PORT))
for i in range(NUM_XMR_NODES):
prepareXmrDataDir(TEST_DIR, i, 'monerod.conf')
cls.xmr_daemons.append(startXmrDaemon(os.path.join(TEST_DIR, 'xmr_' + str(i)), cfg.XMR_BINDIR, cfg.XMRD))
logging.info('Started %s %d', cfg.XMRD, cls.xmr_daemons[-1].pid)
waitForXMRNode(i)
cls.xmr_daemons.append(startXmrWalletRPC(os.path.join(TEST_DIR, 'xmr_' + str(i)), cfg.XMR_BINDIR, cfg.XMR_WALLET_RPC, i))
for i in range(NUM_XMR_NODES):
cls.xmr_wallet_auth.append(('test{0}'.format(i), 'test_pass{0}'.format(i)))
logging.info('Creating XMR wallet %i', i)
waitForXMRWallet(i, cls.xmr_wallet_auth[i])
cls.callxmrnodewallet(cls, i, 'create_wallet', {'filename': 'testwallet', 'language': 'English'})
cls.callxmrnodewallet(cls, i, 'open_wallet', {'filename': 'testwallet'})
logging.info('Preparing swap clients.')
eckey = ECKey()
eckey.generate()
cls.network_key = toWIF(PREFIX_SECRET_KEY_REGTEST, eckey.get_bytes())
cls.network_pubkey = eckey.get_pubkey().get_bytes().hex()
for i in range(NUM_NODES):
prepare_swapclient_dir(TEST_DIR, i, cls.network_key, cls.network_pubkey)
basicswap_dir = os.path.join(os.path.join(TEST_DIR, 'basicswap_' + str(i)))
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
with open(settings_path) as fs:
settings = json.load(fs)
fp = open(os.path.join(basicswap_dir, 'basicswap.log'), 'w')
sc = BasicSwap(fp, basicswap_dir, settings, 'regtest', log_name='BasicSwap{}'.format(i))
sc.setDaemonPID(Coins.BTC, cls.btc_daemons[i].pid)
sc.setDaemonPID(Coins.PART, cls.part_daemons[i].pid)
sc.start()
cls.swap_clients.append(sc)
logging.info('Initialising coin networks.')
cls.swap_clients[0].callrpc('extkeyimportmaster', ['abandon baby cabbage dad eager fabric gadget habit ice kangaroo lab absorb'])
cls.swap_clients[1].callrpc('extkeyimportmaster', ['pact mammal barrel matrix local final lecture chunk wasp survey bid various book strong spread fall ozone daring like topple door fatigue limb olympic', '', 'true'])
cls.swap_clients[1].callrpc('getnewextaddress', ['lblExtTest'])
cls.swap_clients[1].callrpc('rescanblockchain')
for i in range(3):
t = HttpThread(cls.swap_clients[i].fp, TEST_HTTP_HOST, TEST_HTTP_PORT + i, False, cls.swap_clients[i])
cls.http_threads.append(t)
t.start()
cls.btc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT)
cls.xmr_addr = cls.callxmrnodewallet(cls, 0, 'get_address')['address']
num_blocks = 500
logging.info('Mining %d bitcoin blocks to %s', num_blocks, cls.btc_addr)
callnoderpc(0, 'generatetoaddress', [num_blocks, cls.btc_addr], base_rpc_port=BTC_BASE_RPC_PORT)
checkForks(callnoderpc(0, 'getblockchaininfo', base_rpc_port=BTC_BASE_RPC_PORT))
if callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'get_block_count')['count'] < num_blocks:
logging.info('Mining %d Monero blocks.', num_blocks)
callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': num_blocks})
rv = callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'get_block_count')
logging.info('XMR blocks: %d', rv['count'])
logging.info('Starting update thread.')
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
cls.update_thread = threading.Thread(target=run_loop, args=(cls,)) cls.update_thread = threading.Thread(target=run_loop, args=(cls,))
cls.update_thread.start() cls.update_thread.start()
except Exception:
traceback.print_exc()
Test.tearDownClass()
raise ValueError('setUpClass() failed.')
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
global stop_test global stop_test
logging.info('Finalising') logging.info('Finalising')
stop_test = True stop_test = True
if cls.update_thread is not None:
try:
cls.update_thread.join() cls.update_thread.join()
except Exception:
logging.info('Failed to join update_thread')
cls.update_thread = None
for t in cls.http_threads:
t.stop()
t.join()
for c in cls.swap_clients:
c.fp.close()
for d in cls.xmr_daemons:
logging.info('Interrupting %d', d.pid)
try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in cls.xmr_daemons:
try:
d.wait(timeout=20)
if d.stdout:
d.stdout.close()
if d.stderr:
d.stderr.close()
if d.stdin:
d.stdin.close()
except Exception as e:
logging.info('Closing %d, error %s', d.pid, str(e))
for d in cls.part_daemons + cls.btc_daemons:
logging.info('Interrupting %d', d.pid)
try:
d.send_signal(signal.SIGINT)
except Exception as e:
logging.info('Interrupting %d, error %s', d.pid, str(e))
for d in cls.part_daemons + cls.btc_daemons:
try:
d.wait(timeout=20)
if d.stdout:
d.stdout.close()
if d.stderr:
d.stderr.close()
if d.stdin:
d.stdin.close()
except Exception as e:
logging.info('Closing %d, error %s', d.pid, str(e))
super(Test, cls).tearDownClass() super(Test, cls).tearDownClass()
def callxmrnodewallet(self, node_id, method, params=None):
return callrpc_xmr(XMR_BASE_WALLET_RPC_PORT + node_id, self.xmr_wallet_auth[node_id], method, params)
def wait_for_offer(self, swap_client, offer_id):
logging.info('wait_for_offer %s', offer_id.hex())
for i in range(20):
time.sleep(1)
offers = swap_client.listOffers()
for offer in offers:
if offer.offer_id == offer_id:
return
raise ValueError('wait_for_offer timed out.')
def test_01_part_xmr(self): def test_01_part_xmr(self):
logging.info('---------- Test PART to XMR') logging.info('---------- Test PART to XMR')
#swap_clients = self.swap_clients swap_clients = self.swap_clients
js_0 = json.loads(urlopen('http://localhost:1800/json/wallets').read())
assert(make_int(js_0[str(int(Coins.XMR))]['balance'], scale=12) > 0)
assert(make_int(js_0[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0)
#offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 0.5 * COIN, 100 * COIN, SwapTypes.SELLER_FIRST) offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 10 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP)
self.wait_for_offer(swap_clients[1], offer_id)
offers = swap_clients[1].listOffers()
assert(len(offers) == 1)
for offer in offers:
print('offer', offer)
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save