Raise max signature size for fee estimate.

Fix logging.
Valid sequence lock range settings.
Bid debugind can be set through api.
This commit is contained in:
tecnovert 2021-01-30 01:45:24 +02:00
parent 4ea4e0656a
commit 2e0edef9da
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
9 changed files with 149 additions and 101 deletions

View file

@ -1,3 +1,3 @@
name = "basicswap" name = "basicswap"
__version__ = "0.0.13" __version__ = "0.0.14"

View file

@ -14,7 +14,6 @@ import random
import shutil import shutil
import struct import struct
import hashlib import hashlib
import logging
import secrets import secrets
import datetime as dt import datetime as dt
import traceback import traceback
@ -200,6 +199,7 @@ class EventLogTypes(IntEnum):
LOCK_TX_A_CONFIRMED = auto() LOCK_TX_A_CONFIRMED = auto()
LOCK_TX_B_SEEN = auto() LOCK_TX_B_SEEN = auto()
LOCK_TX_B_CONFIRMED = auto() LOCK_TX_B_CONFIRMED = auto()
DEBUG_TWEAK_APPLIED = auto()
class XmrSplitMsgTypes(IntEnum): class XmrSplitMsgTypes(IntEnum):
@ -342,6 +342,8 @@ def describeEventEntry(event_type, event_msg):
return 'Lock tx b seen in chain' return 'Lock tx b seen in chain'
if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED: if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED:
return 'Lock tx b confirmed in chain' return 'Lock tx b confirmed in chain'
if event_type == EventLogTypes.DEBUG_TWEAK_APPLIED:
return 'Debug tweak applied ' + event_msg
def getExpectedSequence(lockType, lockVal, coin_type): def getExpectedSequence(lockType, lockVal, coin_type):
@ -445,6 +447,9 @@ class BasicSwap(BaseApp):
self.min_delay_retry = self.settings.get('min_delay_retry', 60) self.min_delay_retry = self.settings.get('min_delay_retry', 60)
self.max_delay_retry = self.settings.get('max_delay_retry', 5 * 60) self.max_delay_retry = self.settings.get('max_delay_retry', 5 * 60)
self.min_sequence_lock_seconds = self.settings.get('min_sequence_lock_seconds', 1 * 60 * 60)
self.max_sequence_lock_seconds = self.settings.get('max_sequence_lock_seconds', 96 * 60 * 60)
self._bid_expired_leeway = 5 self._bid_expired_leeway = 5
self.swaps_in_progress = dict() self.swaps_in_progress = dict()
@ -595,15 +600,15 @@ class BasicSwap(BaseApp):
def createInterface(self, coin): def createInterface(self, coin):
if coin == Coins.PART: if coin == Coins.PART:
return PARTInterface(self.coin_clients[coin], self.chain) return PARTInterface(self.coin_clients[coin], self.chain, self)
elif coin == Coins.BTC: elif coin == Coins.BTC:
return BTCInterface(self.coin_clients[coin], self.chain) return BTCInterface(self.coin_clients[coin], self.chain, self)
elif coin == Coins.LTC: elif coin == Coins.LTC:
return LTCInterface(self.coin_clients[coin], self.chain) return LTCInterface(self.coin_clients[coin], self.chain, self)
elif coin == Coins.NMC: elif coin == Coins.NMC:
return NMCInterface(self.coin_clients[coin], self.chain) return NMCInterface(self.coin_clients[coin], self.chain, self)
elif coin == Coins.XMR: elif coin == Coins.XMR:
xmr_i = XMRInterface(self.coin_clients[coin], self.chain) xmr_i = XMRInterface(self.coin_clients[coin], self.chain, self)
chain_client_settings = self.getChainClientSettings(coin) chain_client_settings = self.getChainClientSettings(coin)
xmr_i.setWalletFilename(chain_client_settings['walletfile']) xmr_i.setWalletFilename(chain_client_settings['walletfile'])
return xmr_i return xmr_i
@ -735,6 +740,20 @@ class BasicSwap(BaseApp):
self.log.info('Upgrading database from version %d to %d.', db_version, CURRENT_DB_VERSION) self.log.info('Upgrading database from version %d to %d.', db_version, CURRENT_DB_VERSION)
while True: while True:
if db_version == 6:
session = scoped_session(self.session_factory)
session.execute('ALTER TABLE bids ADD COLUMN security_token BLOB')
session.execute('ALTER TABLE offers ADD COLUMN security_token BLOB')
db_version += 1
self.db_version = db_version
self.setIntKVInSession('db_version', db_version, session)
session.commit()
session.close()
session.remove()
self.log.info('Upgraded database to version {}'.format(self.db_version))
continue
if db_version == 4: if db_version == 4:
session = scoped_session(self.session_factory) session = scoped_session(self.session_factory)
@ -743,12 +762,7 @@ class BasicSwap(BaseApp):
db_version += 1 db_version += 1
self.db_version = db_version self.db_version = db_version
kv = session.query(DBKVInt).filter_by(key='db_version').first() self.setIntKVInSession('db_version', db_version, session)
if not kv:
kv = DBKVInt(key='db_version', value=db_version)
else:
kv.value = db_version
session.add(kv)
session.commit() session.commit()
session.close() session.close()
session.remove() session.remove()
@ -804,16 +818,19 @@ class BasicSwap(BaseApp):
key_str = 'main_wallet_seedid_' + chainparams[coin_type]['name'] key_str = 'main_wallet_seedid_' + chainparams[coin_type]['name']
self.setStringKV(key_str, root_hash.hex()) self.setStringKV(key_str, root_hash.hex())
def setIntKV(self, str_key, int_val): def setIntKVInSession(self, str_key, int_val, session):
self.mxDB.acquire()
try:
session = scoped_session(self.session_factory)
kv = session.query(DBKVInt).filter_by(key=str_key).first() kv = session.query(DBKVInt).filter_by(key=str_key).first()
if not kv: if not kv:
kv = DBKVInt(key=str_key, value=int_val) kv = DBKVInt(key=str_key, value=int_val)
else: else:
kv.value = int_val kv.value = int_val
session.add(kv) session.add(kv)
def setIntKV(self, str_key, int_val):
self.mxDB.acquire()
try:
session = scoped_session(self.session_factory)
self.setIntKVInSession(str_key, int_val, session)
session.commit() session.commit()
finally: finally:
session.close() session.close()
@ -1004,7 +1021,7 @@ class BasicSwap(BaseApp):
def validateOfferLockValue(self, coin_from, coin_to, lock_type, lock_value): def validateOfferLockValue(self, coin_from, coin_to, lock_type, lock_value):
if lock_type == OfferMessage.SEQUENCE_LOCK_TIME: if lock_type == OfferMessage.SEQUENCE_LOCK_TIME:
assert(lock_value >= 1 * 60 * 60 and lock_value <= 96 * 60 * 60), 'Invalid lock_value time' assert(lock_value >= self.min_sequence_lock_seconds and lock_value <= self.max_sequence_lock_seconds), 'Invalid lock_value time'
assert(self.coin_clients[coin_from]['use_csv'] and self.coin_clients[coin_to]['use_csv']), 'Both coins need CSV activated.' assert(self.coin_clients[coin_from]['use_csv'] and self.coin_clients[coin_to]['use_csv']), 'Both coins need CSV activated.'
elif lock_type == OfferMessage.SEQUENCE_LOCK_BLOCKS: elif lock_type == OfferMessage.SEQUENCE_LOCK_BLOCKS:
assert(lock_value >= 5 and lock_value <= 1000), 'Invalid lock_value blocks' assert(lock_value >= 5 and lock_value <= 1000), 'Invalid lock_value blocks'
@ -1109,6 +1126,10 @@ class BasicSwap(BaseApp):
offer_id = bytes.fromhex(msg_id) offer_id = bytes.fromhex(msg_id)
security_token = extra_options.get('security_token', None)
if security_token is not None and len(security_token) != 20:
raise ValueError('Security token must be 20 bytes long.')
session = scoped_session(self.session_factory) session = scoped_session(self.session_factory)
offer = Offer( offer = Offer(
offer_id=offer_id, offer_id=offer_id,
@ -1128,7 +1149,8 @@ class BasicSwap(BaseApp):
created_at=offer_created_at, created_at=offer_created_at,
expire_at=offer_created_at + 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,
security_token=security_token)
offer.setState(OfferStates.OFFER_SENT) offer.setState(OfferStates.OFFER_SENT)
if swap_type == SwapTypes.XMR_SWAP: if swap_type == SwapTypes.XMR_SWAP:
@ -1149,7 +1171,7 @@ class BasicSwap(BaseApp):
self.log.info('Sent OFFER %s', offer_id.hex()) self.log.info('Sent OFFER %s', offer_id.hex())
return offer_id return offer_id
def revokeOffer(self, offer_id): def revokeOffer(self, offer_id, security_token=None):
self.log.info('Revoking offer %s', offer_id.hex()) self.log.info('Revoking offer %s', offer_id.hex())
session = None session = None
@ -1159,6 +1181,9 @@ class BasicSwap(BaseApp):
offer = session.query(Offer).filter_by(offer_id=offer_id).first() offer = session.query(Offer).filter_by(offer_id=offer_id).first()
if len(offer.security_token > 0) and offer.security_token != security_token:
raise ValueError('Mismatched security token')
msg_buf = OfferRevokeMessage() msg_buf = OfferRevokeMessage()
msg_buf.offer_msg_id = offer_id msg_buf.offer_msg_id = offer_id
@ -2652,7 +2677,7 @@ class BasicSwap(BaseApp):
self.saveBidInSession(bid_id, bid, session, xmr_swap) self.saveBidInSession(bid_id, bid, session, xmr_swap)
session.commit() session.commit()
except Exception as ex: except Exception as ex:
logging.debug('Trying to publish coin a lock refund spend tx: %s', str(ex)) self.log.debug('Trying to publish coin a lock refund spend tx: %s', str(ex))
if bid.was_sent: if bid.was_sent:
if xmr_swap.a_lock_refund_swipe_tx is None: if xmr_swap.a_lock_refund_swipe_tx is None:
@ -2672,7 +2697,7 @@ class BasicSwap(BaseApp):
self.saveBidInSession(bid_id, bid, session, xmr_swap) self.saveBidInSession(bid_id, bid, session, xmr_swap)
session.commit() session.commit()
except Exception as ex: except Exception as ex:
logging.debug('Trying to publish coin a lock refund swipe tx: %s', str(ex)) self.log.debug('Trying to publish coin a lock refund swipe tx: %s', str(ex))
if BidStates(bid.state) == BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED: if BidStates(bid.state) == BidStates.XMR_SWAP_NOSCRIPT_TX_RECOVERED:
txid_hex = bid.xmr_b_lock_tx.spend_txid.hex() txid_hex = bid.xmr_b_lock_tx.spend_txid.hex()
@ -3271,9 +3296,9 @@ class BasicSwap(BaseApp):
num_removed += 1 num_removed += 1
if num_messages + num_removed > 0: if num_messages + num_removed > 0:
logging.info('Expired {} / {} messages.'.format(num_removed, num_messages)) self.log.info('Expired {} / {} messages.'.format(num_removed, num_messages))
logging.debug('TODO: Expire records from db') self.log.debug('TODO: Expire records from db')
finally: finally:
self.mxDB.release() self.mxDB.release()
@ -3410,7 +3435,7 @@ class BasicSwap(BaseApp):
elif offer_data.swap_type == SwapTypes.XMR_SWAP: elif offer_data.swap_type == SwapTypes.XMR_SWAP:
assert(coin_from != Coins.XMR) assert(coin_from != Coins.XMR)
assert(coin_to == Coins.XMR) assert(coin_to == Coins.XMR)
logging.debug('TODO - More restrictions') self.log.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))
@ -3788,7 +3813,7 @@ class BasicSwap(BaseApp):
ci_from = self.ci(Coins(offer.coin_from)) ci_from = self.ci(Coins(offer.coin_from))
ci_to = self.ci(Coins(offer.coin_to)) ci_to = self.ci(Coins(offer.coin_to))
logging.debug('TODO: xmr bid validation') self.log.debug('TODO: xmr bid validation')
assert(ci_to.verifyKey(bid_data.kbvf)) assert(ci_to.verifyKey(bid_data.kbvf))
assert(ci_from.verifyPubkey(bid_data.pkaf)) assert(ci_from.verifyPubkey(bid_data.pkaf))
@ -3892,7 +3917,7 @@ class BasicSwap(BaseApp):
xmr_swap.a_swap_refund_value, xmr_offer.a_fee_rate xmr_swap.a_swap_refund_value, xmr_offer.a_fee_rate
) )
logging.info('Checking leader\'s lock refund tx signature') self.log.info('Checking leader\'s lock refund tx signature')
v = ci_from.verifyTxSig(xmr_swap.a_lock_refund_tx, xmr_swap.al_lock_refund_tx_sig, xmr_swap.pkal, 0, xmr_swap.a_lock_tx_script, bid.amount) v = ci_from.verifyTxSig(xmr_swap.a_lock_refund_tx, xmr_swap.al_lock_refund_tx_sig, xmr_swap.pkal, 0, xmr_swap.a_lock_tx_script, bid.amount)
bid.setState(BidStates.BID_RECEIVING_ACC) bid.setState(BidStates.BID_RECEIVING_ACC)
@ -4056,7 +4081,9 @@ class BasicSwap(BaseApp):
if bid.debug_ind == DebugTypes.BID_STOP_AFTER_COIN_A_LOCK: if bid.debug_ind == DebugTypes.BID_STOP_AFTER_COIN_A_LOCK:
self.log.debug('XMR bid %s: Abandoning bid for testing: %d.', bid_id.hex(), bid.debug_ind) self.log.debug('XMR bid %s: Abandoning bid for testing: %d.', bid_id.hex(), bid.debug_ind)
# bid.setState(BidStates.BID_ABANDONED) # TODO: Retry if state bid.setState(BidStates.BID_ABANDONED)
self.saveBidInSession(bid_id, bid, session, xmr_swap, save_in_progress=offer)
self.logBidEvent(bid, EventLogTypes.DEBUG_TWEAK_APPLIED, 'ind {}'.format(bid.debug_ind), session)
return return
if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK: if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK:

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2019-2020 tecnovert # Copyright (c) 2019-2021 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.
@ -12,7 +12,7 @@ from sqlalchemy.ext.declarative import declarative_base
from enum import IntEnum, auto from enum import IntEnum, auto
CURRENT_DB_VERSION = 6 CURRENT_DB_VERSION = 7
Base = declarative_base() Base = declarative_base()
@ -62,6 +62,7 @@ class Offer(Base):
# Local fields # Local fields
auto_accept_bids = sa.Column(sa.Boolean) auto_accept_bids = sa.Column(sa.Boolean)
withdraw_to_addr = sa.Column(sa.String) # Address to spend lock tx to - address from wallet if empty TODO withdraw_to_addr = sa.Column(sa.String) # Address to spend lock tx to - address from wallet if empty TODO
security_token = sa.Column(sa.LargeBinary)
state = sa.Column(sa.Integer) state = sa.Column(sa.Integer)
states = sa.Column(sa.LargeBinary) # Packed states and times states = sa.Column(sa.LargeBinary) # Packed states and times
@ -114,6 +115,7 @@ class Bid(Base):
state_note = sa.Column(sa.String) state_note = sa.Column(sa.String)
debug_ind = sa.Column(sa.Integer) debug_ind = sa.Column(sa.Integer)
security_token = sa.Column(sa.LargeBinary)
initiate_tx = None initiate_tx = None
participate_tx = None participate_tx = None

View file

@ -393,6 +393,8 @@ class HttpHandler(BaseHTTPRequestHandler):
if have_data_entry(form_data, 'lockhrs'): if have_data_entry(form_data, 'lockhrs'):
page_data['lockhrs'] = int(get_data_entry(form_data, 'lockhrs')) page_data['lockhrs'] = int(get_data_entry(form_data, 'lockhrs'))
parsed_data['lock_seconds'] = page_data['lockhrs'] * 60 * 60 parsed_data['lock_seconds'] = page_data['lockhrs'] * 60 * 60
elif have_data_entry(form_data, 'lockseconds'):
parsed_data['lock_seconds'] = int(get_data_entry(form_data, 'lockseconds'))
page_data['autoaccept'] = True if have_data_entry(form_data, 'autoaccept') else False page_data['autoaccept'] = True if have_data_entry(form_data, 'autoaccept') else False
parsed_data['autoaccept'] = page_data['autoaccept'] parsed_data['autoaccept'] = page_data['autoaccept']

View file

@ -117,14 +117,19 @@ class BTCInterface(CoinInterface):
def xmr_swap_alock_spend_tx_vsize(): def xmr_swap_alock_spend_tx_vsize():
return 147 return 147
def __init__(self, coin_settings, network): @staticmethod
def txoType():
return CTxOut
def __init__(self, coin_settings, network, swap_client=None):
super().__init__() super().__init__()
rpc_host = coin_settings.get('rpchost', '127.0.0.1') 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.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host)
self.txoType = CTxOut
self._network = network self._network = network
self.blocks_confirmed = coin_settings['blocks_confirmed'] self.blocks_confirmed = coin_settings['blocks_confirmed']
self.setConfTarget(coin_settings['conf_target']) self.setConfTarget(coin_settings['conf_target'])
self._sc = swap_client
self._log = self._sc.log if self._sc.log else logging
def setConfTarget(self, new_conf_target): def setConfTarget(self, new_conf_target):
assert(new_conf_target >= 1 and new_conf_target < 33), 'Invalid conf_target value' assert(new_conf_target >= 1 and new_conf_target < 33), 'Invalid conf_target value'
@ -153,7 +158,7 @@ class BTCInterface(CoinInterface):
self.rpc_callback('sethdseed', [True, key_wif]) self.rpc_callback('sethdseed', [True, key_wif])
except Exception as e: except Exception as e:
# < 0.21: Cannot set a new HD seed while still in Initial Block Download. # < 0.21: Cannot set a new HD seed while still in Initial Block Download.
logging.error('sethdseed failed: {}'.format(str(e))) self._log.error('sethdseed failed: {}'.format(str(e)))
def getWalletInfo(self): def getWalletInfo(self):
return self.rpc_callback('getwalletinfo') return self.rpc_callback('getwalletinfo')
@ -252,7 +257,7 @@ class BTCInterface(CoinInterface):
script = self.genScriptLockTxScript(Kal, Kaf) script = self.genScriptLockTxScript(Kal, Kaf)
tx = CTransaction() tx = CTransaction()
tx.nVersion = self.txVersion() tx.nVersion = self.txVersion()
tx.vout.append(self.txoType(value, self.getScriptDest(script))) tx.vout.append(self.txoType()(value, self.getScriptDest(script)))
return tx.serialize(), script return tx.serialize(), script
@ -316,10 +321,10 @@ class BTCInterface(CoinInterface):
tx = CTransaction() tx = CTransaction()
tx.nVersion = self.txVersion() tx.nVersion = self.txVersion()
tx.vin.append(CTxIn(COutPoint(tx_lock_hash_int, locked_n), nSequence=lock1_value)) tx.vin.append(CTxIn(COutPoint(tx_lock_hash_int, locked_n), nSequence=lock1_value))
tx.vout.append(self.txoType(locked_coin, CScript([OP_0, hashlib.sha256(refund_script).digest()]))) tx.vout.append(self.txoType()(locked_coin, CScript([OP_0, hashlib.sha256(refund_script).digest()])))
witness_bytes = len(script_lock) witness_bytes = len(script_lock)
witness_bytes += 73 * 2 # 2 signatures (72 + 1 byts size) witness_bytes += 74 * 2 # 2 signatures (72 + 1 byte sighashtype + 1 byte size) - Use maximum txn size for estimate
witness_bytes += 2 # 2 empty witness stack values witness_bytes += 2 # 2 empty witness stack values
witness_bytes += getCompactSizeLen(witness_bytes) witness_bytes += getCompactSizeLen(witness_bytes)
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes) vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
@ -327,7 +332,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash() tx.rehash()
logging.info('createScriptLockRefundTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.', self._log.info('createScriptLockRefundTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee) i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
return tx.serialize(), refund_script, tx.vout[0].nValue return tx.serialize(), refund_script, tx.vout[0].nValue
@ -351,7 +356,7 @@ class BTCInterface(CoinInterface):
tx.nVersion = self.txVersion() tx.nVersion = self.txVersion()
tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=0)) tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=0))
tx.vout.append(self.txoType(locked_coin, self.getScriptForPubkeyHash(pkh_refund_to))) tx.vout.append(self.txoType()(locked_coin, self.getScriptForPubkeyHash(pkh_refund_to)))
witness_bytes = len(script_lock_refund) witness_bytes = len(script_lock_refund)
witness_bytes += 73 * 2 # 2 signatures (72 + 1 byte size) witness_bytes += 73 * 2 # 2 signatures (72 + 1 byte size)
@ -362,7 +367,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash() tx.rehash()
logging.info('createScriptLockRefundSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.', self._log.info('createScriptLockRefundSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee) i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
return tx.serialize() return tx.serialize()
@ -386,7 +391,7 @@ class BTCInterface(CoinInterface):
tx.nVersion = self.txVersion() tx.nVersion = self.txVersion()
tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=lock2_value)) tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=lock2_value))
tx.vout.append(self.txoType(locked_coin, self.getScriptForPubkeyHash(pkh_dest))) tx.vout.append(self.txoType()(locked_coin, self.getScriptForPubkeyHash(pkh_dest)))
witness_bytes = len(script_lock_refund) witness_bytes = len(script_lock_refund)
witness_bytes += 73 # signature (72 + 1 byte size) witness_bytes += 73 # signature (72 + 1 byte size)
@ -397,7 +402,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash() tx.rehash()
logging.info('createScriptLockRefundSpendToFTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.', self._log.info('createScriptLockRefundSpendToFTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee) i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
return tx.serialize() return tx.serialize()
@ -416,7 +421,7 @@ class BTCInterface(CoinInterface):
tx.nVersion = self.txVersion() tx.nVersion = self.txVersion()
tx.vin.append(CTxIn(COutPoint(tx_lock_hash_int, locked_n))) tx.vin.append(CTxIn(COutPoint(tx_lock_hash_int, locked_n)))
tx.vout.append(self.txoType(locked_coin, self.getScriptForPubkeyHash(pkh_dest))) tx.vout.append(self.txoType()(locked_coin, self.getScriptForPubkeyHash(pkh_dest)))
witness_bytes = len(script_lock) witness_bytes = len(script_lock)
witness_bytes += 33 # sv, size witness_bytes += 33 # sv, size
@ -428,7 +433,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee tx.vout[0].nValue = locked_coin - pay_fee
tx.rehash() tx.rehash()
logging.info('createScriptLockSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.', self._log.info('createScriptLockSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee) i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
return tx.serialize() return tx.serialize()
@ -447,7 +452,7 @@ class BTCInterface(CoinInterface):
tx = self.loadTx(tx_bytes) tx = self.loadTx(tx_bytes)
tx_hash = self.getTxHash(tx) tx_hash = self.getTxHash(tx)
logging.info('Verifying lock tx: {}.'.format(b2h(tx_hash))) self._log.info('Verifying lock tx: {}.'.format(b2h(tx_hash)))
assert_cond(tx.nVersion == self.txVersion(), 'Bad version') assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
assert_cond(tx.nLockTime == 0, 'Bad nLockTime') assert_cond(tx.nLockTime == 0, 'Bad nLockTime')
@ -491,10 +496,10 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_bytes, add_witness_bytes) vsize = self.getTxVSize(tx, add_bytes, add_witness_bytes)
fee_rate_paid = fee_paid * 1000 / vsize fee_rate_paid = fee_paid * 1000 / vsize
logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid) self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
if not self.compareFeeRates(fee_rate_paid, feerate): if not self.compareFeeRates(fee_rate_paid, feerate):
logging.warning('feerate paid doesn\'t match expected: %ld, %ld', fee_rate_paid, feerate) self._log.warning('feerate paid doesn\'t match expected: %ld, %ld', fee_rate_paid, feerate)
# TODO: Display warning to user # TODO: Display warning to user
return tx_hash, locked_n return tx_hash, locked_n
@ -509,7 +514,7 @@ class BTCInterface(CoinInterface):
tx = self.loadTx(tx_bytes) tx = self.loadTx(tx_bytes)
tx_hash = self.getTxHash(tx) tx_hash = self.getTxHash(tx)
logging.info('Verifying lock refund tx: {}.'.format(b2h(tx_hash))) self._log.info('Verifying lock refund tx: {}.'.format(b2h(tx_hash)))
assert_cond(tx.nVersion == self.txVersion(), 'Bad version') assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
assert_cond(tx.nLockTime == 0, 'nLockTime not 0') assert_cond(tx.nLockTime == 0, 'nLockTime not 0')
@ -543,7 +548,7 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes) vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
fee_rate_paid = fee_paid * 1000 / vsize fee_rate_paid = fee_paid * 1000 / vsize
logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid) self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
if not self.compareFeeRates(fee_rate_paid, feerate): if not self.compareFeeRates(fee_rate_paid, feerate):
raise ValueError('Bad fee rate') raise ValueError('Bad fee rate')
@ -559,7 +564,7 @@ class BTCInterface(CoinInterface):
# Must have only one output sending lock refund tx value - fee to leader's address, TODO: follower shouldn't need to verify destination addr # Must have only one output sending lock refund tx value - fee to leader's address, TODO: follower shouldn't need to verify destination addr
tx = self.loadTx(tx_bytes) tx = self.loadTx(tx_bytes)
tx_hash = self.getTxHash(tx) tx_hash = self.getTxHash(tx)
logging.info('Verifying lock refund spend tx: {}.'.format(b2h(tx_hash))) self._log.info('Verifying lock refund spend tx: {}.'.format(b2h(tx_hash)))
assert_cond(tx.nVersion == self.txVersion(), 'Bad version') assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
assert_cond(tx.nLockTime == 0, 'nLockTime not 0') assert_cond(tx.nLockTime == 0, 'nLockTime not 0')
@ -589,7 +594,7 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes) vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
fee_rate_paid = fee_paid * 1000 / vsize fee_rate_paid = fee_paid * 1000 / vsize
logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx_value, vsize, fee_rate_paid) self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx_value, vsize, fee_rate_paid)
if not self.compareFeeRates(fee_rate_paid, feerate): if not self.compareFeeRates(fee_rate_paid, feerate):
raise ValueError('Bad fee rate') raise ValueError('Bad fee rate')
@ -605,7 +610,7 @@ class BTCInterface(CoinInterface):
tx = self.loadTx(tx_bytes) tx = self.loadTx(tx_bytes)
tx_hash = self.getTxHash(tx) tx_hash = self.getTxHash(tx)
logging.info('Verifying lock spend tx: {}.'.format(b2h(tx_hash))) self._log.info('Verifying lock spend tx: {}.'.format(b2h(tx_hash)))
assert_cond(tx.nVersion == self.txVersion(), 'Bad version') assert_cond(tx.nVersion == self.txVersion(), 'Bad version')
assert_cond(tx.nLockTime == 0, 'nLockTime not 0') assert_cond(tx.nLockTime == 0, 'nLockTime not 0')
@ -638,7 +643,7 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes) vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
fee_rate_paid = fee_paid * 1000 / vsize fee_rate_paid = fee_paid * 1000 / vsize
logging.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx.vout[0].nValue, vsize, fee_rate_paid) self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx.vout[0].nValue, vsize, fee_rate_paid)
if not self.compareFeeRates(fee_rate_paid, feerate): if not self.compareFeeRates(fee_rate_paid, feerate):
raise ValueError('Bad fee rate') raise ValueError('Bad fee rate')
@ -768,7 +773,7 @@ class BTCInterface(CoinInterface):
tx = CTransaction() tx = CTransaction()
tx.nVersion = self.txVersion() tx.nVersion = self.txVersion()
p2wpkh = self.getPkDest(Kbs) p2wpkh = self.getPkDest(Kbs)
tx.vout.append(self.txoType(output_amount, p2wpkh)) tx.vout.append(self.txoType()(output_amount, p2wpkh))
return tx.serialize() return tx.serialize()
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate): def publishBLockTx(self, Kbv, Kbs, output_amount, feerate):
@ -799,7 +804,7 @@ class BTCInterface(CoinInterface):
for utxo in rv['unspents']: for utxo in rv['unspents']:
if 'height' in utxo and utxo['height'] > 0 and rv['height'] - utxo['height'] > cb_block_confirmed: if 'height' in utxo and utxo['height'] > 0 and rv['height'] - utxo['height'] > cb_block_confirmed:
if self.make_int(utxo['amount']) != cb_swap_value: if self.make_int(utxo['amount']) != cb_swap_value:
logging.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount'])) self._log.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount']))
else: else:
return {'txid': utxo['txid'], 'vout': utxo['vout'], 'amount': utxo['amount'], 'height': utxo['height']} return {'txid': utxo['txid'], 'vout': utxo['vout'], 'amount': utxo['amount'], 'height': utxo['height']}
return None return None
@ -817,7 +822,7 @@ class BTCInterface(CoinInterface):
if 'height' in utxo and utxo['height'] > 0 and rv['height'] - utxo['height'] > cb_block_confirmed: if 'height' in utxo and utxo['height'] > 0 and rv['height'] - utxo['height'] > cb_block_confirmed:
if self.make_int(utxo['amount']) != cb_swap_value: if self.make_int(utxo['amount']) != cb_swap_value:
logging.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount'])) self._log.warning('Found output to lock tx pubkey of incorrect value: %s', str(utxo['amount']))
else: else:
return True return True
return False return False
@ -873,7 +878,7 @@ class BTCInterface(CoinInterface):
try: try:
pubkey = PublicKey.from_signature_and_message(signature_bytes, message_hash, hasher=None) pubkey = PublicKey.from_signature_and_message(signature_bytes, message_hash, hasher=None)
except Exception as e: except Exception as e:
logging.info('verifyMessage failed: ' + str(e)) self._log.info('verifyMessage failed: ' + str(e))
return False return False
address_hash = self.decodeAddress(address) address_hash = self.decodeAddress(address)

View file

@ -15,7 +15,6 @@ from .contrib.test_framework.script import (
from .interface_btc import BTCInterface from .interface_btc import BTCInterface
from .chainparams import Coins from .chainparams import Coins
from .rpc import make_rpc_func
class PARTInterface(BTCInterface): class PARTInterface(BTCInterface):
@ -35,13 +34,9 @@ class PARTInterface(BTCInterface):
def xmr_swap_alock_spend_tx_vsize(): def xmr_swap_alock_spend_tx_vsize():
return 213 return 213
def __init__(self, coin_settings, network): @staticmethod
rpc_host = coin_settings.get('rpchost', '127.0.0.1') def txoType():
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'], host=rpc_host) return CTxOutPart
self.txoType = CTxOutPart
self._network = network
self.blocks_confirmed = coin_settings['blocks_confirmed']
self._conf_target = coin_settings['conf_target']
def knownWalletSeed(self): def knownWalletSeed(self):
# TODO: Double check # TODO: Double check

View file

@ -58,7 +58,7 @@ class XMRInterface(CoinInterface):
def nbK(): # No. of bytes requires to encode a public key def nbK(): # No. of bytes requires to encode a public key
return 32 return 32
def __init__(self, coin_settings, network): def __init__(self, coin_settings, network, swap_client=None):
super().__init__() super().__init__()
self.rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', '127.0.0.1')) 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_cb2 = make_xmr_rpc2_func(coin_settings['rpcport'], host=coin_settings.get('rpchost', '127.0.0.1')) # non-json endpoint
@ -68,6 +68,8 @@ class XMRInterface(CoinInterface):
self.blocks_confirmed = coin_settings['blocks_confirmed'] self.blocks_confirmed = coin_settings['blocks_confirmed']
self._restore_height = coin_settings.get('restore_height', 0) self._restore_height = coin_settings.get('restore_height', 0)
self.setFeePriority(coin_settings.get('fee_priority', 0)) self.setFeePriority(coin_settings.get('fee_priority', 0))
self._sc = swap_client
self._log = self._sc.log if self._sc.log else logging
def setFeePriority(self, new_priority): def setFeePriority(self, new_priority):
assert(new_priority >= 0 and new_priority < 4), 'Invalid fee_priority value' assert(new_priority >= 0 and new_priority < 4), 'Invalid fee_priority value'
@ -96,7 +98,7 @@ class XMRInterface(CoinInterface):
'restore_height': self._restore_height, 'restore_height': self._restore_height,
} }
rv = self.rpc_wallet_cb('generate_from_keys', params) rv = self.rpc_wallet_cb('generate_from_keys', params)
logging.info('generate_from_keys %s', dumpj(rv)) self._log.info('generate_from_keys %s', dumpj(rv))
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename}) self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
def ensureWalletExists(self): def ensureWalletExists(self):
@ -137,12 +139,12 @@ class XMRInterface(CoinInterface):
return self.rpc_wallet_cb('get_address')['address'] return self.rpc_wallet_cb('get_address')['address']
def getNewAddress(self, placeholder): def getNewAddress(self, placeholder):
logging.warning('TODO - subaddress?') self._log.warning('TODO - subaddress?')
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename}) self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
return self.rpc_wallet_cb('get_address')['address'] return self.rpc_wallet_cb('get_address')['address']
def get_fee_rate(self, conf_target=2): def get_fee_rate(self, conf_target=2):
logging.warning('TODO - estimate fee rate?') self._log.warning('TODO - estimate fee rate?')
return 0.0, 'unused' return 0.0, 'unused'
def isValidKey(self, key_bytes): def isValidKey(self, key_bytes):
@ -208,14 +210,14 @@ class XMRInterface(CoinInterface):
if self._fee_priority > 0: if self._fee_priority > 0:
params['priority'] = self._fee_priority params['priority'] = self._fee_priority
rv = self.rpc_wallet_cb('transfer', params) rv = self.rpc_wallet_cb('transfer', params)
logging.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr) self._log.info('publishBLockTx %s to address_b58 %s', rv['tx_hash'], shared_addr)
tx_hash = bytes.fromhex(rv['tx_hash']) tx_hash = bytes.fromhex(rv['tx_hash'])
# Debug # Debug
for i in range(10): for i in range(10):
params = {'out': True, 'pending': True, 'failed': True, 'pool': True, } params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
rv = self.rpc_wallet_cb('get_transfers', params) rv = self.rpc_wallet_cb('get_transfers', params)
logging.info('[rm] get_transfers {}'.format(dumpj(rv))) self._log.info('[rm] get_transfers {}'.format(dumpj(rv)))
if 'pending' not in rv: if 'pending' not in rv:
break break
time.sleep(1) time.sleep(1)
@ -229,7 +231,7 @@ class XMRInterface(CoinInterface):
try: try:
self.rpc_wallet_cb('close_wallet') self.rpc_wallet_cb('close_wallet')
except Exception as e: except Exception as e:
logging.warning('close_wallet failed %s', str(e)) self._log.warning('close_wallet failed %s', str(e))
kbv_le = kbv[::-1] kbv_le = kbv[::-1]
params = { params = {
@ -243,7 +245,7 @@ class XMRInterface(CoinInterface):
rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58}) rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58})
except Exception as e: except Exception as e:
rv = self.rpc_wallet_cb('generate_from_keys', params) rv = self.rpc_wallet_cb('generate_from_keys', params)
logging.info('generate_from_keys %s', dumpj(rv)) self._log.info('generate_from_keys %s', dumpj(rv))
rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58}) rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58})
rv = self.rpc_wallet_cb('refresh', timeout=600) rv = self.rpc_wallet_cb('refresh', timeout=600)
@ -252,9 +254,9 @@ class XMRInterface(CoinInterface):
# Debug # Debug
try: try:
current_height = self.rpc_wallet_cb('get_height')['height'] current_height = self.rpc_wallet_cb('get_height')['height']
logging.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58) self._log.info('findTxB XMR current_height %d\nAddress: %s', current_height, address_b58)
except Exception as e: except Exception as e:
logging.info('rpc_cb failed %s', str(e)) self._log.info('rpc_cb failed %s', str(e))
current_height = None # If the transfer is available it will be deep enough current_height = None # If the transfer is available it will be deep enough
# and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed): # and (current_height is None or current_height - transfer['block_height'] > cb_block_confirmed):
''' '''
@ -265,7 +267,7 @@ class XMRInterface(CoinInterface):
if transfer['amount'] == cb_swap_value: if transfer['amount'] == cb_swap_value:
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']} return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
else: else:
logging.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash'])) self._log.warning('Incorrect amount detected for coin b lock txn: {}'.format(transfer['tx_hash']))
return None return None
@ -277,7 +279,7 @@ class XMRInterface(CoinInterface):
try: try:
self.rpc_wallet_cb('close_wallet') self.rpc_wallet_cb('close_wallet')
except Exception as e: except Exception as e:
logging.warning('close_wallet failed %s', str(e)) self._log.warning('close_wallet failed %s', str(e))
params = { params = {
'filename': address_b58, 'filename': address_b58,
@ -296,7 +298,7 @@ class XMRInterface(CoinInterface):
current_height = self.rpc_cb2('get_height')['height'] current_height = self.rpc_cb2('get_height')['height']
print('current_height', current_height) print('current_height', current_height)
except Exception as e: except Exception as e:
logging.warning('rpc_cb failed %s', str(e)) self._log.warning('rpc_cb failed %s', str(e))
current_height = None # If the transfer is available it will be deep enough current_height = None # If the transfer is available it will be deep enough
# TODO: Make accepting current_height == None a user selectable option # TODO: Make accepting current_height == None a user selectable option
@ -336,9 +338,9 @@ class XMRInterface(CoinInterface):
try: try:
current_height = self.rpc_cb2('get_height')['height'] current_height = self.rpc_cb2('get_height')['height']
logging.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid) self._log.info('findTxnByHash XMR current_height %d\nhash: %s', current_height, txid)
except Exception as e: except Exception as e:
logging.info('rpc_cb failed %s', str(e)) self._log.info('rpc_cb failed %s', str(e))
current_height = None # If the transfer is available it will be deep enough current_height = None # If the transfer is available it will be deep enough
params = {'transfer_type': 'available'} params = {'transfer_type': 'available'}
@ -361,7 +363,7 @@ class XMRInterface(CoinInterface):
try: try:
self.rpc_wallet_cb('close_wallet') self.rpc_wallet_cb('close_wallet')
except Exception as e: except Exception as e:
logging.warning('close_wallet failed %s', str(e)) self._log.warning('close_wallet failed %s', str(e))
wallet_filename = address_b58 + '_spend' wallet_filename = address_b58 + '_spend'
@ -377,7 +379,7 @@ class XMRInterface(CoinInterface):
self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename}) self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename})
except Exception as e: except Exception as e:
rv = self.rpc_wallet_cb('generate_from_keys', params) rv = self.rpc_wallet_cb('generate_from_keys', params)
logging.info('generate_from_keys %s', dumpj(rv)) self._log.info('generate_from_keys %s', dumpj(rv))
self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename}) self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename})
# For a while after opening the wallet rpc cmds return empty data # For a while after opening the wallet rpc cmds return empty data
@ -389,10 +391,10 @@ class XMRInterface(CoinInterface):
time.sleep(1 + i) time.sleep(1 + i)
if rv['balance'] < cb_swap_value: if rv['balance'] < cb_swap_value:
logging.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value)) self._log.error('wallet {} balance {}, expected {}'.format(wallet_filename, rv['balance'], cb_swap_value))
raise ValueError('Invalid balance') raise ValueError('Invalid balance')
if rv['unlocked_balance'] < cb_swap_value: if rv['unlocked_balance'] < cb_swap_value:
logging.error('wallet {} balance {}, expected {}, blocks_to_unlock {}'.format(wallet_filename, rv['unlocked_balance'], cb_swap_value, rv['blocks_to_unlock'])) self._log.error('wallet {} balance {}, expected {}, blocks_to_unlock {}'.format(wallet_filename, rv['unlocked_balance'], cb_swap_value, rv['blocks_to_unlock']))
raise ValueError('Invalid unlocked_balance') raise ValueError('Invalid unlocked_balance')
params = {'address': address_to} params = {'address': address_to}

View file

@ -21,6 +21,7 @@ from .ui import (
describeBid, describeBid,
setCoinFilter, setCoinFilter,
get_data_entry, get_data_entry,
have_data_entry,
) )
@ -70,11 +71,11 @@ def js_offers(self, url_split, post_string, is_json, sent=False):
filters['coin_from'] = setCoinFilter(post_data, 'coin_from') filters['coin_from'] = setCoinFilter(post_data, 'coin_from')
filters['coin_to'] = setCoinFilter(post_data, 'coin_to') filters['coin_to'] = setCoinFilter(post_data, 'coin_to')
if b'sort_by' in post_data: if have_data_entry(post_data, 'sort_by'):
sort_by = get_data_entry(post_data, 'sort_by') sort_by = get_data_entry(post_data, 'sort_by')
assert(sort_by in ['created_at', 'rate']), 'Invalid sort by' assert(sort_by in ['created_at', 'rate']), 'Invalid sort by'
filters['sort_by'] = sort_by filters['sort_by'] = sort_by
if b'sort_dir' in post_data: if have_data_entry(post_data, 'sort_dir'):
sort_dir = get_data_entry(post_data, 'sort_dir') sort_dir = get_data_entry(post_data, 'sort_dir')
assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir' assert(sort_dir in ['asc', 'desc']), 'Invalid sort dir'
filters['sort_dir'] = sort_dir filters['sort_dir'] = sort_dir
@ -113,38 +114,51 @@ def js_bids(self, url_split, post_string, is_json):
if url_split[3] == 'new': if url_split[3] == 'new':
if post_string == '': if post_string == '':
raise ValueError('No post data') raise ValueError('No post data')
if is_json:
post_data = json.loads(post_string)
post_data['is_json'] = True
else:
post_data = urllib.parse.parse_qs(post_string) post_data = urllib.parse.parse_qs(post_string)
offer_id = bytes.fromhex(post_data[b'offer_id'][0].decode('utf-8')) offer_id = bytes.fromhex(get_data_entry(post_data, 'offer_id'))
assert(len(offer_id) == 28) assert(len(offer_id) == 28)
offer = swap_client.getOffer(offer_id) offer = swap_client.getOffer(offer_id)
assert(offer), 'Offer not found.' assert(offer), 'Offer not found.'
ci_from = swap_client.ci(offer.coin_from) ci_from = swap_client.ci(offer.coin_from)
amount_from = inputAmount(post_data[b'amount_from'][0].decode('utf-8'), ci_from) amount_from = inputAmount(get_data_entry(post_data, 'amount_from'), ci_from)
addr_from = None addr_from = None
if b'addr_from' in post_data: if have_data_entry(post_data, 'addr_from'):
addr_from = post_data[b'addr_from'][0].decode('utf-8') addr_from = get_data_entry(post_data, 'addr_from')
if addr_from == '-1': if addr_from == '-1':
addr_from = None addr_from = None
if offer.swap_type == SwapTypes.XMR_SWAP: if offer.swap_type == SwapTypes.XMR_SWAP:
bid_id = swap_client.postXmrBid(offer_id, amount_from, addr_send_from=addr_from).hex() bid_id = swap_client.postXmrBid(offer_id, amount_from, addr_send_from=addr_from)
else: else:
bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from).hex() bid_id = swap_client.postBid(offer_id, amount_from, addr_send_from=addr_from)
rv = {'bid_id': bid_id} if have_data_entry(post_data, 'debugind'):
swap_client.setBidDebugInd(bid_id, int(get_data_entry(post_data, 'debugind')))
rv = {'bid_id': bid_id.hex()}
return bytes(json.dumps(rv), 'UTF-8') return bytes(json.dumps(rv), 'UTF-8')
bid_id = bytes.fromhex(url_split[3]) bid_id = bytes.fromhex(url_split[3])
assert(len(bid_id) == 28) assert(len(bid_id) == 28)
if post_string != '': if post_string != '':
if is_json:
post_data = json.loads(post_string)
post_data['is_json'] = True
else:
post_data = urllib.parse.parse_qs(post_string) post_data = urllib.parse.parse_qs(post_string)
if b'accept' in post_data: if have_data_entry(post_data, 'accept'):
swap_client.acceptBid(bid_id) swap_client.acceptBid(bid_id)
elif have_data_entry(post_data, 'debugind'):
swap_client.setBidDebugInd(bid_id, int(get_data_entry(post_data, 'debugind')))
bid, xmr_swap, offer, xmr_offer, events = swap_client.getXmrBidAndOffer(bid_id) bid, xmr_swap, offer, xmr_offer, events = swap_client.getXmrBidAndOffer(bid_id)
assert(bid), 'Unknown bid ID' assert(bid), 'Unknown bid ID'

View file

@ -206,6 +206,7 @@ class Test(unittest.TestCase):
settings['max_delay_event'] = 4 settings['max_delay_event'] = 4
settings['min_delay_retry'] = 10 settings['min_delay_retry'] = 10
settings['max_delay_retry'] = 20 settings['max_delay_retry'] = 20
settings['min_sequence_lock_seconds'] = 60
settings['check_progress_seconds'] = 5 settings['check_progress_seconds'] = 5
settings['check_watched_seconds'] = 5 settings['check_watched_seconds'] = 5