ui, xmr: List of candidate remote XMR daemon urls can be set through the http ui

2024-05-20_merge
tecnovert 3 years ago
parent eff5235205
commit b152150932
No known key found for this signature in database
GPG Key ID: 8ED6D8750C4E3F93
  1. 62
      basicswap/basicswap.py
  2. 30
      basicswap/http_server.py
  3. 15
      basicswap/rpc_xmr.py
  4. 23
      basicswap/templates/settings.html
  5. 2
      doc/release-notes.md

@ -34,6 +34,7 @@ from .interface_xmr import XMRInterface
from .interface_passthrough_btc import PassthroughBTCInterface from .interface_passthrough_btc import PassthroughBTCInterface
from . import __version__ from . import __version__
from .rpc_xmr import make_xmr_rpc2_func
from .util import ( from .util import (
TemporaryError, TemporaryError,
pubkeyToAddress, pubkeyToAddress,
@ -377,6 +378,9 @@ class BasicSwap(BaseApp):
if self.coin_clients[coin]['connection_type'] == 'rpc': if self.coin_clients[coin]['connection_type'] == 'rpc':
if coin == Coins.XMR: if coin == Coins.XMR:
if chain_client_settings.get('automatically_select_daemon', False):
self.selectXMRRemoteDaemon(coin)
self.coin_clients[coin]['walletrpchost'] = chain_client_settings.get('walletrpchost', '127.0.0.1') self.coin_clients[coin]['walletrpchost'] = chain_client_settings.get('walletrpchost', '127.0.0.1')
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:
@ -384,6 +388,41 @@ class BasicSwap(BaseApp):
else: else:
raise ValueError('Missing XMR wallet rpc credentials.') raise ValueError('Missing XMR wallet rpc credentials.')
def selectXMRRemoteDaemon(self, coin):
self.log.info('Selecting remote XMR daemon.')
chain_client_settings = self.getChainClientSettings(coin)
remote_daemon_urls = chain_client_settings.get('remote_daemon_urls', [])
rpchost = self.coin_clients[coin]['rpchost']
rpcport = self.coin_clients[coin]['rpcport']
current_daemon_url = f'{rpchost}:{rpcport}'
if current_daemon_url in remote_daemon_urls:
self.log.info(f'Trying last used url {rpchost}:{rpcport}.')
try:
rpc_cb2 = make_xmr_rpc2_func(rpcport, rpchost)
test = rpc_cb2('get_height', timeout=20)['height']
return True
except Exception as e:
self.log.warning(f'Failed to set XMR remote daemon to {rpchost}:{rpcport}, {e}')
random.shuffle(remote_daemon_urls)
for url in remote_daemon_urls:
self.log.info(f'Trying url {url}.')
try:
rpchost, rpcport = url.rsplit(':', 1)
rpc_cb2 = make_xmr_rpc2_func(rpcport, rpchost)
test = rpc_cb2('get_height', timeout=20)['height']
self.coin_clients[coin]['rpchost'] = rpchost
self.coin_clients[coin]['rpcport'] = rpcport
data = {
'rpchost': rpchost,
'rpcport': rpcport,
}
self.editSettings(self.coin_clients[coin]['name'], data)
return True
except Exception as e:
self.log.warning(f'Failed to set XMR remote daemon to {url}, {e}')
raise ValueError('Failed to select a working XMR daemon url.')
def ci(self, coin): # Coin interface def ci(self, coin): # Coin interface
if coin == Coins.PART_ANON: if coin == Coins.PART_ANON:
return self.coin_clients[Coins.PART]['interface_anon'] return self.coin_clients[Coins.PART]['interface_anon']
@ -4818,6 +4857,7 @@ class BasicSwap(BaseApp):
with self.mxDB: with self.mxDB:
settings_cc = self.settings['chainclients'][coin_name] settings_cc = self.settings['chainclients'][coin_name]
settings_changed = False settings_changed = False
suggest_reboot = False
if 'lookups' in data: if 'lookups' in data:
if settings_cc.get('chain_lookups', 'local') != data['lookups']: if settings_cc.get('chain_lookups', 'local') != data['lookups']:
settings_changed = True settings_changed = True
@ -4827,6 +4867,26 @@ class BasicSwap(BaseApp):
cc['chain_lookups'] = data['lookups'] cc['chain_lookups'] = data['lookups']
break break
for setting in ('manage_daemon', 'rpchost', 'rpcport', 'automatically_select_daemon'):
if setting not in data:
continue
if settings_cc.get(setting) != data[setting]:
settings_changed = True
suggest_reboot = True
settings_cc[setting] = data[setting]
if 'remotedaemonurls' in data:
remotedaemonurls_in = data['remotedaemonurls'].split('\n')
remotedaemonurls = set()
for url in remotedaemonurls_in:
if url.count(':') > 0:
remotedaemonurls.add(url.strip())
if set(settings_cc.get('remote_daemon_urls', [])) != remotedaemonurls:
settings_cc['remote_daemon_urls'] = list(remotedaemonurls)
settings_changed = True
suggest_reboot = True
if 'fee_priority' in data: if 'fee_priority' in data:
new_fee_priority = data['fee_priority'] new_fee_priority = data['fee_priority']
ensure(new_fee_priority >= 0 and new_fee_priority < 4, 'Invalid priority') ensure(new_fee_priority >= 0 and new_fee_priority < 4, 'Invalid priority')
@ -4858,7 +4918,7 @@ class BasicSwap(BaseApp):
shutil.copyfile(settings_path, settings_path + '.last') shutil.copyfile(settings_path, settings_path + '.last')
with open(settings_path, 'w') as fp: with open(settings_path, 'w') as fp:
json.dump(self.settings, fp, indent=4) json.dump(self.settings, fp, indent=4)
return settings_changed return settings_changed, suggest_reboot
def enableCoin(self, coin_name): def enableCoin(self, coin_name):
self.log.info('Enabling coin %s', coin_name) self.log.info('Enabling coin %s', coin_name)

@ -388,26 +388,36 @@ class HttpHandler(BaseHTTPRequestHandler):
form_data = self.checkForm(post_string, 'settings', messages) form_data = self.checkForm(post_string, 'settings', messages)
if form_data: if form_data:
for name, c in swap_client.settings['chainclients'].items(): for name, c in swap_client.settings['chainclients'].items():
if bytes('apply_' + name, 'utf-8') in form_data: if have_data_entry(form_data, 'apply_' + name):
data = {'lookups': form_data[bytes('lookups_' + name, 'utf-8')][0].decode('utf-8')} data = {'lookups': get_data_entry(form_data, 'lookups_' + name)}
if name == 'monero': if name == 'monero':
data['fee_priority'] = int(form_data[bytes('fee_priority_' + name, 'utf-8')][0]) data['fee_priority'] = int(get_data_entry(form_data, 'fee_priority_' + name))
data['manage_daemon'] = True if get_data_entry(form_data, 'managedaemon_' + name) == 'true' else False
data['rpchost'] = get_data_entry(form_data, 'rpchost_' + name)
data['rpcport'] = int(get_data_entry(form_data, 'rpcport_' + name))
data['remotedaemonurls'] = get_data_entry(form_data, 'remotedaemonurls_' + name)
data['automatically_select_daemon'] = True if get_data_entry(form_data, 'autosetdaemon_' + name) == 'true' else False
else: else:
data['conf_target'] = int(form_data[bytes('conf_target_' + name, 'utf-8')][0]) data['conf_target'] = int(get_data_entry(form_data, 'conf_target_' + name))
if swap_client.editSettings(name, data) is True: settings_changed, suggest_reboot = swap_client.editSettings(name, data)
if settings_changed is True:
messages.append('Settings applied.') messages.append('Settings applied.')
elif bytes('enable_' + name, 'utf-8') in form_data: if suggest_reboot is True:
messages.append('Please restart BasicSwap.')
elif have_data_entry(form_data, 'enable_' + name):
swap_client.enableCoin(name) swap_client.enableCoin(name)
messages.append(name.capitalize() + ' enabled, shutting down.') messages.append(name.capitalize() + ' enabled, shutting down.')
swap_client.stopRunning() swap_client.stopRunning()
elif bytes('disable_' + name, 'utf-8') in form_data: elif have_data_entry(form_data, 'disable_' + name):
swap_client.disableCoin(name) swap_client.disableCoin(name)
messages.append(name.capitalize() + ' disabled, shutting down.') messages.append(name.capitalize() + ' disabled, shutting down.')
swap_client.stopRunning() swap_client.stopRunning()
chains_formatted = [] chains_formatted = []
for name, c in swap_client.settings['chainclients'].items(): sorted_names = sorted(swap_client.settings['chainclients'].keys())
for name in sorted_names:
c = swap_client.settings['chainclients'][name]
chains_formatted.append({ chains_formatted.append({
'name': name, 'name': name,
'lookups': c.get('chain_lookups', 'local'), 'lookups': c.get('chain_lookups', 'local'),
@ -417,6 +427,10 @@ class HttpHandler(BaseHTTPRequestHandler):
if name == 'monero': if name == 'monero':
chains_formatted[-1]['fee_priority'] = c.get('fee_priority', 0) chains_formatted[-1]['fee_priority'] = c.get('fee_priority', 0)
chains_formatted[-1]['manage_wallet_daemon'] = c.get('manage_wallet_daemon', 'Unknown') chains_formatted[-1]['manage_wallet_daemon'] = c.get('manage_wallet_daemon', 'Unknown')
chains_formatted[-1]['rpchost'] = c.get('rpchost', 'localhost')
chains_formatted[-1]['rpcport'] = int(c.get('rpcport', 18081))
chains_formatted[-1]['remotedaemonurls'] = '\n'.join(c.get('remote_daemon_urls', []))
chains_formatted[-1]['autosetdaemon'] = c.get('automatically_select_daemon', False)
else: else:
chains_formatted[-1]['conf_target'] = c.get('conf_target', 2) chains_formatted[-1]['conf_target'] = c.get('conf_target', 2)
if name != 'particl': if name != 'particl':

@ -7,7 +7,10 @@ import requests
def callrpc_xmr(rpc_port, auth, method, params=[], rpc_host='127.0.0.1', path='json_rpc', timeout=120): def callrpc_xmr(rpc_port, auth, method, params=[], rpc_host='127.0.0.1', path='json_rpc', timeout=120):
# auth is a tuple: (username, password) # auth is a tuple: (username, password)
try: try:
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, path) if rpc_host.count('://') > 0:
url = '{}:{}/{}'.format(rpc_host, rpc_port, path)
else:
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, path)
request_body = { request_body = {
'method': method, 'method': method,
'params': params, 'params': params,
@ -30,7 +33,10 @@ def callrpc_xmr(rpc_port, auth, method, params=[], rpc_host='127.0.0.1', path='j
def callrpc_xmr_na(rpc_port, method, params=[], rpc_host='127.0.0.1', path='json_rpc', timeout=120): def callrpc_xmr_na(rpc_port, method, params=[], rpc_host='127.0.0.1', path='json_rpc', timeout=120):
try: try:
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, path) if rpc_host.count('://') > 0:
url = '{}:{}/{}'.format(rpc_host, rpc_port, path)
else:
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, path)
request_body = { request_body = {
'method': method, 'method': method,
'params': params, 'params': params,
@ -53,7 +59,10 @@ def callrpc_xmr_na(rpc_port, method, params=[], rpc_host='127.0.0.1', path='json
def callrpc_xmr2(rpc_port, method, params=None, rpc_host='127.0.0.1', timeout=120): def callrpc_xmr2(rpc_port, method, params=None, rpc_host='127.0.0.1', timeout=120):
try: try:
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, method) if rpc_host.count('://') > 0:
url = '{}:{}/{}'.format(rpc_host, rpc_port, method)
else:
url = 'http://{}:{}/{}'.format(rpc_host, rpc_port, method)
headers = { headers = {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }

@ -15,8 +15,31 @@
<tr><td>Connection Type</td><td>{{ c.connection_type }}</td></tr> <tr><td>Connection Type</td><td>{{ c.connection_type }}</td></tr>
{% endif %} {% endif %}
{% if c.manage_daemon is defined %} {% if c.manage_daemon is defined %}
{% if c.name == 'monero' %}
<tr><td>Manage Daemon</td><td>
<select name="managedaemon_{{ c.name }}">
<option value="true"{% if c.manage_daemon==true %} selected{% endif %}>True</option>
<option value="false"{% if c.manage_daemon==false %} selected{% endif %}>False</option>
</select></td></tr>
<tr><td>Daemon RPC Host</td><td><input type="text" name="rpchost_{{ c.name }}" value="{{ c.rpchost }}"></td></tr>
<tr><td>Daemon RPC Port</td><td><input type="text" name="rpcport_{{ c.name }}" value="{{ c.rpcport }}"></td></tr>
<tr><td colspan=2>Remote Daemon Urls<br/>
List of public nodes to use if "Automatically Select Daemon" is true.<br/>
Add one entry per line, eg:<br/>
node.xmr.to:18081<br/>
<textarea class="monospace" name="remotedaemonurls_{{ c.name }}" rows="10" cols="100">
{{ c.remotedaemonurls }}
</textarea>
</td></tr>
<tr><td>Automatically Select Daemon</td><td>
<select name="autosetdaemon_{{ c.name }}">
<option value="true"{% if c.autosetdaemon==true %} selected{% endif %}>True</option>
<option value="false"{% if c.autosetdaemon==false %} selected{% endif %}>False</option>
</select></td></tr>
{% else %}
<tr><td>Manage Daemon</td><td>{{ c.manage_daemon }}</td></tr> <tr><td>Manage Daemon</td><td>{{ c.manage_daemon }}</td></tr>
{% endif %} {% endif %}
{% endif %}
{% if c.manage_wallet_daemon is defined %} {% if c.manage_wallet_daemon is defined %}
<tr><td>Manage Wallet Daemon</td><td>{{ c.manage_wallet_daemon }}</td></tr> <tr><td>Manage Wallet Daemon</td><td>{{ c.manage_wallet_daemon }}</td></tr>
{% endif %} {% endif %}

@ -9,6 +9,8 @@
- xmrswaps: - xmrswaps:
- Setting state to 'Script tx redeemed' will trigger an attempt to redeem the scriptless lock tx. - Setting state to 'Script tx redeemed' will trigger an attempt to redeem the scriptless lock tx.
- Node will wait for the chain B lock tx to reach a spendable depth before attempting to spend. - Node will wait for the chain B lock tx to reach a spendable depth before attempting to spend.
- ui: Sort settings page by coin name.
- ui, xmr: List of candidate remote XMR daemon urls can be set through the http ui
0.0.25 0.0.25

Loading…
Cancel
Save