Adding settings page.

This commit is contained in:
tecnovert 2019-08-06 00:04:40 +02:00
parent 4405a130f5
commit 3e542e6bd0
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
7 changed files with 138 additions and 11 deletions

View file

@ -15,6 +15,8 @@ import hashlib
import subprocess
import logging
import sqlalchemy as sa
import shutil
import json
from sqlalchemy.orm import sessionmaker, scoped_session
from enum import IntEnum, auto
@ -453,6 +455,7 @@ class BasicSwap():
'pid': None,
'core_version': None,
'explorers': [],
'chain_lookups': chain_client_settings.get('chain_lookups', 'local'),
}
def setDaemonPID(self, name, pid):
@ -637,13 +640,13 @@ class BasicSwap():
if bid.state == BidStates.BID_ABANDONED or bid.state == BidStates.SWAP_COMPLETED:
# Return unused addrs to pool
if bid.getITxState() != TxStates.TX_REDEEMED:
self.returnAddressToPool(bid_id, TxTypes.ITX_REDEEM)
self.returnAddressToPool(bid.bid_id, TxTypes.ITX_REDEEM)
if bid.getITxState() != TxStates.TX_REFUNDED:
self.returnAddressToPool(bid_id, TxTypes.ITX_REFUND)
self.returnAddressToPool(bid.bid_id, TxTypes.ITX_REFUND)
if bid.getPTxState() != TxStates.TX_REDEEMED:
self.returnAddressToPool(bid_id, TxTypes.PTX_REDEEM)
self.returnAddressToPool(bid.bid_id, TxTypes.PTX_REDEEM)
if bid.getPTxState() != TxStates.TX_REFUNDED:
self.returnAddressToPool(bid_id, TxTypes.PTX_REFUND)
self.returnAddressToPool(bid.bid_id, TxTypes.PTX_REFUND)
def loadFromDB(self):
self.log.info('Loading data from db')
@ -1700,12 +1703,40 @@ class BasicSwap():
# bid saved in checkBidState
def getAddressBalance(self, coin_type, address):
if self.coin_clients[coin_type]['chain_lookups'] == 'explorer':
explorers = self.coin_clients[coin_type]['explorers']
# TODO: random offset into explorers, try blocks
for exp in explorers:
return exp.getBalance(address)
return self.lookupUnspentByAddress(coin_type, address, sum_output=True)
def lookupChainHeight(self, coin_type):
return self.callcoinrpc(coin_type, 'getblockchaininfo')['blocks']
def lookupUnspentByAddress(self, coin_type, address, sum_output=False, assert_amount=None, assert_txid=None):
# TODO: Lookup from explorers
if self.coin_clients[coin_type]['chain_lookups'] == 'explorer':
explorers = self.coin_clients[coin_type]['explorers']
# TODO: random offset into explorers, try blocks
for exp in explorers:
# TODO: ExplorerBitAps use only gettransaction if assert_txid is set
rv = exp.lookupUnspentByAddress(address)
if assert_amount is not None:
assert(rv['value'] == int(assert_amount)), 'Incorrect output amount in txn {}: {} != {}.'.format(assert_txid, rv['value'], int(assert_amount))
if assert_txid is not None:
assert(rv['txid)'] == assert_txid), 'Incorrect txid'
return rv
raise ValueError('No explorer for lookupUnspentByAddress {}'.format(str(coin_type)))
if self.coin_clients[coin_type]['connection_type'] != 'rpc':
raise ValueError('No RPC connection for lookupUnspentByAddress {}'.format(str(coin_type)))
if assert_txid is not None:
try:
@ -1739,6 +1770,7 @@ class BasicSwap():
'index': o['vout'],
'height': o['height'],
'n_conf': n_conf,
'value': makeInt(o['amount']),
}
else:
sum_unspent += o['amount'] * COIN
@ -2153,7 +2185,7 @@ class BasicSwap():
else:
addr_search = bid_data.proof_address
sum_unspent = self.lookupUnspentByAddress(coin_to, addr_search, sum_output=True)
sum_unspent = self.getAddressBalance(coin_to, addr_search)
self.log.debug('Proof of funds %s %s', bid_data.proof_address, format8(sum_unspent))
assert(sum_unspent >= bid_data.amount), 'Proof of funds failed'
@ -2366,7 +2398,7 @@ class BasicSwap():
if has_changed:
session = scoped_session(self.session_factory)
try:
self.saveBidInSession(session, bid)
self.saveBidInSession(bid_id, bid, session)
session.commit()
if bid.state and bid.state > BidStates.BID_RECEIVED and bid.state < BidStates.SWAP_COMPLETED:
self.activateBid(session, bid)
@ -2380,6 +2412,23 @@ class BasicSwap():
finally:
self.mxDB.release()
def editSettings(self, coin_name, data):
self.log.info('Updating settings %s', coin_name)
self.mxDB.acquire()
try:
if 'lookups' in data:
self.settings['chainclients'][coin_name]['chain_lookups'] = data['lookups']
settings_path = os.path.join(self.data_dir, 'basicswap.json')
shutil.copyfile(settings_path, settings_path + '.last')
with open(settings_path, 'w') as fp:
json.dump(self.settings, fp, indent=4)
for c in self.coin_clients:
if c['name'] == coin_name:
c['chain_lookups'] = data['lookups']
finally:
self.mxDB.release()
def getSummary(self, opts=None):
num_watched_outputs = 0
for c, v in self.coin_clients.items():

View file

@ -190,4 +190,3 @@ class EventQueue(Base):
trigger_at = sa.Column(sa.BigInteger)
linked_id = sa.Column(sa.LargeBinary)
event_type = sa.Column(sa.Integer)

View file

@ -48,6 +48,7 @@ class ExplorerInsight(Explorer):
'index': utxo['vout'],
'height': utxo['height'],
'n_conf': utxo['confirmations'],
'value': utxo['satoshis'],
})
return rv
@ -66,10 +67,28 @@ class ExplorerBitAps(Explorer):
def getBalance(self, address):
data = json.loads(self.readURL(self.base_url + '/address/state/' + address))
return data
return data['data']['balance']
def lookupUnspentByAddress(self, address):
return json.loads(self.readURL(self.base_url + '/address/transactions/' + address))
# Can't get unspents return only if exactly one transaction exists
data = json.loads(self.readURL(self.base_url + '/address/transactions/' + address))
try:
assert(data['data']['list'] == 1)
except Exception as ex:
self.log.debug('Explorer error: {}'.format(str(ex)))
return None
tx = data['data']['list'][0]
tx_data = json.loads(self.readURL(self.base_url + '/transaction/{}'.format(tx['txId'])))['data']
for i, vout in tx_data['vOut'].items():
if vout['address'] == address:
return [{
'txid': tx_data['txId'],
'index': int(i),
'height': tx_data['blockHeight'],
'n_conf': tx_data['confirmations'],
'value': vout['value'],
}]
class ExplorerChainz(Explorer):

View file

@ -204,7 +204,7 @@ class HttpHandler(BaseHTTPRequestHandler):
explorer = form_data[b'explorer'][0].decode('utf-8')
action = form_data[b'action'][0].decode('utf-8')
args = '' if not b'args' in form_data else form_data[b'args'][0].decode('utf-8')
args = '' if b'args' not in form_data else form_data[b'args'][0].decode('utf-8')
try:
c, e = explorer.split('_')
exp = swap_client.coin_clients[Coins(int(c))]['explorers'][int(e)]
@ -331,6 +331,32 @@ class HttpHandler(BaseHTTPRequestHandler):
form_id=os.urandom(8).hex(),
), 'UTF-8')
def page_settings(self, url_split, post_string):
swap_client = self.server.swap_client
messages = []
form_data = self.checkForm(post_string, 'settings', messages)
if form_data:
for name, c in swap_client.settings['chainclients'].items():
if bytes('apply_' + name, 'utf-8') in form_data:
data = {'lookups': form_data[bytes('lookups_' + name, 'utf-8')][0].decode('utf-8')}
swap_client.editSettings(name, data)
chains_formatted = []
for name, c in swap_client.settings['chainclients'].items():
chains_formatted.append({
'name': name,
'lookups': c.get('chain_lookups', 'local')
})
template = env.get_template('settings.html')
return bytes(template.render(
title=self.server.title,
h2=self.server.title,
chains=chains_formatted,
form_id=os.urandom(8).hex(),
), 'UTF-8')
def page_newoffer(self, url_split, post_string):
swap_client = self.server.swap_client
@ -739,6 +765,8 @@ class HttpHandler(BaseHTTPRequestHandler):
return self.page_active(url_split, post_string)
if url_split[1] == 'wallets':
return self.page_wallets(url_split, post_string)
if url_split[1] == 'settings':
return self.page_settings(url_split, post_string)
if url_split[1] == 'rpc':
return self.page_rpc(url_split, post_string)
if url_split[1] == 'explorers':

View file

@ -8,6 +8,7 @@ Version: {{ version }}
</p>
<p>
<a href="/wallets">View Wallets</a><br/>
<a href="/settings">Settings</a><br/>
<a href="/rpc">RPC Console</a><br/>
<a href="/explorers">Explorers</a><br/>
<br/>

View file

@ -0,0 +1,27 @@
{% include 'header.html' %}
<h3>Settings</h3>
{% for m in messages %}
<p>{{ m }}</p>
{% endfor %}
<form method="post">
{% for c in chains %}
<h4>{{ c.name }}</h4>
<table>
<tr><td>Chain Lookups</td><td>
<select name="lookups_{{ c.name }}">
<option value="local"{% if c.lookups=='local' %} selected{% endif %}>Local Node</option>
<option value="explorer"{% if c.lookups=='explorer' %} selected{% endif %}>Explorer</option>
</select></td></tr>
<tr><td><input type="submit" name="apply_{{ c.name }}" value="Apply"></td></tr>
</table>
{% endfor %}
<input type="hidden" name="formid" value="{{ form_id }}">
</form>
<p><a href="/">home</a></p>
</body></html>

View file

@ -383,6 +383,7 @@ def main():
'override_feerate': 0.002,
'conf_target': 2,
'core_version_group': 18,
'chain_lookups': 'local',
},
'litecoin': {
'connection_type': 'rpc' if 'litecoin' in with_coins else 'none',
@ -394,6 +395,7 @@ def main():
'blocks_confirmed': 2,
'conf_target': 2,
'core_version_group': 17,
'chain_lookups': 'local',
},
'bitcoin': {
'connection_type': 'rpc' if 'bitcoin' in with_coins else 'none',
@ -405,6 +407,7 @@ def main():
'blocks_confirmed': 1,
'conf_target': 2,
'core_version_group': 18,
'chain_lookups': 'local',
},
'namecoin': {
'connection_type': 'rpc' if 'namecoin' in with_coins else 'none',
@ -417,6 +420,7 @@ def main():
'blocks_confirmed': 1,
'conf_target': 2,
'core_version_group': 18,
'chain_lookups': 'local',
}
}