Increase version, add test for bids sent while recipient is offline.

This commit is contained in:
tecnovert
2021-01-11 23:48:46 +02:00
parent a3ba5cf7e6
commit 60b477e3c0
20 changed files with 352 additions and 208 deletions

View File

@@ -1,3 +1,3 @@
name = "basicswap"
__version__ = "0.0.9"
__version__ = "0.0.10"

View File

@@ -440,12 +440,7 @@ class BasicSwap(BaseApp):
self.swaps_in_progress = dict()
if self.chain == 'regtest':
self.SMSG_SECONDS_IN_DAY = 600
self.SMSG_SECONDS_IN_HOUR = 60 * 2
else:
self.SMSG_SECONDS_IN_DAY = 86400
self.SMSG_SECONDS_IN_HOUR = 60 * 60
self.SMSG_SECONDS_IN_HOUR = 60 * 2 if self.chain == 'regtest' else 60 * 60
# Encode key to match network
wif_prefix = chainparams[Coins.PART][self.chain]['key_prefix']
@@ -579,7 +574,7 @@ class BasicSwap(BaseApp):
if self.coin_clients[coin]['connection_type'] == 'rpc':
if coin == Coins.XMR:
self.coin_clients[coin]['walletrpchost'] = chain_client_settings.get('walletrpchost', 'localhost')
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'])
if 'walletrpcpassword' in chain_client_settings:
self.coin_clients[coin]['walletrpcauth'] = (chain_client_settings['walletrpcuser'], chain_client_settings['walletrpcpassword'])
@@ -803,9 +798,9 @@ class BasicSwap(BaseApp):
kv.value = int_val
session.add(kv)
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
def setStringKV(self, str_key, str_val):
@@ -819,9 +814,9 @@ class BasicSwap(BaseApp):
kv.value = str_val
session.add(kv)
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
def getStringKV(self, str_key):
@@ -963,12 +958,15 @@ class BasicSwap(BaseApp):
self.loadFromDB()
# Scan inbox
options = {'encoding': 'hex'}
# TODO: Redundant? small window for zmq messages to go unnoticed during startup?
# options = {'encoding': 'hex'}
options = {'encoding': 'none'}
ro = self.callrpc('smsginbox', ['unread', '', options])
nm = 0
for msg in ro['messages']:
msg['hex'] += '00' # Add nullbtye to match output from 'smsg' cmd - TODO: make consistent
self.processMsg(msg)
# TODO: Remove workaround for smsginbox bug
get_msg = self.callrpc('smsg', [msg['msgid'], {'encoding': 'hex', 'setread': True}])
self.processMsg(get_msg)
nm += 1
self.log.info('Scanned %d unread messages.', nm)
@@ -1024,6 +1022,7 @@ class BasicSwap(BaseApp):
self.validateOfferLockValue(coin_from_t, coin_to_t, lock_type, lock_value)
self.mxDB.acquire()
session = None
try:
self.checkSynced(coin_from_t, coin_to_t)
# TODO: require proof of funds on offers?
@@ -1123,9 +1122,11 @@ class BasicSwap(BaseApp):
if addr_send_from is None:
session.add(SmsgAddress(addr=offer_addr, use_type=MessageTypes.OFFER))
session.commit()
session.close()
session.remove()
finally:
if session:
session.close()
session.remove()
self.mxDB.release()
self.log.info('Sent OFFER %s', offer_id.hex())
return offer_id
@@ -1262,9 +1263,9 @@ class BasicSwap(BaseApp):
addr = record.addr
session.add(record)
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
return addr
@@ -1280,9 +1281,9 @@ class BasicSwap(BaseApp):
session.commit()
except Exception as ex:
pass
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
def getReceiveAddressForCoin(self, coin_type):
@@ -1380,9 +1381,9 @@ class BasicSwap(BaseApp):
value=addr
))
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
return addr
@@ -1391,11 +1392,11 @@ class BasicSwap(BaseApp):
try:
self._contract_count += 1
session = scoped_session(self.session_factory)
self.engine.execute('UPDATE kv_int SET value = {} WHERE KEY="contract_count"'.format(self._contract_count))
session.execute('UPDATE kv_int SET value = {} WHERE KEY="contract_count"'.format(self._contract_count))
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
return self._contract_count
@@ -1458,9 +1459,9 @@ class BasicSwap(BaseApp):
session = scoped_session(self.session_factory)
self.saveBidInSession(bid_id, bid, session, xmr_swap)
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
def saveToDB(self, db_record):
@@ -1469,9 +1470,9 @@ class BasicSwap(BaseApp):
session = scoped_session(self.session_factory)
session.add(db_record)
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
def createEventInSession(self, delay, event_type, linked_id, session):
@@ -1492,9 +1493,9 @@ class BasicSwap(BaseApp):
session = scoped_session(self.session_factory)
self.createEventInSession(delay, event_type, linked_id, session)
session.commit()
finally:
session.close()
session.remove()
finally:
self.mxDB.release()
def logBidEvent(self, bid, event_type, event_msg, session):
@@ -1577,13 +1578,15 @@ class BasicSwap(BaseApp):
)
bid.setState(BidStates.BID_SENT)
session = scoped_session(self.session_factory)
self.saveBidInSession(bid_id, bid, session)
if addr_send_from is None:
session.add(SmsgAddress(addr=bid_addr, use_type=MessageTypes.BID))
session.commit()
session.close()
session.remove()
try:
session = scoped_session(self.session_factory)
self.saveBidInSession(bid_id, bid, session)
if addr_send_from is None:
session.add(SmsgAddress(addr=bid_addr, use_type=MessageTypes.BID))
session.commit()
finally:
session.close()
session.remove()
self.log.info('Sent BID %s', bid_id.hex())
return bid_id
@@ -1712,17 +1715,16 @@ class BasicSwap(BaseApp):
self.mxDB.release()
def list_bid_events(self, bid_id, session):
session = scoped_session(self.session_factory)
query_str = 'SELECT created_at, event_type, event_msg FROM eventlog ' + \
'WHERE active_ind = 1 AND linked_type = {} AND linked_id = x\'{}\' '.format(TableTypes.BID, bid_id.hex())
q = self.engine.execute(query_str)
q = session.execute(query_str)
events = []
for row in q:
events.append({'at': row[0], 'desc': describeEventEntry(row[1], row[2])})
query_str = 'SELECT created_at, trigger_at FROM eventqueue ' + \
'WHERE active_ind = 1 AND linked_id = x\'{}\' '.format(bid_id.hex())
q = self.engine.execute(query_str)
q = session.execute(query_str)
events = []
for row in q:
events.append({'at': row[0], 'desc': 'Delaying until: {}'.format(format_timestamp(row[1]))})
@@ -1736,13 +1738,13 @@ class BasicSwap(BaseApp):
assert(bid), 'Bid not found'
assert(offer), 'Offer not found'
if offer.swap_type == SwapTypes.XMR_SWAP:
return self.acceptXmrBid(bid_id)
# Ensure bid is still valid
now = int(time.time())
assert(bid.expire_at > now), 'Bid expired'
assert(bid.state == BidStates.BID_RECEIVED), 'Wrong bid state: {}'.format(BidStates(bid.state))
assert(bid.state == BidStates.BID_RECEIVED), 'Wrong bid state: {}'.format(str(BidStates(bid.state)))
if offer.swap_type == SwapTypes.XMR_SWAP:
return self.acceptXmrBid(bid_id)
if bid.contract_count is None:
bid.contract_count = self.getNewContractId()
@@ -1934,13 +1936,15 @@ class BasicSwap(BaseApp):
)
bid.setState(BidStates.BID_SENT)
session = scoped_session(self.session_factory)
self.saveBidInSession(xmr_swap.bid_id, bid, session, xmr_swap)
if addr_send_from is None:
session.add(SmsgAddress(addr=bid_addr, use_type=MessageTypes.BID))
session.commit()
session.close()
session.remove()
try:
session = scoped_session(self.session_factory)
self.saveBidInSession(xmr_swap.bid_id, bid, session, xmr_swap)
if addr_send_from is None:
session.add(SmsgAddress(addr=bid_addr, use_type=MessageTypes.BID))
session.commit()
finally:
session.close()
session.remove()
self.log.info('Sent XMR_BID_FL %s', xmr_swap.bid_id.hex())
return xmr_swap.bid_id
@@ -1957,7 +1961,8 @@ class BasicSwap(BaseApp):
bid, xmr_swap = self.getXmrBid(bid_id)
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid_id.hex())
assert(bid.expire_at > now), 'Offer has expired'
assert(bid.expire_at > now), 'Bid expired'
assert(bid.state == BidStates.BID_RECEIVED), 'Wrong bid state: {}'.format(str(BidStates(bid.state)))
offer, xmr_offer = self.getXmrOffer(bid.offer_id)
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
@@ -2066,11 +2071,7 @@ class BasicSwap(BaseApp):
bid.setState(BidStates.BID_ACCEPTED)
session = scoped_session(self.session_factory)
self.saveBidInSession(bid_id, bid, session, xmr_swap)
session.commit()
session.close()
session.remove()
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
# Add to swaps_in_progress only when waiting on txns
self.log.info('Sent XMR_BID_ACCEPT_LF %s', bid_id.hex())
@@ -3182,7 +3183,7 @@ class BasicSwap(BaseApp):
self.initiateTxnSpent(watched_output.bid_id, spend_txid_hex, spend_n, spend_txn)
def checkForSpends(self, coin_type, c):
# assert(self.mxDB.locked()) self.log.debug('checkForSpends %s', coin_type)
# assert(self.mxDB.locked())
self.log.debug('checkForSpends %s', coin_type)
if coin_type == Coins.PART and self.coin_clients[coin_type]['have_spent_index']:
@@ -3236,11 +3237,18 @@ class BasicSwap(BaseApp):
now = int(time.time())
options = {'encoding': 'none'}
ro = self.callrpc('smsginbox', ['all', '', options])
num_messages = 0
num_removed = 0
for msg in ro['messages']:
expire_at = msg['sent'] + msg['daysretention'] * self.SMSG_SECONDS_IN_DAY
num_messages += 1
expire_at = msg['sent'] + msg['ttl']
if expire_at < now:
options = {'encoding': 'none', 'delete': True}
del_msg = self.callrpc('smsg', [msg['msgid'], options])
num_removed += 1
if num_messages + num_removed > 0:
logging.info('Expired {} / {} messages.'.format(num_removed, num_messages))
logging.debug('TODO: Expire records from db')
@@ -3303,7 +3311,7 @@ class BasicSwap(BaseApp):
session = scoped_session(self.session_factory)
q = session.query(Bid).filter(Bid.state == BidStates.BID_RECEIVING)
for bid in q:
q = self.engine.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {}'.format(bid.bid_id.hex(), XmrSplitMsgTypes.BID)).first()
q = session.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {}'.format(bid.bid_id.hex(), XmrSplitMsgTypes.BID)).first()
num_segments = q[0]
if num_segments > 1:
try:
@@ -3321,7 +3329,7 @@ class BasicSwap(BaseApp):
q = session.query(Bid).filter(Bid.state == BidStates.BID_RECEIVING_ACC)
for bid in q:
q = self.engine.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {}'.format(bid.bid_id.hex(), XmrSplitMsgTypes.BID_ACCEPT)).first()
q = session.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {}'.format(bid.bid_id.hex(), XmrSplitMsgTypes.BID_ACCEPT)).first()
num_segments = q[0]
if num_segments > 1:
try:
@@ -3330,6 +3338,7 @@ class BasicSwap(BaseApp):
self.log.info('Verify xmr bid accept {} failed: {}'.format(bid.bid_id.hex(), str(ex)))
bid.setState(BidStates.BID_ERROR, 'Failed accept validation: ' + str(ex))
session.add(bid)
self.updateBidInProgress(bid)
continue
if bid.created_at + ttl_xmr_split_messages < now:
self.log.debug('Expiring partially received bid accept: {}'.format(bid.bid_id.hex()))
@@ -3388,49 +3397,51 @@ class BasicSwap(BaseApp):
raise ValueError('Offer has been revoked {}.'.format(offer_id.hex()))
session = scoped_session(self.session_factory)
# Check for sent
existing_offer = self.getOffer(offer_id)
if existing_offer is None:
offer = Offer(
offer_id=offer_id,
active_ind=1,
try:
# Check for sent
existing_offer = self.getOffer(offer_id)
if existing_offer is None:
offer = Offer(
offer_id=offer_id,
active_ind=1,
coin_from=offer_data.coin_from,
coin_to=offer_data.coin_to,
amount_from=offer_data.amount_from,
rate=offer_data.rate,
min_bid_amount=offer_data.min_bid_amount,
time_valid=offer_data.time_valid,
lock_type=int(offer_data.lock_type),
lock_value=offer_data.lock_value,
swap_type=offer_data.swap_type,
coin_from=offer_data.coin_from,
coin_to=offer_data.coin_to,
amount_from=offer_data.amount_from,
rate=offer_data.rate,
min_bid_amount=offer_data.min_bid_amount,
time_valid=offer_data.time_valid,
lock_type=int(offer_data.lock_type),
lock_value=offer_data.lock_value,
swap_type=offer_data.swap_type,
addr_from=msg['from'],
created_at=msg['sent'],
expire_at=msg['sent'] + offer_data.time_valid,
was_sent=False)
offer.setState(OfferStates.OFFER_RECEIVED)
session.add(offer)
addr_from=msg['from'],
created_at=msg['sent'],
expire_at=msg['sent'] + offer_data.time_valid,
was_sent=False)
offer.setState(OfferStates.OFFER_RECEIVED)
session.add(offer)
if offer.swap_type == SwapTypes.XMR_SWAP:
xmr_offer = XmrOffer()
if offer.swap_type == SwapTypes.XMR_SWAP:
xmr_offer = XmrOffer()
xmr_offer.offer_id = offer_id
xmr_offer.lock_time_1 = getExpectedSequence(offer_data.lock_type, offer_data.lock_value, coin_from)
xmr_offer.lock_time_2 = getExpectedSequence(offer_data.lock_type, offer_data.lock_value, coin_from)
xmr_offer.offer_id = offer_id
xmr_offer.lock_time_1 = getExpectedSequence(offer_data.lock_type, offer_data.lock_value, coin_from)
xmr_offer.lock_time_2 = getExpectedSequence(offer_data.lock_type, offer_data.lock_value, coin_from)
xmr_offer.a_fee_rate = offer_data.fee_rate_from
xmr_offer.b_fee_rate = offer_data.fee_rate_to
xmr_offer.a_fee_rate = offer_data.fee_rate_from
xmr_offer.b_fee_rate = offer_data.fee_rate_to
session.add(xmr_offer)
session.add(xmr_offer)
self.log.debug('Received new offer %s', offer_id.hex())
else:
existing_offer.setState(OfferStates.OFFER_RECEIVED)
session.add(existing_offer)
session.commit()
session.close()
session.remove()
self.log.debug('Received new offer %s', offer_id.hex())
else:
existing_offer.setState(OfferStates.OFFER_RECEIVED)
session.add(existing_offer)
session.commit()
finally:
session.close()
session.remove()
def processOfferRevoke(self, msg):
assert(msg['to'] == self.network_addr), 'Message received on wrong address'
@@ -3540,6 +3551,7 @@ class BasicSwap(BaseApp):
was_received=True,
)
else:
assert(bid.state == BidStates.BID_SENT), 'Wrong bid state: {}'.format(str(BidStates(bid.state)))
bid.created_at = msg['sent']
bid.expire_at = msg['sent'] + bid_data.time_valid
bid.was_received = True
@@ -3585,7 +3597,7 @@ class BasicSwap(BaseApp):
if bid.was_received: # Sent to self
self.log.info('Received valid bid accept %s for bid %s sent to self', bid.accept_msg_id.hex(), bid_id.hex())
return
raise ValueError('Wrong bid state: {}'.format(str(BidStates(bid.state))))
raise ValueError('Wrong bid state: {}'.format(str(BidStates(str(BidStates(bid.state))))))
use_csv = True if offer.lock_type < ABS_LOCK_BLOCKS else False
@@ -3784,6 +3796,7 @@ class BasicSwap(BaseApp):
xmr_swap.b_restore_height = ci_to._restore_height
self.log.warning('XMR swap restore height clamped to {}'.format(ci_to._restore_height))
else:
assert(bid.state == BidStates.BID_SENT), 'Wrong bid state: {}'.format(str(BidStates(bid.state)))
bid.created_at = msg['sent']
bid.expire_at = msg['sent'] + bid_data.time_valid
bid.was_received = True
@@ -4336,13 +4349,25 @@ class BasicSwap(BaseApp):
assert(len(msg_data.msg_id) == 28), 'Bad msg_id length'
if msg_data.msg_type == XmrSplitMsgTypes.BID or msg_data.msg_type == XmrSplitMsgTypes.BID_ACCEPT:
dbr = XmrSplitData()
dbr.bid_id = msg_data.msg_id
dbr.msg_type = msg_data.msg_type
dbr.msg_sequence = msg_data.sequence
dbr.dleag = msg_data.dleag
dbr.created_at = now
self.saveToDB(dbr)
try:
session = scoped_session(self.session_factory)
q = session.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {} AND msg_sequence = {}'.format(msg_data.msg_id.hex(), msg_data.msg_type, msg_data.sequence)).first()
num_exists = q[0]
if num_exists > 0:
self.log.warning('Ignoring duplicate xmr_split_data entry: ({}, {}, {})'.format(msg_data.msg_id.hex(), msg_data.msg_type, msg_data.sequence))
return
dbr = XmrSplitData()
dbr.bid_id = msg_data.msg_id
dbr.msg_type = msg_data.msg_type
dbr.msg_sequence = msg_data.sequence
dbr.dleag = msg_data.dleag
dbr.created_at = now
session.add(dbr)
session.commit()
finally:
session.close()
session.remove()
def processXmrLockReleaseMessage(self, msg):
self.log.debug('Processing xmr secret msg %s', msg['msgid'])
@@ -4640,9 +4665,9 @@ class BasicSwap(BaseApp):
try:
session = scoped_session(self.session_factory)
if offer_id:
q = self.engine.execute('SELECT COUNT(*) FROM bids WHERE state >= {} AND offer_id = x\'{}\''.format(BidStates.BID_ACCEPTED, offer_id.hex())).first()
q = session.execute('SELECT COUNT(*) FROM bids WHERE state >= {} AND offer_id = x\'{}\''.format(BidStates.BID_ACCEPTED, offer_id.hex())).first()
else:
q = self.engine.execute('SELECT COUNT(*) FROM bids WHERE state >= {}'.format(BidStates.BID_ACCEPTED)).first()
q = session.execute('SELECT COUNT(*) FROM bids WHERE state >= {}'.format(BidStates.BID_ACCEPTED)).first()
return q[0]
finally:
session.close()
@@ -4712,7 +4737,7 @@ class BasicSwap(BaseApp):
query_str += 'WHERE bids.was_received = 1 '
query_str += 'ORDER BY bids.created_at DESC'
q = self.engine.execute(query_str)
q = session.execute(query_str)
for row in q:
rv.append(row)
return rv
@@ -4751,7 +4776,7 @@ class BasicSwap(BaseApp):
try:
session = scoped_session(self.session_factory)
rv = []
q = self.engine.execute('SELECT addr FROM smsgaddresses WHERE use_type = {} ORDER BY addr_id DESC'.format(use_type))
q = session.execute('SELECT addr FROM smsgaddresses WHERE use_type = {} ORDER BY addr_id DESC'.format(use_type))
for row in q:
rv.append(row[0])
return rv

View File

@@ -330,6 +330,8 @@ class XmrSplitData(Base):
dleag = sa.Column(sa.LargeBinary)
created_at = sa.Column(sa.BigInteger)
__table_args__ = (sa.UniqueConstraint('bid_id', 'msg_type', 'msg_sequence', name='uc_1'),)
class RevokedMessage(Base):
__tablename__ = 'revoked_messages'

View File

@@ -39,6 +39,7 @@ from .js_server import (
js_bids,
js_sentbids,
js_network,
js_revokeoffer,
js_index,
)
from .ui import (
@@ -821,6 +822,7 @@ class HttpHandler(BaseHTTPRequestHandler):
'bids': js_bids,
'sentbids': js_sentbids,
'network': js_network,
'revokeoffer': js_revokeoffer,
}.get(url_split[2], js_index)
return func(self, url_split, post_string)
except Exception as ex:

View File

@@ -117,7 +117,7 @@ class BTCInterface(CoinInterface):
def __init__(self, coin_settings, network):
super().__init__()
rpc_host = coin_settings.get('rpchost', 'localhost')
rpc_host = coin_settings.get('rpchost', '127.0.0.1')
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host)
self.txoType = CTxOut
self._network = network

View File

@@ -36,7 +36,7 @@ class PARTInterface(BTCInterface):
return 213
def __init__(self, coin_settings, network):
rpc_host = coin_settings.get('rpchost', 'localhost')
rpc_host = coin_settings.get('rpchost', '127.0.0.1')
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host)
self.txoType = CTxOutPart
self._network = network

View File

@@ -57,8 +57,8 @@ class XMRInterface(CoinInterface):
def __init__(self, coin_settings, network):
super().__init__()
self.rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', 'localhost'))
self.rpc_cb2 = make_xmr_rpc2_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', 'localhost')) # non-json endpoint
self.rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', '127.0.0.1'))
self.rpc_cb2 = make_xmr_rpc2_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', '127.0.0.1')) # non-json endpoint
self.rpc_wallet_cb = make_xmr_wallet_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'])
self._network = network

View File

@@ -34,6 +34,7 @@ def js_wallets(self, url_split, post_string):
def js_offers(self, url_split, post_string, sent=False):
offer_id = None
if len(url_split) > 3:
if url_split[3] == 'new':
if post_string == '':
@@ -52,6 +53,10 @@ def js_offers(self, url_split, post_string, sent=False):
'sort_by': 'created_at',
'sort_dir': 'desc',
}
if offer_id:
filters['offer_id'] = offer_id
if post_string != '':
post_data = urllib.parse.parse_qs(post_string)
filters['coin_from'] = setCoinFilter(form_data, b'coin_from')
@@ -160,5 +165,12 @@ def js_network(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.get_network_info()), 'UTF-8')
def js_revokeoffer(self, url_split, post_string):
offer_id = bytes.fromhex(url_split[3])
assert(len(offer_id) == 28)
self.server.swap_client.revokeOffer(offer_id)
return bytes(json.dumps({'revoked_offer': offer_id.hex()}), 'UTF-8')
def js_index(self, url_split, post_string):
return bytes(json.dumps(self.server.swap_client.getSummary()), 'UTF-8')