mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-03 17:29:26 +00:00
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:
parent
4ea4e0656a
commit
2e0edef9da
9 changed files with 149 additions and 101 deletions
|
@ -1,3 +1,3 @@
|
|||
name = "basicswap"
|
||||
|
||||
__version__ = "0.0.13"
|
||||
__version__ = "0.0.14"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue