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"
__version__ = "0.0.13"
__version__ = "0.0.14"

View file

@ -14,7 +14,6 @@ import random
import shutil
import struct
import hashlib
import logging
import secrets
import datetime as dt
import traceback
@ -200,6 +199,7 @@ class EventLogTypes(IntEnum):
LOCK_TX_A_CONFIRMED = auto()
LOCK_TX_B_SEEN = auto()
LOCK_TX_B_CONFIRMED = auto()
DEBUG_TWEAK_APPLIED = auto()
class XmrSplitMsgTypes(IntEnum):
@ -342,6 +342,8 @@ def describeEventEntry(event_type, event_msg):
return 'Lock tx b seen in chain'
if event_type == EventLogTypes.LOCK_TX_B_CONFIRMED:
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):
@ -445,6 +447,9 @@ class BasicSwap(BaseApp):
self.min_delay_retry = self.settings.get('min_delay_retry', 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.swaps_in_progress = dict()
@ -595,15 +600,15 @@ class BasicSwap(BaseApp):
def createInterface(self, coin):
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:
return BTCInterface(self.coin_clients[coin], self.chain)
return BTCInterface(self.coin_clients[coin], self.chain, self)
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:
return NMCInterface(self.coin_clients[coin], self.chain)
return NMCInterface(self.coin_clients[coin], self.chain, self)
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)
xmr_i.setWalletFilename(chain_client_settings['walletfile'])
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)
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:
session = scoped_session(self.session_factory)
@ -743,12 +762,7 @@ class BasicSwap(BaseApp):
db_version += 1
self.db_version = db_version
kv = session.query(DBKVInt).filter_by(key='db_version').first()
if not kv:
kv = DBKVInt(key='db_version', value=db_version)
else:
kv.value = db_version
session.add(kv)
self.setIntKVInSession('db_version', db_version, session)
session.commit()
session.close()
session.remove()
@ -804,16 +818,19 @@ class BasicSwap(BaseApp):
key_str = 'main_wallet_seedid_' + chainparams[coin_type]['name']
self.setStringKV(key_str, root_hash.hex())
def setIntKV(self, str_key, int_val):
self.mxDB.acquire()
try:
session = scoped_session(self.session_factory)
def setIntKVInSession(self, str_key, int_val, session):
kv = session.query(DBKVInt).filter_by(key=str_key).first()
if not kv:
kv = DBKVInt(key=str_key, value=int_val)
else:
kv.value = int_val
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()
finally:
session.close()
@ -1004,7 +1021,7 @@ class BasicSwap(BaseApp):
def validateOfferLockValue(self, coin_from, coin_to, lock_type, lock_value):
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.'
elif lock_type == OfferMessage.SEQUENCE_LOCK_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)
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)
offer = Offer(
offer_id=offer_id,
@ -1128,7 +1149,8 @@ class BasicSwap(BaseApp):
created_at=offer_created_at,
expire_at=offer_created_at + msg_buf.time_valid,
was_sent=True,
auto_accept_bids=auto_accept_bids,)
auto_accept_bids=auto_accept_bids,
security_token=security_token)
offer.setState(OfferStates.OFFER_SENT)
if swap_type == SwapTypes.XMR_SWAP:
@ -1149,7 +1171,7 @@ class BasicSwap(BaseApp):
self.log.info('Sent OFFER %s', offer_id.hex())
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())
session = None
@ -1159,6 +1181,9 @@ class BasicSwap(BaseApp):
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.offer_msg_id = offer_id
@ -2652,7 +2677,7 @@ class BasicSwap(BaseApp):
self.saveBidInSession(bid_id, bid, session, xmr_swap)
session.commit()
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 xmr_swap.a_lock_refund_swipe_tx is None:
@ -2672,7 +2697,7 @@ class BasicSwap(BaseApp):
self.saveBidInSession(bid_id, bid, session, xmr_swap)
session.commit()
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:
txid_hex = bid.xmr_b_lock_tx.spend_txid.hex()
@ -3271,9 +3296,9 @@ class BasicSwap(BaseApp):
num_removed += 1
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:
self.mxDB.release()
@ -3410,7 +3435,7 @@ class BasicSwap(BaseApp):
elif offer_data.swap_type == SwapTypes.XMR_SWAP:
assert(coin_from != Coins.XMR)
assert(coin_to == Coins.XMR)
logging.debug('TODO - More restrictions')
self.log.debug('TODO - More restrictions')
else:
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_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_from.verifyPubkey(bid_data.pkaf))
@ -3892,7 +3917,7 @@ class BasicSwap(BaseApp):
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)
bid.setState(BidStates.BID_RECEIVING_ACC)
@ -4056,7 +4081,9 @@ class BasicSwap(BaseApp):
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)
# 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
if bid.debug_ind == DebugTypes.CREATE_INVALID_COIN_B_LOCK:

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019-2020 tecnovert
# Copyright (c) 2019-2021 tecnovert
# Distributed under the MIT software license, see the accompanying
# 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
CURRENT_DB_VERSION = 6
CURRENT_DB_VERSION = 7
Base = declarative_base()
@ -62,6 +62,7 @@ class Offer(Base):
# Local fields
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
security_token = sa.Column(sa.LargeBinary)
state = sa.Column(sa.Integer)
states = sa.Column(sa.LargeBinary) # Packed states and times
@ -114,6 +115,7 @@ class Bid(Base):
state_note = sa.Column(sa.String)
debug_ind = sa.Column(sa.Integer)
security_token = sa.Column(sa.LargeBinary)
initiate_tx = None
participate_tx = None

View file

@ -393,6 +393,8 @@ class HttpHandler(BaseHTTPRequestHandler):
if have_data_entry(form_data, 'lockhrs'):
page_data['lockhrs'] = int(get_data_entry(form_data, 'lockhrs'))
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
parsed_data['autoaccept'] = page_data['autoaccept']

View file

@ -117,14 +117,19 @@ class BTCInterface(CoinInterface):
def xmr_swap_alock_spend_tx_vsize():
return 147
def __init__(self, coin_settings, network):
@staticmethod
def txoType():
return CTxOut
def __init__(self, coin_settings, network, swap_client=None):
super().__init__()
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
self.blocks_confirmed = coin_settings['blocks_confirmed']
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):
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])
except Exception as e:
# < 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):
return self.rpc_callback('getwalletinfo')
@ -252,7 +257,7 @@ class BTCInterface(CoinInterface):
script = self.genScriptLockTxScript(Kal, Kaf)
tx = CTransaction()
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
@ -316,10 +321,10 @@ class BTCInterface(CoinInterface):
tx = CTransaction()
tx.nVersion = self.txVersion()
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 += 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 += getCompactSizeLen(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.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)
return tx.serialize(), refund_script, tx.vout[0].nValue
@ -351,7 +356,7 @@ class BTCInterface(CoinInterface):
tx.nVersion = self.txVersion()
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 += 73 * 2 # 2 signatures (72 + 1 byte size)
@ -362,7 +367,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee
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)
return tx.serialize()
@ -386,7 +391,7 @@ class BTCInterface(CoinInterface):
tx.nVersion = self.txVersion()
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 += 73 # signature (72 + 1 byte size)
@ -397,7 +402,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee
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)
return tx.serialize()
@ -416,7 +421,7 @@ class BTCInterface(CoinInterface):
tx.nVersion = self.txVersion()
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 += 33 # sv, size
@ -428,7 +433,7 @@ class BTCInterface(CoinInterface):
tx.vout[0].nValue = locked_coin - pay_fee
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)
return tx.serialize()
@ -447,7 +452,7 @@ class BTCInterface(CoinInterface):
tx = self.loadTx(tx_bytes)
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.nLockTime == 0, 'Bad nLockTime')
@ -491,10 +496,10 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_bytes, add_witness_bytes)
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):
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
return tx_hash, locked_n
@ -509,7 +514,7 @@ class BTCInterface(CoinInterface):
tx = self.loadTx(tx_bytes)
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.nLockTime == 0, 'nLockTime not 0')
@ -543,7 +548,7 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
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):
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
tx = self.loadTx(tx_bytes)
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.nLockTime == 0, 'nLockTime not 0')
@ -589,7 +594,7 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
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):
raise ValueError('Bad fee rate')
@ -605,7 +610,7 @@ class BTCInterface(CoinInterface):
tx = self.loadTx(tx_bytes)
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.nLockTime == 0, 'nLockTime not 0')
@ -638,7 +643,7 @@ class BTCInterface(CoinInterface):
vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
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):
raise ValueError('Bad fee rate')
@ -768,7 +773,7 @@ class BTCInterface(CoinInterface):
tx = CTransaction()
tx.nVersion = self.txVersion()
p2wpkh = self.getPkDest(Kbs)
tx.vout.append(self.txoType(output_amount, p2wpkh))
tx.vout.append(self.txoType()(output_amount, p2wpkh))
return tx.serialize()
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate):
@ -799,7 +804,7 @@ class BTCInterface(CoinInterface):
for utxo in rv['unspents']:
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:
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:
return {'txid': utxo['txid'], 'vout': utxo['vout'], 'amount': utxo['amount'], 'height': utxo['height']}
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 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:
return True
return False
@ -873,7 +878,7 @@ class BTCInterface(CoinInterface):
try:
pubkey = PublicKey.from_signature_and_message(signature_bytes, message_hash, hasher=None)
except Exception as e:
logging.info('verifyMessage failed: ' + str(e))
self._log.info('verifyMessage failed: ' + str(e))
return False
address_hash = self.decodeAddress(address)

View file

@ -15,7 +15,6 @@ from .contrib.test_framework.script import (
from .interface_btc import BTCInterface
from .chainparams import Coins
from .rpc import make_rpc_func
class PARTInterface(BTCInterface):
@ -35,13 +34,9 @@ class PARTInterface(BTCInterface):
def xmr_swap_alock_spend_tx_vsize():
return 213
def __init__(self, coin_settings, network):
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
self.blocks_confirmed = coin_settings['blocks_confirmed']
self._conf_target = coin_settings['conf_target']
@staticmethod
def txoType():
return CTxOutPart
def knownWalletSeed(self):
# TODO: Double check

View file

@ -58,7 +58,7 @@ class XMRInterface(CoinInterface):
def nbK(): # No. of bytes requires to encode a public key
return 32
def __init__(self, coin_settings, network):
def __init__(self, coin_settings, network, swap_client=None):
super().__init__()
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
@ -68,6 +68,8 @@ class XMRInterface(CoinInterface):
self.blocks_confirmed = coin_settings['blocks_confirmed']
self._restore_height = coin_settings.get('restore_height', 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):
assert(new_priority >= 0 and new_priority < 4), 'Invalid fee_priority value'
@ -96,7 +98,7 @@ class XMRInterface(CoinInterface):
'restore_height': self._restore_height,
}
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})
def ensureWalletExists(self):
@ -137,12 +139,12 @@ class XMRInterface(CoinInterface):
return self.rpc_wallet_cb('get_address')['address']
def getNewAddress(self, placeholder):
logging.warning('TODO - subaddress?')
self._log.warning('TODO - subaddress?')
self.rpc_wallet_cb('open_wallet', {'filename': self._wallet_filename})
return self.rpc_wallet_cb('get_address')['address']
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'
def isValidKey(self, key_bytes):
@ -208,14 +210,14 @@ class XMRInterface(CoinInterface):
if self._fee_priority > 0:
params['priority'] = self._fee_priority
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'])
# Debug
for i in range(10):
params = {'out': True, 'pending': True, 'failed': True, 'pool': True, }
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:
break
time.sleep(1)
@ -229,7 +231,7 @@ class XMRInterface(CoinInterface):
try:
self.rpc_wallet_cb('close_wallet')
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]
params = {
@ -243,7 +245,7 @@ class XMRInterface(CoinInterface):
rv = self.rpc_wallet_cb('open_wallet', {'filename': address_b58})
except Exception as e:
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('refresh', timeout=600)
@ -252,9 +254,9 @@ class XMRInterface(CoinInterface):
# Debug
try:
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:
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
# 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:
return {'txid': transfer['tx_hash'], 'amount': transfer['amount'], 'height': 0 if 'block_height' not in transfer else transfer['block_height']}
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
@ -277,7 +279,7 @@ class XMRInterface(CoinInterface):
try:
self.rpc_wallet_cb('close_wallet')
except Exception as e:
logging.warning('close_wallet failed %s', str(e))
self._log.warning('close_wallet failed %s', str(e))
params = {
'filename': address_b58,
@ -296,7 +298,7 @@ class XMRInterface(CoinInterface):
current_height = self.rpc_cb2('get_height')['height']
print('current_height', current_height)
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
# TODO: Make accepting current_height == None a user selectable option
@ -336,9 +338,9 @@ class XMRInterface(CoinInterface):
try:
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:
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
params = {'transfer_type': 'available'}
@ -361,7 +363,7 @@ class XMRInterface(CoinInterface):
try:
self.rpc_wallet_cb('close_wallet')
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'
@ -377,7 +379,7 @@ class XMRInterface(CoinInterface):
self.rpc_wallet_cb('open_wallet', {'filename': wallet_filename})
except Exception as e:
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})
# For a while after opening the wallet rpc cmds return empty data
@ -389,10 +391,10 @@ class XMRInterface(CoinInterface):
time.sleep(1 + i)
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')
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')
params = {'address': address_to}

View file

@ -21,6 +21,7 @@ from .ui import (
describeBid,
setCoinFilter,
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_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')
assert(sort_by in ['created_at', 'rate']), 'Invalid 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')
assert(sort_dir in ['asc', 'desc']), 'Invalid 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 post_string == '':
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)
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)
offer = swap_client.getOffer(offer_id)
assert(offer), 'Offer not found.'
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
if b'addr_from' in post_data:
addr_from = post_data[b'addr_from'][0].decode('utf-8')
if have_data_entry(post_data, 'addr_from'):
addr_from = get_data_entry(post_data, 'addr_from')
if addr_from == '-1':
addr_from = None
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:
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')
bid_id = bytes.fromhex(url_split[3])
assert(len(bid_id) == 28)
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)
if b'accept' in post_data:
if have_data_entry(post_data, 'accept'):
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)
assert(bid), 'Unknown bid ID'

View file

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