mirror of
https://github.com/basicswap/basicswap.git
synced 2024-11-17 00:07:56 +00:00
MSG3L
Debug mode is disabled by default.
This commit is contained in:
parent
009729aa96
commit
18a5322f10
14 changed files with 503 additions and 91 deletions
|
@ -36,7 +36,7 @@ class BaseApp:
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.coin_clients = {}
|
self.coin_clients = {}
|
||||||
self.mxDB = threading.RLock()
|
self.mxDB = threading.RLock()
|
||||||
self.debug = self.settings.get('debug', cfg.DEBUG)
|
self.debug = self.settings.get('debug', False)
|
||||||
|
|
||||||
self.prepareLogging()
|
self.prepareLogging()
|
||||||
self.log.info('Network: {}'.format(self.chain))
|
self.log.info('Network: {}'.format(self.chain))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2019 tecnovert
|
# Copyright (c) 2019-2020 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.
|
||||||
|
|
||||||
|
@ -57,6 +57,8 @@ from .messages_pb2 import (
|
||||||
XmrBidMessage,
|
XmrBidMessage,
|
||||||
XmrBidAcceptMessage,
|
XmrBidAcceptMessage,
|
||||||
XmrSplitMessage,
|
XmrSplitMessage,
|
||||||
|
XmrBidLockTxSigsMessage,
|
||||||
|
XmrBidLockSpendTxMessage,
|
||||||
)
|
)
|
||||||
from .db import (
|
from .db import (
|
||||||
CURRENT_DB_VERSION,
|
CURRENT_DB_VERSION,
|
||||||
|
@ -95,6 +97,7 @@ class MessageTypes(IntEnum):
|
||||||
XMR_BID = auto()
|
XMR_BID = auto()
|
||||||
XMR_BID_SPLIT = auto()
|
XMR_BID_SPLIT = auto()
|
||||||
XMR_BID_ACCEPT = auto()
|
XMR_BID_ACCEPT = auto()
|
||||||
|
XMR_BID_TXN_SIGS_FL = auto()
|
||||||
|
|
||||||
|
|
||||||
class SwapTypes(IntEnum):
|
class SwapTypes(IntEnum):
|
||||||
|
@ -120,6 +123,8 @@ class BidStates(IntEnum):
|
||||||
SWAP_INITIATED = auto() # Initiate txn validated
|
SWAP_INITIATED = auto() # Initiate txn validated
|
||||||
SWAP_PARTICIPATING = auto() # Participate txn validated
|
SWAP_PARTICIPATING = auto() # Participate txn validated
|
||||||
SWAP_COMPLETED = auto() # All swap txns spent
|
SWAP_COMPLETED = auto() # All swap txns spent
|
||||||
|
XMR_SWAP_SCRIPT_COIN_LOCKED = auto()
|
||||||
|
SWAP_DELAYING = auto()
|
||||||
SWAP_TIMEDOUT = auto()
|
SWAP_TIMEDOUT = auto()
|
||||||
BID_ABANDONED = auto() # Bid will no longer be processed
|
BID_ABANDONED = auto() # Bid will no longer be processed
|
||||||
BID_ERROR = auto() # An error occurred
|
BID_ERROR = auto() # An error occurred
|
||||||
|
@ -141,9 +146,15 @@ class TxTypes(IntEnum):
|
||||||
PTX_REDEEM = auto()
|
PTX_REDEEM = auto()
|
||||||
PTX_REFUND = auto()
|
PTX_REFUND = auto()
|
||||||
|
|
||||||
|
XMR_SWAP_A_LOCK = auto()
|
||||||
|
XMR_SWAP_A_LOCK_REFUND = auto()
|
||||||
|
XMR_SWAP_A_LOCK_REFUND_SPEND = auto()
|
||||||
|
|
||||||
|
|
||||||
class EventTypes(IntEnum):
|
class EventTypes(IntEnum):
|
||||||
ACCEPT_BID = auto()
|
ACCEPT_BID = auto()
|
||||||
|
SIGN_XMR_SWAP_LOCK_TX_A = auto()
|
||||||
|
SEND_XMR_SWAP_LOCK_TX_A = auto()
|
||||||
|
|
||||||
|
|
||||||
class XmrSplitMsgTypes(IntEnum):
|
class XmrSplitMsgTypes(IntEnum):
|
||||||
|
@ -467,15 +478,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])
|
return PARTInterface(self.coin_clients[coin], self.chain)
|
||||||
elif coin == Coins.BTC:
|
elif coin == Coins.BTC:
|
||||||
return BTCInterface(self.coin_clients[coin])
|
return BTCInterface(self.coin_clients[coin], self.chain)
|
||||||
elif coin == Coins.LTC:
|
elif coin == Coins.LTC:
|
||||||
return LTCInterface(self.coin_clients[coin])
|
return LTCInterface(self.coin_clients[coin], self.chain)
|
||||||
elif coin == Coins.NMC:
|
elif coin == Coins.NMC:
|
||||||
return NMCInterface(self.coin_clients[coin])
|
return NMCInterface(self.coin_clients[coin], self.chain)
|
||||||
elif coin == Coins.XMR:
|
elif coin == Coins.XMR:
|
||||||
return XMRInterface(self.coin_clients[coin])
|
return XMRInterface(self.coin_clients[coin], self.chain)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown coin type')
|
raise ValueError('Unknown coin type')
|
||||||
|
|
||||||
|
@ -1087,11 +1098,8 @@ class BasicSwap(BaseApp):
|
||||||
finally:
|
finally:
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
||||||
def createEvent(self, delay, event_type, linked_id):
|
def createEventInSession(self, delay, event_type, linked_id, session):
|
||||||
self.log.debug('createEvent %d %s', event_type, linked_id.hex())
|
self.log.debug('createEvent %d %s', event_type, linked_id.hex())
|
||||||
self.mxDB.acquire()
|
|
||||||
try:
|
|
||||||
session = scoped_session(self.session_factory)
|
|
||||||
event = EventQueue()
|
event = EventQueue()
|
||||||
event.active_ind = 1
|
event.active_ind = 1
|
||||||
event.created_at = int(time.time())
|
event.created_at = int(time.time())
|
||||||
|
@ -1099,6 +1107,13 @@ class BasicSwap(BaseApp):
|
||||||
event.event_type = event_type
|
event.event_type = event_type
|
||||||
event.linked_id = linked_id
|
event.linked_id = linked_id
|
||||||
session.add(event)
|
session.add(event)
|
||||||
|
|
||||||
|
def createEvent(self, delay, event_type, linked_id):
|
||||||
|
#self.log.debug('createEvent %d %s', event_type, linked_id.hex())
|
||||||
|
self.mxDB.acquire()
|
||||||
|
try:
|
||||||
|
session = scoped_session(self.session_factory)
|
||||||
|
self.createEventInSession(delay, event_type, linked_id, session)
|
||||||
session.commit()
|
session.commit()
|
||||||
session.close()
|
session.close()
|
||||||
session.remove()
|
session.remove()
|
||||||
|
@ -1351,11 +1366,6 @@ class BasicSwap(BaseApp):
|
||||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(offer_id.hex())
|
assert(xmr_offer), 'XMR offer not found: {}.'.format(offer_id.hex())
|
||||||
assert(offer.expire_at > int(time.time())), 'Offer has expired'
|
assert(offer.expire_at > int(time.time())), 'Offer has expired'
|
||||||
|
|
||||||
msg_buf = XmrBidMessage()
|
|
||||||
msg_buf.offer_msg_id = offer_id
|
|
||||||
msg_buf.time_valid = 60 * 10
|
|
||||||
msg_buf.amount = int(amount) # amount of coin_from
|
|
||||||
|
|
||||||
coin_from = Coins(offer.coin_from)
|
coin_from = Coins(offer.coin_from)
|
||||||
coin_to = Coins(offer.coin_to)
|
coin_to = Coins(offer.coin_to)
|
||||||
ci_from = self.ci(coin_from)
|
ci_from = self.ci(coin_from)
|
||||||
|
@ -1363,6 +1373,14 @@ class BasicSwap(BaseApp):
|
||||||
|
|
||||||
self.checkSynced(coin_from, coin_to)
|
self.checkSynced(coin_from, coin_to)
|
||||||
|
|
||||||
|
msg_buf = XmrBidMessage()
|
||||||
|
msg_buf.offer_msg_id = offer_id
|
||||||
|
msg_buf.time_valid = 60 * 10
|
||||||
|
msg_buf.amount = int(amount) # amount of coin_from
|
||||||
|
|
||||||
|
address_out = self.getReceiveAddressFromPool(coin_from, offer_id, TxTypes.XMR_SWAP_A_LOCK)
|
||||||
|
msg_buf.dest_af = ci_from.decodeAddress(address_out)
|
||||||
|
|
||||||
bid_created_at = int(time.time())
|
bid_created_at = int(time.time())
|
||||||
if offer.swap_type != SwapTypes.XMR_SWAP:
|
if offer.swap_type != SwapTypes.XMR_SWAP:
|
||||||
raise ValueError('TODO')
|
raise ValueError('TODO')
|
||||||
|
@ -1370,6 +1388,7 @@ class BasicSwap(BaseApp):
|
||||||
# Follower to leader
|
# Follower to leader
|
||||||
xmr_swap = XmrSwap()
|
xmr_swap = XmrSwap()
|
||||||
xmr_swap.contract_count = self.getNewContractId()
|
xmr_swap.contract_count = self.getNewContractId()
|
||||||
|
xmr_swap.dest_af = msg_buf.dest_af
|
||||||
xmr_swap.b_restore_height = self.ci(coin_to).getChainHeight()
|
xmr_swap.b_restore_height = self.ci(coin_to).getChainHeight()
|
||||||
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 1, for_xmr=True)
|
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 1, for_xmr=True)
|
||||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||||
|
@ -1580,7 +1599,8 @@ class BasicSwap(BaseApp):
|
||||||
session.close()
|
session.close()
|
||||||
session.remove()
|
session.remove()
|
||||||
|
|
||||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
#self.swaps_in_progress[bid_id] = (bid, offer)
|
||||||
|
# Add to swaps_in_progress only when waiting on txns
|
||||||
self.log.info('Sent XMR_BID_ACCEPT %s', bid_id.hex())
|
self.log.info('Sent XMR_BID_ACCEPT %s', bid_id.hex())
|
||||||
return bid_id
|
return bid_id
|
||||||
finally:
|
finally:
|
||||||
|
@ -1625,6 +1645,7 @@ class BasicSwap(BaseApp):
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
||||||
def setBidError(self, bid_id, bid, error_str):
|
def setBidError(self, bid_id, bid, error_str):
|
||||||
|
self.log.error('Bid %s - Error: %s', bid_id.hex(), error_str)
|
||||||
bid.setState(BidStates.BID_ERROR)
|
bid.setState(BidStates.BID_ERROR)
|
||||||
bid.state_note = 'error msg: ' + error_str
|
bid.state_note = 'error msg: ' + error_str
|
||||||
self.saveBid(bid_id, bid)
|
self.saveBid(bid_id, bid)
|
||||||
|
@ -2435,6 +2456,10 @@ class BasicSwap(BaseApp):
|
||||||
for row in q:
|
for row in q:
|
||||||
if row.event_type == EventTypes.ACCEPT_BID:
|
if row.event_type == EventTypes.ACCEPT_BID:
|
||||||
self.acceptBid(row.linked_id)
|
self.acceptBid(row.linked_id)
|
||||||
|
elif row.event_type == EventTypes.SIGN_XMR_SWAP_LOCK_TX_A:
|
||||||
|
self.sendXmrBidTxnSigsFtoL(row.linked_id, session)
|
||||||
|
elif row.event_type == EventTypes.SEND_XMR_SWAP_LOCK_TX_A:
|
||||||
|
self.sendXmrBidCoinALockTx(row.linked_id, session)
|
||||||
else:
|
else:
|
||||||
self.log.warning('Unknown event type: %d', row.event_type)
|
self.log.warning('Unknown event type: %d', row.event_type)
|
||||||
|
|
||||||
|
@ -2459,9 +2484,9 @@ class BasicSwap(BaseApp):
|
||||||
if num_segments > 1:
|
if num_segments > 1:
|
||||||
try:
|
try:
|
||||||
self.receiveXmrBid(bid, session)
|
self.receiveXmrBid(bid, session)
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
self.log.info('Verify xmr bid {} failed: {}'.format(bid.bid_id.hex(), str(e)))
|
self.log.info('Verify xmr bid {} failed: {}'.format(bid.bid_id.hex(), str(ex)))
|
||||||
bid.setState(BidStates.BID_ERROR, 'Failed validation: ' + str(e))
|
bid.setState(BidStates.BID_ERROR, 'Failed validation: ' + str(ex))
|
||||||
session.add(bid)
|
session.add(bid)
|
||||||
continue
|
continue
|
||||||
if bid.created_at + ttl_xmr_split_messages < now:
|
if bid.created_at + ttl_xmr_split_messages < now:
|
||||||
|
@ -2476,9 +2501,9 @@ class BasicSwap(BaseApp):
|
||||||
if num_segments > 1:
|
if num_segments > 1:
|
||||||
try:
|
try:
|
||||||
self.receiveXmrBidAccept(bid, session)
|
self.receiveXmrBidAccept(bid, session)
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
self.log.info('Verify xmr bid accept {} failed: {}'.format(bid.bid_id.hex(), str(e)))
|
self.log.info('Verify xmr bid accept {} failed: {}'.format(bid.bid_id.hex(), str(ex)))
|
||||||
bid.setState(BidStates.BID_ERROR, 'Failed accept validation: ' + str(e))
|
bid.setState(BidStates.BID_ERROR, 'Failed accept validation: ' + str(ex))
|
||||||
session.add(bid)
|
session.add(bid)
|
||||||
continue
|
continue
|
||||||
if bid.created_at + ttl_xmr_split_messages < now:
|
if bid.created_at + ttl_xmr_split_messages < now:
|
||||||
|
@ -2489,6 +2514,7 @@ class BasicSwap(BaseApp):
|
||||||
# Expire old records
|
# Expire old records
|
||||||
q = session.query(XmrSplitData).filter(XmrSplitData.created_at + ttl_xmr_split_messages < now)
|
q = session.query(XmrSplitData).filter(XmrSplitData.created_at + ttl_xmr_split_messages < now)
|
||||||
q.delete(synchronize_session=False)
|
q.delete(synchronize_session=False)
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
session.close()
|
session.close()
|
||||||
session.remove()
|
session.remove()
|
||||||
|
@ -2659,7 +2685,6 @@ class BasicSwap(BaseApp):
|
||||||
else:
|
else:
|
||||||
delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
|
delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
|
||||||
self.log.info('Auto accepting bid %s in %d seconds', bid_id.hex(), delay)
|
self.log.info('Auto accepting bid %s in %d seconds', bid_id.hex(), delay)
|
||||||
|
|
||||||
self.createEvent(delay, EventTypes.ACCEPT_BID, bid_id)
|
self.createEvent(delay, EventTypes.ACCEPT_BID, bid_id)
|
||||||
|
|
||||||
def processBidAccept(self, msg):
|
def processBidAccept(self, msg):
|
||||||
|
@ -2760,6 +2785,14 @@ class BasicSwap(BaseApp):
|
||||||
if not ci_to.verifyDLEAG(xmr_swap.kbsf_dleag):
|
if not ci_to.verifyDLEAG(xmr_swap.kbsf_dleag):
|
||||||
raise ValueError('Invalid DLEAG proof.')
|
raise ValueError('Invalid DLEAG proof.')
|
||||||
|
|
||||||
|
# Extract pubkeys from MSG1L DLEAG
|
||||||
|
xmr_swap.pkasf = xmr_swap.kbsf_dleag[0: 33]
|
||||||
|
if not ci_from.verifyPubkey(xmr_swap.pkasf):
|
||||||
|
raise ValueError('Invalid coin a pubkey.')
|
||||||
|
xmr_swap.pkbsf = xmr_swap.kbsf_dleag[33: 33 + 32]
|
||||||
|
if not ci_to.verifyPubkey(xmr_swap.pkbsf):
|
||||||
|
raise ValueError('Invalid coin b pubkey.')
|
||||||
|
|
||||||
if not ci_from.verifyPubkey(xmr_swap.pkaf):
|
if not ci_from.verifyPubkey(xmr_swap.pkaf):
|
||||||
raise ValueError('Invalid pubkey.')
|
raise ValueError('Invalid pubkey.')
|
||||||
if not ci_from.verifyPubkey(xmr_swap.pkarf):
|
if not ci_from.verifyPubkey(xmr_swap.pkarf):
|
||||||
|
@ -2794,14 +2827,27 @@ class BasicSwap(BaseApp):
|
||||||
if not ci_to.verifyDLEAG(xmr_swap.kbsl_dleag):
|
if not ci_to.verifyDLEAG(xmr_swap.kbsl_dleag):
|
||||||
raise ValueError('Invalid DLEAG proof.')
|
raise ValueError('Invalid DLEAG proof.')
|
||||||
|
|
||||||
|
# Extract pubkeys from MSG1F DLEAG
|
||||||
|
xmr_swap.pkasl = xmr_swap.kbsl_dleag[0: 33]
|
||||||
|
if not ci_from.verifyPubkey(xmr_swap.pkasl):
|
||||||
|
raise ValueError('Invalid coin a pubkey.')
|
||||||
|
xmr_swap.pkbsl = xmr_swap.kbsl_dleag[33: 33 + 32]
|
||||||
|
if not ci_to.verifyPubkey(xmr_swap.pkbsl):
|
||||||
|
raise ValueError('Invalid coin b pubkey.')
|
||||||
|
|
||||||
if not ci_from.verifyPubkey(xmr_swap.pkal):
|
if not ci_from.verifyPubkey(xmr_swap.pkal):
|
||||||
raise ValueError('Invalid pubkey.')
|
raise ValueError('Invalid pubkey.')
|
||||||
if not ci_from.verifyPubkey(xmr_swap.pkarl):
|
if not ci_from.verifyPubkey(xmr_swap.pkarl):
|
||||||
raise ValueError('Invalid pubkey.')
|
raise ValueError('Invalid pubkey.')
|
||||||
|
|
||||||
bid.setState(BidStates.BID_ACCEPTED)
|
#bid.setState(BidStates.BID_ACCEPTED)
|
||||||
|
bid.setState(BidStates.SWAP_DELAYING)
|
||||||
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
||||||
|
|
||||||
|
delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
|
||||||
|
self.log.info('Responding to xmr bid accept %s in %d seconds', bid.bid_id.hex(), delay)
|
||||||
|
self.createEventInSession(delay, EventTypes.SIGN_XMR_SWAP_LOCK_TX_A, bid.bid_id, session)
|
||||||
|
|
||||||
def processXmrBid(self, msg):
|
def processXmrBid(self, msg):
|
||||||
self.log.debug('Processing xmr bid msg %s', msg['msgid'])
|
self.log.debug('Processing xmr bid msg %s', msg['msgid'])
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
|
@ -2841,6 +2887,7 @@ class BasicSwap(BaseApp):
|
||||||
|
|
||||||
xmr_swap = XmrSwap(
|
xmr_swap = XmrSwap(
|
||||||
bid_id=bid_id,
|
bid_id=bid_id,
|
||||||
|
dest_af=bid_data.dest_af,
|
||||||
pkaf=bid_data.pkaf,
|
pkaf=bid_data.pkaf,
|
||||||
pkarf=bid_data.pkarf,
|
pkarf=bid_data.pkarf,
|
||||||
vkbvf=bid_data.kbvf,
|
vkbvf=bid_data.kbvf,
|
||||||
|
@ -2858,7 +2905,7 @@ class BasicSwap(BaseApp):
|
||||||
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
|
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
|
||||||
|
|
||||||
def processXmrBidAccept(self, msg):
|
def processXmrBidAccept(self, msg):
|
||||||
# F receiving MSG1F
|
# F receiving MSG1F and MSG2F
|
||||||
self.log.debug('Processing xmr bid accept msg %s', msg['msgid'])
|
self.log.debug('Processing xmr bid accept msg %s', msg['msgid'])
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
msg_bytes = bytes.fromhex(msg['hex'][2:-2])
|
msg_bytes = bytes.fromhex(msg['hex'][2:-2])
|
||||||
|
@ -2869,13 +2916,18 @@ class BasicSwap(BaseApp):
|
||||||
|
|
||||||
self.log.debug('for bid %s', msg_data.bid_msg_id.hex())
|
self.log.debug('for bid %s', msg_data.bid_msg_id.hex())
|
||||||
bid, xmr_swap = self.getXmrBid(msg_data.bid_msg_id)
|
bid, xmr_swap = self.getXmrBid(msg_data.bid_msg_id)
|
||||||
|
assert(bid), 'Bid not found: {}.'.format(msg_data.bid_id.hex())
|
||||||
|
assert(xmr_swap), 'XMR swap not found: {}.'.format(msg_data.bid_id.hex())
|
||||||
|
|
||||||
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=True)
|
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=True)
|
||||||
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(bid.offer_id.hex())
|
assert(xmr_offer), 'XMR offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
coin_from = Coins(offer.coin_from)
|
coin_from = Coins(offer.coin_from)
|
||||||
coin_to = Coins(offer.coin_to)
|
coin_to = Coins(offer.coin_to)
|
||||||
|
ci_from = self.ci(coin_from)
|
||||||
|
ci_to = self.ci(coin_to)
|
||||||
|
|
||||||
|
try:
|
||||||
assert(len(msg_data.sh) == 32), 'Bad secret hash length'
|
assert(len(msg_data.sh) == 32), 'Bad secret hash length'
|
||||||
|
|
||||||
xmr_swap.sh = msg_data.sh
|
xmr_swap.sh = msg_data.sh
|
||||||
|
@ -2884,8 +2936,172 @@ class BasicSwap(BaseApp):
|
||||||
xmr_swap.vkbvl = msg_data.kbvl
|
xmr_swap.vkbvl = msg_data.kbvl
|
||||||
xmr_swap.kbsl_dleag = msg_data.kbsl_dleag
|
xmr_swap.kbsl_dleag = msg_data.kbsl_dleag
|
||||||
|
|
||||||
|
xmr_swap.a_lock_tx = msg_data.a_lock_tx
|
||||||
|
xmr_swap.a_lock_tx_script = msg_data.a_lock_tx_script
|
||||||
|
xmr_swap.a_lock_refund_tx = msg_data.a_lock_refund_tx
|
||||||
|
xmr_swap.a_lock_refund_tx_script = msg_data.a_lock_refund_tx_script
|
||||||
|
xmr_swap.a_lock_refund_spend_tx = msg_data.a_lock_refund_spend_tx
|
||||||
|
xmr_swap.al_lock_refund_tx_sig = msg_data.al_lock_refund_tx_sig
|
||||||
|
|
||||||
|
check_a_lock_tx_inputs = True
|
||||||
|
xmr_swap.a_lock_tx_id, lock_tx_vout = ci_from.verifyLockTx(
|
||||||
|
xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script,
|
||||||
|
bid.amount,
|
||||||
|
xmr_swap.sh,
|
||||||
|
xmr_swap.pkal, xmr_swap.pkaf,
|
||||||
|
xmr_offer.lock_time_1, xmr_offer.a_fee_rate,
|
||||||
|
xmr_swap.pkarl, xmr_swap.pkarf,
|
||||||
|
check_a_lock_tx_inputs
|
||||||
|
)
|
||||||
|
xmr_swap.a_lock_tx_dest = ci_from.getScriptDest(xmr_swap.a_lock_tx_script)
|
||||||
|
|
||||||
|
lock_refund_tx_id, xmr_swap.a_swap_refund_value = ci_from.verifyLockRefundTx(
|
||||||
|
xmr_swap.a_lock_refund_tx, xmr_swap.a_lock_refund_tx_script,
|
||||||
|
xmr_swap.a_lock_tx_id, lock_tx_vout, xmr_offer.lock_time_1, xmr_swap.a_lock_tx_script,
|
||||||
|
xmr_swap.pkarl, xmr_swap.pkarf,
|
||||||
|
xmr_offer.lock_time_2,
|
||||||
|
xmr_swap.pkaf,
|
||||||
|
bid.amount, xmr_offer.a_fee_rate
|
||||||
|
)
|
||||||
|
|
||||||
|
ci_from.verifyLockRefundSpendTx(
|
||||||
|
xmr_swap.a_lock_refund_spend_tx,
|
||||||
|
lock_refund_tx_id, xmr_swap.a_lock_refund_tx_script,
|
||||||
|
xmr_swap.pkal,
|
||||||
|
xmr_swap.a_swap_refund_value, xmr_offer.a_fee_rate
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.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.pkarl, 0, xmr_swap.a_lock_tx_script, bid.amount)
|
||||||
|
|
||||||
bid.setState(BidStates.BID_RECEIVING_ACC)
|
bid.setState(BidStates.BID_RECEIVING_ACC)
|
||||||
self.saveBid(msg_data.bid_msg_id, bid, xmr_swap=xmr_swap)
|
self.saveBid(bid.bid_id, bid, xmr_swap=xmr_swap)
|
||||||
|
except Exception as ex:
|
||||||
|
if self.debug:
|
||||||
|
traceback.print_exc()
|
||||||
|
self.setBidError(bid.bid_id, bid, str(ex))
|
||||||
|
|
||||||
|
def sendXmrBidTxnSigsFtoL(self, bid_id, session):
|
||||||
|
# F -> L: Sending MSG3L
|
||||||
|
self.log.debug('Signing xmr bid lock txns %s', bid_id.hex())
|
||||||
|
|
||||||
|
bid, xmr_swap = self.getXmrBid(bid_id)
|
||||||
|
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
||||||
|
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid_id.hex())
|
||||||
|
|
||||||
|
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=False)
|
||||||
|
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
|
assert(xmr_offer), 'XMR offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
|
coin_from = Coins(offer.coin_from)
|
||||||
|
coin_to = Coins(offer.coin_to)
|
||||||
|
ci_from = self.ci(coin_from)
|
||||||
|
ci_to = self.ci(coin_to)
|
||||||
|
|
||||||
|
try:
|
||||||
|
karf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 4)
|
||||||
|
|
||||||
|
print('[rm] xmr_swap.a_swap_refund_value', xmr_swap.a_swap_refund_value)
|
||||||
|
xmr_swap.af_lock_refund_spend_tx_esig = ci_from.signTxOtVES(karf, xmr_swap.pkasl, xmr_swap.a_lock_refund_spend_tx, 0, xmr_swap.a_lock_refund_tx_script, xmr_swap.a_swap_refund_value)
|
||||||
|
xmr_swap.af_lock_refund_tx_sig = ci_from.signTx(karf, xmr_swap.a_lock_refund_tx, 0, xmr_swap.a_lock_tx_script, bid.amount)
|
||||||
|
|
||||||
|
msg_buf = XmrBidLockTxSigsMessage(
|
||||||
|
bid_msg_id=bid_id,
|
||||||
|
af_lock_refund_spend_tx_esig=xmr_swap.af_lock_refund_spend_tx_esig,
|
||||||
|
af_lock_refund_tx_sig=xmr_swap.af_lock_refund_tx_sig
|
||||||
|
)
|
||||||
|
|
||||||
|
mag_bytes = msg_buf.SerializeToString()
|
||||||
|
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_TXN_SIGS_FL) + mag_bytes.hex()
|
||||||
|
|
||||||
|
options = {'decodehex': True, 'ttl_is_seconds': True}
|
||||||
|
# TODO: set msg_valid based on bid / offer parameters
|
||||||
|
msg_valid = self.SMSG_SECONDS_IN_HOUR * 48
|
||||||
|
ro = self.callrpc('smsgsend', [bid.bid_addr, offer.addr_from, payload_hex, False, msg_valid, False, options])
|
||||||
|
xmr_swap.coin_a_lock_tx_sigs_l_id = bytes.fromhex(ro['msgid'])
|
||||||
|
|
||||||
|
self.log.info('Sent XMR_BID_TXN_SIGS_FL %s', xmr_swap.coin_a_lock_tx_sigs_l_id.hex())
|
||||||
|
|
||||||
|
bid.setState(BidStates.BID_ACCEPTED)
|
||||||
|
session.add(bid)
|
||||||
|
session.add(xmr_swap)
|
||||||
|
|
||||||
|
self.swaps_in_progress[bid_id] = (bid, offer)
|
||||||
|
except Exception as ex:
|
||||||
|
if self.debug:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def sendXmrBidCoinALockTx(self, bid_id, session):
|
||||||
|
# Send coin A lock tx and MSG4F L -> F
|
||||||
|
self.log.debug('Sending coin A lock tx for xmr bid %s', bid_id.hex())
|
||||||
|
|
||||||
|
bid, xmr_swap = self.getXmrBid(bid_id)
|
||||||
|
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
||||||
|
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid_id.hex())
|
||||||
|
|
||||||
|
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=False)
|
||||||
|
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
|
assert(xmr_offer), 'XMR offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
|
coin_from = Coins(offer.coin_from)
|
||||||
|
coin_to = Coins(offer.coin_to)
|
||||||
|
ci_from = self.ci(coin_from)
|
||||||
|
ci_to = self.ci(coin_to)
|
||||||
|
|
||||||
|
kal = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 4)
|
||||||
|
|
||||||
|
xmr_swap.a_lock_spend_tx = ci_from.createScriptLockSpendTx(
|
||||||
|
xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script,
|
||||||
|
xmr_swap.dest_af,
|
||||||
|
xmr_offer.a_fee_rate)
|
||||||
|
|
||||||
|
xmr_swap.al_lock_spend_tx_esig = ci_from.signTxOtVES(kal, xmr_swap.pkasf, xmr_swap.a_lock_spend_tx, 0, xmr_swap.a_lock_tx_script, bid.amount) # self.a_swap_value
|
||||||
|
|
||||||
|
# TODO: Separate MSG4F and txn sending
|
||||||
|
|
||||||
|
|
||||||
|
def processXmrBidCoinALockSigs(self, msg):
|
||||||
|
# Follower processing MSG3L
|
||||||
|
self.log.debug('Processing xmr coin a follower lock sigs msg %s', msg['msgid'])
|
||||||
|
now = int(time.time())
|
||||||
|
msg_bytes = bytes.fromhex(msg['hex'][2:-2])
|
||||||
|
msg_data = XmrBidLockTxSigsMessage()
|
||||||
|
msg_data.ParseFromString(msg_bytes)
|
||||||
|
|
||||||
|
assert(len(msg_data.bid_msg_id) == 28), 'Bad bid_msg_id length'
|
||||||
|
bid_id = msg_data.bid_msg_id
|
||||||
|
|
||||||
|
bid, xmr_swap = self.getXmrBid(bid_id)
|
||||||
|
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
||||||
|
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid_id.hex())
|
||||||
|
|
||||||
|
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=False)
|
||||||
|
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
|
assert(xmr_offer), 'XMR offer not found: {}.'.format(bid.offer_id.hex())
|
||||||
|
coin_from = Coins(offer.coin_from)
|
||||||
|
coin_to = Coins(offer.coin_to)
|
||||||
|
ci_from = self.ci(coin_from)
|
||||||
|
ci_to = self.ci(coin_to)
|
||||||
|
|
||||||
|
try:
|
||||||
|
xmr_swap.af_lock_refund_spend_tx_esig = msg_data.af_lock_refund_spend_tx_esig
|
||||||
|
xmr_swap.af_lock_refund_tx_sig = msg_data.af_lock_refund_tx_sig
|
||||||
|
|
||||||
|
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||||
|
xmr_swap.af_lock_refund_spend_tx_sig = ci_from.decryptOtVES(kbsl, xmr_swap.af_lock_refund_spend_tx_esig)
|
||||||
|
|
||||||
|
print('[rm] xmr_swap.a_swap_refund_value', xmr_swap.a_swap_refund_value)
|
||||||
|
v = ci_from.verifyTxSig(xmr_swap.a_lock_refund_spend_tx, xmr_swap.af_lock_refund_spend_tx_sig, xmr_swap.pkarf, 0, xmr_swap.a_lock_refund_tx_script, xmr_swap.a_swap_refund_value)
|
||||||
|
assert(v), 'Invalid signature for lock refund spend txn'
|
||||||
|
|
||||||
|
delay = random.randrange(self.min_delay_auto_accept, self.max_delay_auto_accept)
|
||||||
|
self.log.info('Sending coin A lock tx for xmr bid %s in %d seconds', bid_id.hex(), delay)
|
||||||
|
self.createEvent(delay, EventTypes.SEND_XMR_SWAP_LOCK_TX_A, bid_id)
|
||||||
|
|
||||||
|
bid.setState(BidStates.SWAP_DELAYING)
|
||||||
|
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
|
||||||
|
except Exception as ex:
|
||||||
|
if self.debug:
|
||||||
|
traceback.print_exc()
|
||||||
|
self.setBidError(bid_id, bid, str(ex))
|
||||||
|
|
||||||
def processXmrSplitMessage(self, msg):
|
def processXmrSplitMessage(self, msg):
|
||||||
self.log.debug('Processing xmr split msg %s', msg['msgid'])
|
self.log.debug('Processing xmr split msg %s', msg['msgid'])
|
||||||
|
@ -2895,7 +3111,6 @@ class BasicSwap(BaseApp):
|
||||||
msg_data.ParseFromString(msg_bytes)
|
msg_data.ParseFromString(msg_bytes)
|
||||||
|
|
||||||
# Validate data
|
# Validate data
|
||||||
print('[rm] msg_data.msg_id', msg_data.msg_id.hex())
|
|
||||||
assert(len(msg_data.msg_id) == 28), 'Bad msg_id length'
|
assert(len(msg_data.msg_id) == 28), 'Bad msg_id length'
|
||||||
|
|
||||||
if msg_data.msg_type == XmrSplitMsgTypes.BID or msg_data.msg_type == XmrSplitMsgTypes.BID_ACCEPT:
|
if msg_data.msg_type == XmrSplitMsgTypes.BID or msg_data.msg_type == XmrSplitMsgTypes.BID_ACCEPT:
|
||||||
|
@ -2923,11 +3138,14 @@ class BasicSwap(BaseApp):
|
||||||
self.processXmrBid(msg)
|
self.processXmrBid(msg)
|
||||||
elif msg_type == MessageTypes.XMR_BID_ACCEPT:
|
elif msg_type == MessageTypes.XMR_BID_ACCEPT:
|
||||||
self.processXmrBidAccept(msg)
|
self.processXmrBidAccept(msg)
|
||||||
|
elif msg_type == MessageTypes.XMR_BID_TXN_SIGS_FL:
|
||||||
|
self.processXmrBidCoinALockSigs(msg)
|
||||||
elif msg_type == MessageTypes.XMR_BID_SPLIT:
|
elif msg_type == MessageTypes.XMR_BID_SPLIT:
|
||||||
self.processXmrSplitMessage(msg)
|
self.processXmrSplitMessage(msg)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.log.error('processMsg %s', str(ex))
|
self.log.error('processMsg %s', str(ex))
|
||||||
|
if self.debug:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
@ -2954,6 +3172,7 @@ class BasicSwap(BaseApp):
|
||||||
pass
|
pass
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.log.error('smsg zmq %s', str(ex))
|
self.log.error('smsg zmq %s', str(ex))
|
||||||
|
if self.debug:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
self.mxDB.acquire()
|
self.mxDB.acquire()
|
||||||
|
@ -2968,6 +3187,7 @@ class BasicSwap(BaseApp):
|
||||||
to_remove.append(bid_id)
|
to_remove.append(bid_id)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.log.error('checkBidState %s %s', bid_id.hex(), str(ex))
|
self.log.error('checkBidState %s %s', bid_id.hex(), str(ex))
|
||||||
|
if self.debug:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.setBidError(bid_id, v[0], str(ex))
|
self.setBidError(bid_id, v[0], str(ex))
|
||||||
|
|
||||||
|
@ -2996,6 +3216,7 @@ class BasicSwap(BaseApp):
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.log.error('update %s', str(ex))
|
self.log.error('update %s', str(ex))
|
||||||
|
if self.debug:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
DEBUG = True
|
|
||||||
|
|
||||||
CONFIG_FILENAME = 'basicswap.json'
|
CONFIG_FILENAME = 'basicswap.json'
|
||||||
DEFAULT_DATADIR = '~/.basicswap'
|
DEFAULT_DATADIR = '~/.basicswap'
|
||||||
TEST_DATADIRS = os.path.expanduser(os.getenv('DATADIRS', '/tmp/basicswap'))
|
TEST_DATADIRS = os.path.expanduser(os.getenv('DATADIRS', '/tmp/basicswap'))
|
||||||
|
|
|
@ -228,15 +228,21 @@ class XmrSwap(Base):
|
||||||
bid_accept_msg_id2 = sa.Column(sa.LargeBinary)
|
bid_accept_msg_id2 = sa.Column(sa.LargeBinary)
|
||||||
bid_accept_msg_id3 = sa.Column(sa.LargeBinary)
|
bid_accept_msg_id3 = sa.Column(sa.LargeBinary)
|
||||||
|
|
||||||
|
coin_a_lock_tx_sigs_l_id = sa.Column(sa.LargeBinary) # MSG3L F -> L
|
||||||
|
|
||||||
contract_count = sa.Column(sa.Integer)
|
contract_count = sa.Column(sa.Integer)
|
||||||
|
|
||||||
sh = sa.Column(sa.LargeBinary) # Secret hash
|
sh = sa.Column(sa.LargeBinary) # Secret hash
|
||||||
|
|
||||||
|
dest_af = sa.Column(sa.LargeBinary) # Destination for coin A amount to follower when swap completes successfully
|
||||||
|
|
||||||
pkal = sa.Column(sa.LargeBinary)
|
pkal = sa.Column(sa.LargeBinary)
|
||||||
pkarl = sa.Column(sa.LargeBinary)
|
pkarl = sa.Column(sa.LargeBinary)
|
||||||
|
pkasl = sa.Column(sa.LargeBinary)
|
||||||
|
|
||||||
pkaf = sa.Column(sa.LargeBinary)
|
pkaf = sa.Column(sa.LargeBinary)
|
||||||
pkarf = sa.Column(sa.LargeBinary)
|
pkarf = sa.Column(sa.LargeBinary)
|
||||||
|
pkasf = sa.Column(sa.LargeBinary)
|
||||||
|
|
||||||
vkbvl = sa.Column(sa.LargeBinary)
|
vkbvl = sa.Column(sa.LargeBinary)
|
||||||
vkbsl = sa.Column(sa.LargeBinary)
|
vkbsl = sa.Column(sa.LargeBinary)
|
||||||
|
@ -260,6 +266,13 @@ class XmrSwap(Base):
|
||||||
|
|
||||||
a_lock_refund_spend_tx = sa.Column(sa.LargeBinary)
|
a_lock_refund_spend_tx = sa.Column(sa.LargeBinary)
|
||||||
|
|
||||||
|
af_lock_refund_spend_tx_esig = sa.Column(sa.LargeBinary)
|
||||||
|
af_lock_refund_spend_tx_sig = sa.Column(sa.LargeBinary)
|
||||||
|
af_lock_refund_tx_sig = sa.Column(sa.LargeBinary)
|
||||||
|
|
||||||
|
a_lock_spend_tx = sa.Column(sa.LargeBinary)
|
||||||
|
al_lock_spend_tx_esig = sa.Column(sa.LargeBinary)
|
||||||
|
|
||||||
b_restore_height = sa.Column(sa.Integer) # Height of xmr chain before the swap
|
b_restore_height = sa.Column(sa.Integer) # Height of xmr chain before the swap
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,25 @@ import time
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from basicswap.contrib.test_framework import segwit_addr
|
||||||
|
|
||||||
|
|
||||||
from .util import (
|
from .util import (
|
||||||
decodeScriptNum,
|
decodeScriptNum,
|
||||||
getCompactSizeLen,
|
getCompactSizeLen,
|
||||||
dumpj,
|
dumpj,
|
||||||
format_amount,
|
format_amount,
|
||||||
make_int
|
make_int,
|
||||||
)
|
decodeAddress)
|
||||||
from coincurve.keys import (
|
from coincurve.keys import (
|
||||||
PublicKey)
|
PublicKey)
|
||||||
from coincurve.dleag import (
|
from coincurve.dleag import (
|
||||||
verify_secp256k1_point)
|
verify_secp256k1_point)
|
||||||
|
from coincurve.ecdsaotves import (
|
||||||
|
ecdsaotves_enc_sign,
|
||||||
|
ecdsaotves_enc_verify,
|
||||||
|
ecdsaotves_dec_sig,
|
||||||
|
ecdsaotves_rec_enc_key)
|
||||||
|
|
||||||
from .ecc_util import (
|
from .ecc_util import (
|
||||||
G, ep,
|
G, ep,
|
||||||
|
@ -59,7 +66,7 @@ from .contrib.test_framework.script import (
|
||||||
|
|
||||||
from .contrib.test_framework.key import ECKey, ECPubKey
|
from .contrib.test_framework.key import ECKey, ECPubKey
|
||||||
|
|
||||||
from .chainparams import CoinInterface
|
from .chainparams import CoinInterface, Coins, chainparams
|
||||||
from .rpc import make_rpc_func
|
from .rpc import make_rpc_func
|
||||||
from .util import assert_cond
|
from .util import assert_cond
|
||||||
|
|
||||||
|
@ -72,6 +79,10 @@ def findOutput(tx, script_pk):
|
||||||
|
|
||||||
|
|
||||||
class BTCInterface(CoinInterface):
|
class BTCInterface(CoinInterface):
|
||||||
|
@staticmethod
|
||||||
|
def coin_type():
|
||||||
|
return Coins.BTC
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exp():
|
def exp():
|
||||||
return 8
|
return 8
|
||||||
|
@ -102,9 +113,10 @@ class BTCInterface(CoinInterface):
|
||||||
def compareFeeRates(self, a, b):
|
def compareFeeRates(self, a, b):
|
||||||
return abs(a - b) < 20
|
return abs(a - b) < 20
|
||||||
|
|
||||||
def __init__(self, coin_settings):
|
def __init__(self, coin_settings, network):
|
||||||
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'])
|
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'])
|
||||||
self.txoType = CTxOut
|
self.txoType = CTxOut
|
||||||
|
self._network = network
|
||||||
|
|
||||||
def testDaemonRPC(self):
|
def testDaemonRPC(self):
|
||||||
self.rpc_callback('getwalletinfo', [])
|
self.rpc_callback('getwalletinfo', [])
|
||||||
|
@ -124,6 +136,13 @@ class BTCInterface(CoinInterface):
|
||||||
args.append('bech32')
|
args.append('bech32')
|
||||||
return self.rpc_callback('getnewaddress', args)
|
return self.rpc_callback('getnewaddress', args)
|
||||||
|
|
||||||
|
def decodeAddress(self, address):
|
||||||
|
bech32_prefix = chainparams[self.coin_type()][self._network]['hrp']
|
||||||
|
if address.startswith(bech32_prefix):
|
||||||
|
ignr, pkhash = segwit_addr.decode(bech32_prefix, address)
|
||||||
|
return pkhash
|
||||||
|
return decodeAddress(address)[1:]
|
||||||
|
|
||||||
def getNewSecretKey(self):
|
def getNewSecretKey(self):
|
||||||
return getSecretInt()
|
return getSecretInt()
|
||||||
|
|
||||||
|
@ -379,8 +398,8 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
return tx.serialize()
|
return tx.serialize()
|
||||||
|
|
||||||
def createScriptLockSpendTx(self, tx_lock, script_lock, pkh_dest, tx_fee_rate):
|
def createScriptLockSpendTx(self, tx_lock_bytes, script_lock, pkh_dest, tx_fee_rate):
|
||||||
|
tx_lock = self.loadTx(tx_lock_bytes)
|
||||||
output_script = CScript([OP_0, hashlib.sha256(script_lock).digest()])
|
output_script = CScript([OP_0, hashlib.sha256(script_lock).digest()])
|
||||||
locked_n = findOutput(tx_lock, output_script)
|
locked_n = findOutput(tx_lock, output_script)
|
||||||
assert_cond(locked_n is not None, 'Output not found in tx')
|
assert_cond(locked_n is not None, 'Output not found in tx')
|
||||||
|
@ -411,7 +430,7 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
return tx.serialize()
|
return tx.serialize()
|
||||||
|
|
||||||
def verifyLockTx(self, tx, script_out,
|
def verifyLockTx(self, tx_bytes, script_out,
|
||||||
swap_value,
|
swap_value,
|
||||||
sh,
|
sh,
|
||||||
Kal, Kaf,
|
Kal, Kaf,
|
||||||
|
@ -425,6 +444,7 @@ class BTCInterface(CoinInterface):
|
||||||
# However by checking early we can avoid wasting time processing unmineable txns
|
# However by checking early we can avoid wasting time processing unmineable txns
|
||||||
# Check fee is reasonable
|
# Check fee is reasonable
|
||||||
|
|
||||||
|
tx = self.loadTx(tx_bytes)
|
||||||
tx_hash = self.getTxHash(tx)
|
tx_hash = self.getTxHash(tx)
|
||||||
logging.info('Verifying lock tx: {}.'.format(b2h(tx_hash)))
|
logging.info('Verifying lock tx: {}.'.format(b2h(tx_hash)))
|
||||||
|
|
||||||
|
@ -441,11 +461,11 @@ class BTCInterface(CoinInterface):
|
||||||
# Check script and values
|
# Check script and values
|
||||||
shv, A, B, csv_val, C, D = self.extractScriptLockScriptValues(script_out)
|
shv, A, B, csv_val, C, D = self.extractScriptLockScriptValues(script_out)
|
||||||
assert_cond(shv == sh, 'Bad hash lock')
|
assert_cond(shv == sh, 'Bad hash lock')
|
||||||
assert_cond(A == self.encodePubkey(Kal), 'Bad script pubkey')
|
assert_cond(A == Kal, 'Bad script pubkey')
|
||||||
assert_cond(B == self.encodePubkey(Kaf), 'Bad script pubkey')
|
assert_cond(B == Kaf, 'Bad script pubkey')
|
||||||
assert_cond(csv_val == lock_value, 'Bad script csv value')
|
assert_cond(csv_val == lock_value, 'Bad script csv value')
|
||||||
assert_cond(C == self.encodePubkey(Karl), 'Bad script pubkey')
|
assert_cond(C == Karl, 'Bad script pubkey')
|
||||||
assert_cond(D == self.encodePubkey(Karf), 'Bad script pubkey')
|
assert_cond(D == Karf, 'Bad script pubkey')
|
||||||
|
|
||||||
if check_lock_tx_inputs:
|
if check_lock_tx_inputs:
|
||||||
# Check that inputs are unspent and verify fee rate
|
# Check that inputs are unspent and verify fee rate
|
||||||
|
@ -454,7 +474,6 @@ class BTCInterface(CoinInterface):
|
||||||
add_witness_bytes = getCompactSizeLen(len(tx.vin))
|
add_witness_bytes = getCompactSizeLen(len(tx.vin))
|
||||||
for pi in tx.vin:
|
for pi in tx.vin:
|
||||||
ptx = self.rpc_callback('getrawtransaction', [i2h(pi.prevout.hash), True])
|
ptx = self.rpc_callback('getrawtransaction', [i2h(pi.prevout.hash), True])
|
||||||
print('ptx', dumpj(ptx))
|
|
||||||
prevout = ptx['vout'][pi.prevout.n]
|
prevout = ptx['vout'][pi.prevout.n]
|
||||||
inputs_value += make_int(prevout['value'])
|
inputs_value += make_int(prevout['value'])
|
||||||
|
|
||||||
|
@ -483,7 +502,7 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
return tx_hash, locked_n
|
return tx_hash, locked_n
|
||||||
|
|
||||||
def verifyLockRefundTx(self, tx, script_out,
|
def verifyLockRefundTx(self, tx_bytes, script_out,
|
||||||
prevout_id, prevout_n, prevout_seq, prevout_script,
|
prevout_id, prevout_n, prevout_seq, prevout_script,
|
||||||
Karl, Karf, csv_val_expect, Kaf, swap_value, feerate):
|
Karl, Karf, csv_val_expect, Kaf, swap_value, feerate):
|
||||||
# Verify:
|
# Verify:
|
||||||
|
@ -491,6 +510,7 @@ class BTCInterface(CoinInterface):
|
||||||
# Must have only one output to the p2wsh of the lock refund script
|
# Must have only one output to the p2wsh of the lock refund script
|
||||||
# Output value must be locked_coin - lock tx fee
|
# Output value must be locked_coin - lock tx fee
|
||||||
|
|
||||||
|
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)))
|
logging.info('Verifying lock refund tx: {}.'.format(b2h(tx_hash)))
|
||||||
|
|
||||||
|
@ -511,10 +531,10 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
# Check script and values
|
# Check script and values
|
||||||
A, B, csv_val, C = self.extractScriptLockRefundScriptValues(script_out)
|
A, B, csv_val, C = self.extractScriptLockRefundScriptValues(script_out)
|
||||||
assert_cond(A == self.encodePubkey(Karl), 'Bad script pubkey')
|
assert_cond(A == Karl, 'Bad script pubkey')
|
||||||
assert_cond(B == self.encodePubkey(Karf), 'Bad script pubkey')
|
assert_cond(B == Karf, 'Bad script pubkey')
|
||||||
assert_cond(csv_val == csv_val_expect, 'Bad script csv value')
|
assert_cond(csv_val == csv_val_expect, 'Bad script csv value')
|
||||||
assert_cond(C == self.encodePubkey(Kaf), 'Bad script pubkey')
|
assert_cond(C == Kaf, 'Bad script pubkey')
|
||||||
|
|
||||||
fee_paid = swap_value - locked_coin
|
fee_paid = swap_value - locked_coin
|
||||||
assert(fee_paid > 0)
|
assert(fee_paid > 0)
|
||||||
|
@ -533,13 +553,14 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
return tx_hash, locked_coin
|
return tx_hash, locked_coin
|
||||||
|
|
||||||
def verifyLockRefundSpendTx(self, tx,
|
def verifyLockRefundSpendTx(self, tx_bytes,
|
||||||
lock_refund_tx_id, prevout_script,
|
lock_refund_tx_id, prevout_script,
|
||||||
Kal,
|
Kal,
|
||||||
prevout_value, feerate):
|
prevout_value, feerate):
|
||||||
# Verify:
|
# Verify:
|
||||||
# Must have only one input with correct prevout (n is always 0) and sequence
|
# Must have only one input with correct prevout (n is always 0) and sequence
|
||||||
# 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_hash = self.getTxHash(tx)
|
tx_hash = self.getTxHash(tx)
|
||||||
logging.info('Verifying lock refund spend tx: {}.'.format(b2h(tx_hash)))
|
logging.info('Verifying lock refund spend tx: {}.'.format(b2h(tx_hash)))
|
||||||
|
|
||||||
|
@ -553,7 +574,7 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
assert_cond(len(tx.vout) == 1, 'tx doesn\'t have one output')
|
assert_cond(len(tx.vout) == 1, 'tx doesn\'t have one output')
|
||||||
|
|
||||||
p2wpkh = CScript([OP_0, hash160(self.encodePubkey(Kal))])
|
p2wpkh = CScript([OP_0, hash160(Kal)])
|
||||||
locked_n = findOutput(tx, p2wpkh)
|
locked_n = findOutput(tx, p2wpkh)
|
||||||
assert_cond(locked_n is not None, 'Output not found in lock refund spend tx')
|
assert_cond(locked_n is not None, 'Output not found in lock refund spend tx')
|
||||||
tx_value = tx.vout[locked_n].nValue
|
tx_value = tx.vout[locked_n].nValue
|
||||||
|
@ -632,16 +653,22 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
return eck.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
return eck.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
||||||
|
|
||||||
def signTxOtVES(self, key_sign, key_encrypt, tx, prevout_n, prevout_script, prevout_value):
|
def signTxOtVES(self, key_sign, pubkey_encrypt, tx_bytes, prevout_n, prevout_script, prevout_value):
|
||||||
|
tx = self.loadTx(tx_bytes)
|
||||||
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
||||||
return otves.EncSign(key_sign, key_encrypt, sig_hash)
|
|
||||||
|
|
||||||
def verifyTxOtVES(self, tx, sig, Ks, Ke, prevout_n, prevout_script, prevout_value):
|
return ecdsaotves_enc_sign(key_sign, pubkey_encrypt, sig_hash)
|
||||||
|
#return otves.EncSign(key_sign, key_encrypt, sig_hash)
|
||||||
|
|
||||||
|
def verifyTxOtVES(self, tx_bytes, sig, Ks, Ke, prevout_n, prevout_script, prevout_value):
|
||||||
|
tx = self.loadTx(tx_bytes)
|
||||||
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
||||||
return otves.EncVrfy(Ks, Ke, sig_hash, sig)
|
return ecdsaotves_enc_verify(Ks, Ke, sig_hash, sig)
|
||||||
|
#return otves.EncVrfy(Ks, Ke, sig_hash, sig)
|
||||||
|
|
||||||
def decryptOtVES(self, k, esig):
|
def decryptOtVES(self, k, esig):
|
||||||
return otves.DecSig(k, esig) + b'\x01' # 0x1 is SIGHASH_ALL
|
return ecdsaotves_dec_sig(k, esig) + b'\x01' # 0x1 is SIGHASH_ALL
|
||||||
|
#return otves.DecSig(k, esig) + b'\x01' # 0x1 is SIGHASH_ALL
|
||||||
|
|
||||||
def verifyTxSig(self, tx_bytes, sig, K, prevout_n, prevout_script, prevout_value):
|
def verifyTxSig(self, tx_bytes, sig, K, prevout_n, prevout_script, prevout_value):
|
||||||
tx = self.loadTx(tx_bytes)
|
tx = self.loadTx(tx_bytes)
|
||||||
|
@ -675,9 +702,9 @@ class BTCInterface(CoinInterface):
|
||||||
tx.deserialize(BytesIO(tx_bytes))
|
tx.deserialize(BytesIO(tx_bytes))
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
def getTxHash(self, tx_bytes):
|
def getTxHash(self, tx):
|
||||||
tx = CTransaction()
|
if isinstance(tx, bytes):
|
||||||
tx = FromHex(tx, tx_bytes.hex())
|
tx = self.loadTx(tx)
|
||||||
tx.rehash()
|
tx.rehash()
|
||||||
return i2b(tx.sha256)
|
return i2b(tx.sha256)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
from .interface_btc import BTCInterface
|
from .interface_btc import BTCInterface
|
||||||
|
from .chainparams import Coins
|
||||||
|
|
||||||
class LTCInterface(BTCInterface):
|
class LTCInterface(BTCInterface):
|
||||||
pass
|
@staticmethod
|
||||||
|
def coin_type():
|
||||||
|
return Coins.LTC
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
from .interface_btc import BTCInterface
|
from .interface_btc import BTCInterface
|
||||||
|
from .chainparams import Coins
|
||||||
|
|
||||||
class NMCInterface(BTCInterface):
|
class NMCInterface(BTCInterface):
|
||||||
pass
|
@staticmethod
|
||||||
|
def coin_type():
|
||||||
|
return Coins.NMC
|
||||||
|
|
|
@ -10,11 +10,15 @@ from .contrib.test_framework.messages import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from .interface_btc import BTCInterface
|
from .interface_btc import BTCInterface
|
||||||
from .chainparams import CoinInterface
|
from .chainparams import CoinInterface, Coins
|
||||||
from .rpc import make_rpc_func
|
from .rpc import make_rpc_func
|
||||||
|
|
||||||
|
|
||||||
class PARTInterface(BTCInterface):
|
class PARTInterface(BTCInterface):
|
||||||
|
@staticmethod
|
||||||
|
def coin_type():
|
||||||
|
return Coins.PART
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def witnessScaleFactor():
|
def witnessScaleFactor():
|
||||||
return 2
|
return 2
|
||||||
|
@ -23,9 +27,10 @@ class PARTInterface(BTCInterface):
|
||||||
def txVersion():
|
def txVersion():
|
||||||
return 0xa0
|
return 0xa0
|
||||||
|
|
||||||
def __init__(self, coin_settings):
|
def __init__(self, coin_settings, network):
|
||||||
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'])
|
self.rpc_callback = make_rpc_func(coin_settings['rpcport'], coin_settings['rpcauth'])
|
||||||
self.txoType = CTxOutPart
|
self.txoType = CTxOutPart
|
||||||
|
self._network = network
|
||||||
|
|
||||||
def getNewAddress(self, use_segwit):
|
def getNewAddress(self, use_segwit):
|
||||||
return self.rpc_callback('getnewaddress', ['swap_receive'])
|
return self.rpc_callback('getnewaddress', ['swap_receive'])
|
||||||
|
|
|
@ -25,12 +25,16 @@ from .rpc_xmr import (
|
||||||
make_xmr_wallet_rpc_func)
|
make_xmr_wallet_rpc_func)
|
||||||
from .ecc_util import (
|
from .ecc_util import (
|
||||||
b2i)
|
b2i)
|
||||||
from .chainparams import CoinInterface
|
from .chainparams import CoinInterface, Coins
|
||||||
|
|
||||||
XMR_COIN = 10 ** 12
|
XMR_COIN = 10 ** 12
|
||||||
|
|
||||||
|
|
||||||
class XMRInterface(CoinInterface):
|
class XMRInterface(CoinInterface):
|
||||||
|
@staticmethod
|
||||||
|
def coin_type():
|
||||||
|
return Coins.XMR
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exp():
|
def exp():
|
||||||
return 12
|
return 12
|
||||||
|
@ -43,12 +47,13 @@ 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):
|
def __init__(self, coin_settings, network):
|
||||||
rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'])
|
rpc_cb = make_xmr_rpc_func(coin_settings['rpcport'])
|
||||||
rpc_wallet_cb = make_xmr_wallet_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'])
|
rpc_wallet_cb = make_xmr_wallet_rpc_func(coin_settings['walletrpcport'], coin_settings['walletrpcauth'])
|
||||||
|
|
||||||
self.rpc_cb = rpc_cb
|
self.rpc_cb = rpc_cb
|
||||||
self.rpc_wallet_cb = rpc_wallet_cb
|
self.rpc_wallet_cb = rpc_wallet_cb
|
||||||
|
self._network = network
|
||||||
|
|
||||||
def testDaemonRPC(self):
|
def testDaemonRPC(self):
|
||||||
self.rpc_wallet_cb('get_languages')
|
self.rpc_wallet_cb('get_languages')
|
||||||
|
|
|
@ -51,9 +51,8 @@ message BidAcceptMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Step 2, buyer -> seller */
|
|
||||||
message XmrBidMessage {
|
message XmrBidMessage {
|
||||||
|
/* MSG1L, F -> L */
|
||||||
bytes offer_msg_id = 1;
|
bytes offer_msg_id = 1;
|
||||||
uint64 time_valid = 2; /* seconds bid is valid for */
|
uint64 time_valid = 2; /* seconds bid is valid for */
|
||||||
uint64 amount = 3; /* amount of amount_from bid is for */
|
uint64 amount = 3; /* amount of amount_from bid is for */
|
||||||
|
@ -63,6 +62,8 @@ message XmrBidMessage {
|
||||||
|
|
||||||
bytes kbvf = 6;
|
bytes kbvf = 6;
|
||||||
bytes kbsf_dleag = 7;
|
bytes kbsf_dleag = 7;
|
||||||
|
|
||||||
|
bytes dest_af = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message XmrSplitMessage {
|
message XmrSplitMessage {
|
||||||
|
@ -72,7 +73,6 @@ message XmrSplitMessage {
|
||||||
bytes dleag = 4;
|
bytes dleag = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
message XmrBidAcceptMessage {
|
message XmrBidAcceptMessage {
|
||||||
bytes bid_msg_id = 1;
|
bytes bid_msg_id = 1;
|
||||||
|
|
||||||
|
@ -92,3 +92,20 @@ message XmrBidAcceptMessage {
|
||||||
bytes al_lock_refund_tx_sig = 12;
|
bytes al_lock_refund_tx_sig = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message XmrBidLockTxSigsMessage {
|
||||||
|
/* MSG3L */
|
||||||
|
bytes bid_msg_id = 1;
|
||||||
|
|
||||||
|
bytes af_lock_refund_spend_tx_esig = 2;
|
||||||
|
bytes af_lock_refund_tx_sig = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message XmrBidLockSpendTxMessage {
|
||||||
|
/* MSG4F */
|
||||||
|
bytes bid_msg_id = 1;
|
||||||
|
|
||||||
|
bytes a_lock_spend_tx = 2;
|
||||||
|
bytes al_lock_spend_tx_esig = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
syntax='proto3',
|
syntax='proto3',
|
||||||
serialized_options=None,
|
serialized_options=None,
|
||||||
create_key=_descriptor._internal_create_key,
|
create_key=_descriptor._internal_create_key,
|
||||||
serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\xd8\x03\n\x0cOfferMessage\x12\x11\n\tcoin_from\x18\x01 \x01(\r\x12\x0f\n\x07\x63oin_to\x18\x02 \x01(\r\x12\x13\n\x0b\x61mount_from\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x16\n\x0emin_bid_amount\x18\x05 \x01(\x04\x12\x12\n\ntime_valid\x18\x06 \x01(\x04\x12\x33\n\tlock_type\x18\x07 \x01(\x0e\x32 .basicswap.OfferMessage.LockType\x12\x12\n\nlock_value\x18\x08 \x01(\r\x12\x11\n\tswap_type\x18\t \x01(\r\x12\x15\n\rproof_address\x18\n \x01(\t\x12\x17\n\x0fproof_signature\x18\x0b \x01(\t\x12\x15\n\rpkhash_seller\x18\x0c \x01(\x0c\x12\x13\n\x0bsecret_hash\x18\r \x01(\x0c\x12\x15\n\rfee_rate_from\x18\x0e \x01(\x04\x12\x13\n\x0b\x66\x65\x65_rate_to\x18\x0f \x01(\x04\"q\n\x08LockType\x12\x0b\n\x07NOT_SET\x10\x00\x12\x18\n\x14SEQUENCE_LOCK_BLOCKS\x10\x01\x12\x16\n\x12SEQUENCE_LOCK_TIME\x10\x02\x12\x13\n\x0f\x41\x42S_LOCK_BLOCKS\x10\x03\x12\x11\n\rABS_LOCK_TIME\x10\x04\"\x8c\x01\n\nBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x04 \x01(\x0c\x12\x15\n\rproof_address\x18\x05 \x01(\t\x12\x17\n\x0fproof_signature\x18\x06 \x01(\t\"V\n\x10\x42idAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x15\n\rinitiate_txid\x18\x02 \x01(\x0c\x12\x17\n\x0f\x63ontract_script\x18\x03 \x01(\x0c\"\x88\x01\n\rXmrBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04pkaf\x18\x04 \x01(\x0c\x12\r\n\x05pkarf\x18\x05 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x06 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x07 \x01(\x0c\"T\n\x0fXmrSplitMessage\x12\x0e\n\x06msg_id\x18\x01 \x01(\x0c\x12\x10\n\x08msg_type\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\r\n\x05\x64leag\x18\x04 \x01(\x0c\"\x9b\x02\n\x13XmrBidAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\n\n\x02sh\x18\x02 \x01(\x0c\x12\x0c\n\x04pkal\x18\x03 \x01(\x0c\x12\r\n\x05pkarl\x18\x04 \x01(\x0c\x12\x0c\n\x04kbvl\x18\x05 \x01(\x0c\x12\x12\n\nkbsl_dleag\x18\x06 \x01(\x0c\x12\x11\n\ta_lock_tx\x18\x07 \x01(\x0c\x12\x18\n\x10\x61_lock_tx_script\x18\x08 \x01(\x0c\x12\x18\n\x10\x61_lock_refund_tx\x18\t \x01(\x0c\x12\x1f\n\x17\x61_lock_refund_tx_script\x18\n \x01(\x0c\x12\x1e\n\x16\x61_lock_refund_spend_tx\x18\x0b \x01(\x0c\x12\x1d\n\x15\x61l_lock_refund_tx_sig\x18\x0c \x01(\x0c\x62\x06proto3'
|
serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\xd8\x03\n\x0cOfferMessage\x12\x11\n\tcoin_from\x18\x01 \x01(\r\x12\x0f\n\x07\x63oin_to\x18\x02 \x01(\r\x12\x13\n\x0b\x61mount_from\x18\x03 \x01(\x04\x12\x0c\n\x04rate\x18\x04 \x01(\x04\x12\x16\n\x0emin_bid_amount\x18\x05 \x01(\x04\x12\x12\n\ntime_valid\x18\x06 \x01(\x04\x12\x33\n\tlock_type\x18\x07 \x01(\x0e\x32 .basicswap.OfferMessage.LockType\x12\x12\n\nlock_value\x18\x08 \x01(\r\x12\x11\n\tswap_type\x18\t \x01(\r\x12\x15\n\rproof_address\x18\n \x01(\t\x12\x17\n\x0fproof_signature\x18\x0b \x01(\t\x12\x15\n\rpkhash_seller\x18\x0c \x01(\x0c\x12\x13\n\x0bsecret_hash\x18\r \x01(\x0c\x12\x15\n\rfee_rate_from\x18\x0e \x01(\x04\x12\x13\n\x0b\x66\x65\x65_rate_to\x18\x0f \x01(\x04\"q\n\x08LockType\x12\x0b\n\x07NOT_SET\x10\x00\x12\x18\n\x14SEQUENCE_LOCK_BLOCKS\x10\x01\x12\x16\n\x12SEQUENCE_LOCK_TIME\x10\x02\x12\x13\n\x0f\x41\x42S_LOCK_BLOCKS\x10\x03\x12\x11\n\rABS_LOCK_TIME\x10\x04\"\x8c\x01\n\nBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x14\n\x0cpkhash_buyer\x18\x04 \x01(\x0c\x12\x15\n\rproof_address\x18\x05 \x01(\t\x12\x17\n\x0fproof_signature\x18\x06 \x01(\t\"V\n\x10\x42idAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x15\n\rinitiate_txid\x18\x02 \x01(\x0c\x12\x17\n\x0f\x63ontract_script\x18\x03 \x01(\x0c\"\x99\x01\n\rXmrBidMessage\x12\x14\n\x0coffer_msg_id\x18\x01 \x01(\x0c\x12\x12\n\ntime_valid\x18\x02 \x01(\x04\x12\x0e\n\x06\x61mount\x18\x03 \x01(\x04\x12\x0c\n\x04pkaf\x18\x04 \x01(\x0c\x12\r\n\x05pkarf\x18\x05 \x01(\x0c\x12\x0c\n\x04kbvf\x18\x06 \x01(\x0c\x12\x12\n\nkbsf_dleag\x18\x07 \x01(\x0c\x12\x0f\n\x07\x64\x65st_af\x18\x08 \x01(\x0c\"T\n\x0fXmrSplitMessage\x12\x0e\n\x06msg_id\x18\x01 \x01(\x0c\x12\x10\n\x08msg_type\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\x12\r\n\x05\x64leag\x18\x04 \x01(\x0c\"\x9b\x02\n\x13XmrBidAcceptMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\n\n\x02sh\x18\x02 \x01(\x0c\x12\x0c\n\x04pkal\x18\x03 \x01(\x0c\x12\r\n\x05pkarl\x18\x04 \x01(\x0c\x12\x0c\n\x04kbvl\x18\x05 \x01(\x0c\x12\x12\n\nkbsl_dleag\x18\x06 \x01(\x0c\x12\x11\n\ta_lock_tx\x18\x07 \x01(\x0c\x12\x18\n\x10\x61_lock_tx_script\x18\x08 \x01(\x0c\x12\x18\n\x10\x61_lock_refund_tx\x18\t \x01(\x0c\x12\x1f\n\x17\x61_lock_refund_tx_script\x18\n \x01(\x0c\x12\x1e\n\x16\x61_lock_refund_spend_tx\x18\x0b \x01(\x0c\x12\x1d\n\x15\x61l_lock_refund_tx_sig\x18\x0c \x01(\x0c\"r\n\x17XmrBidLockTxSigsMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12$\n\x1c\x61\x66_lock_refund_spend_tx_esig\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61\x66_lock_refund_tx_sig\x18\x03 \x01(\x0c\"f\n\x18XmrBidLockSpendTxMessage\x12\x12\n\nbid_msg_id\x18\x01 \x01(\x0c\x12\x17\n\x0f\x61_lock_spend_tx\x18\x02 \x01(\x0c\x12\x1d\n\x15\x61l_lock_spend_tx_esig\x18\x03 \x01(\x0c\x62\x06proto3'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -366,6 +366,13 @@ _XMRBIDMESSAGE = _descriptor.Descriptor(
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='dest_af', full_name='basicswap.XmrBidMessage.dest_af', index=7,
|
||||||
|
number=8, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
],
|
],
|
||||||
extensions=[
|
extensions=[
|
||||||
],
|
],
|
||||||
|
@ -379,7 +386,7 @@ _XMRBIDMESSAGE = _descriptor.Descriptor(
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=736,
|
serialized_start=736,
|
||||||
serialized_end=872,
|
serialized_end=889,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -431,8 +438,8 @@ _XMRSPLITMESSAGE = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=874,
|
serialized_start=891,
|
||||||
serialized_end=958,
|
serialized_end=975,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -540,8 +547,100 @@ _XMRBIDACCEPTMESSAGE = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=961,
|
serialized_start=978,
|
||||||
serialized_end=1244,
|
serialized_end=1261,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_XMRBIDLOCKTXSIGSMESSAGE = _descriptor.Descriptor(
|
||||||
|
name='XmrBidLockTxSigsMessage',
|
||||||
|
full_name='basicswap.XmrBidLockTxSigsMessage',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
create_key=_descriptor._internal_create_key,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='bid_msg_id', full_name='basicswap.XmrBidLockTxSigsMessage.bid_msg_id', index=0,
|
||||||
|
number=1, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='af_lock_refund_spend_tx_esig', full_name='basicswap.XmrBidLockTxSigsMessage.af_lock_refund_spend_tx_esig', index=1,
|
||||||
|
number=2, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='af_lock_refund_tx_sig', full_name='basicswap.XmrBidLockTxSigsMessage.af_lock_refund_tx_sig', index=2,
|
||||||
|
number=3, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
],
|
||||||
|
serialized_options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
syntax='proto3',
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=1263,
|
||||||
|
serialized_end=1377,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_XMRBIDLOCKSPENDTXMESSAGE = _descriptor.Descriptor(
|
||||||
|
name='XmrBidLockSpendTxMessage',
|
||||||
|
full_name='basicswap.XmrBidLockSpendTxMessage',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
create_key=_descriptor._internal_create_key,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='bid_msg_id', full_name='basicswap.XmrBidLockSpendTxMessage.bid_msg_id', index=0,
|
||||||
|
number=1, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='a_lock_spend_tx', full_name='basicswap.XmrBidLockSpendTxMessage.a_lock_spend_tx', index=1,
|
||||||
|
number=2, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='al_lock_spend_tx_esig', full_name='basicswap.XmrBidLockSpendTxMessage.al_lock_spend_tx_esig', index=2,
|
||||||
|
number=3, type=12, cpp_type=9, label=1,
|
||||||
|
has_default_value=False, default_value=b"",
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
],
|
||||||
|
serialized_options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
syntax='proto3',
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=1379,
|
||||||
|
serialized_end=1481,
|
||||||
)
|
)
|
||||||
|
|
||||||
_OFFERMESSAGE.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE
|
_OFFERMESSAGE.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE
|
||||||
|
@ -552,6 +651,8 @@ DESCRIPTOR.message_types_by_name['BidAcceptMessage'] = _BIDACCEPTMESSAGE
|
||||||
DESCRIPTOR.message_types_by_name['XmrBidMessage'] = _XMRBIDMESSAGE
|
DESCRIPTOR.message_types_by_name['XmrBidMessage'] = _XMRBIDMESSAGE
|
||||||
DESCRIPTOR.message_types_by_name['XmrSplitMessage'] = _XMRSPLITMESSAGE
|
DESCRIPTOR.message_types_by_name['XmrSplitMessage'] = _XMRSPLITMESSAGE
|
||||||
DESCRIPTOR.message_types_by_name['XmrBidAcceptMessage'] = _XMRBIDACCEPTMESSAGE
|
DESCRIPTOR.message_types_by_name['XmrBidAcceptMessage'] = _XMRBIDACCEPTMESSAGE
|
||||||
|
DESCRIPTOR.message_types_by_name['XmrBidLockTxSigsMessage'] = _XMRBIDLOCKTXSIGSMESSAGE
|
||||||
|
DESCRIPTOR.message_types_by_name['XmrBidLockSpendTxMessage'] = _XMRBIDLOCKSPENDTXMESSAGE
|
||||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), {
|
OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), {
|
||||||
|
@ -596,5 +697,19 @@ XmrBidAcceptMessage = _reflection.GeneratedProtocolMessageType('XmrBidAcceptMess
|
||||||
})
|
})
|
||||||
_sym_db.RegisterMessage(XmrBidAcceptMessage)
|
_sym_db.RegisterMessage(XmrBidAcceptMessage)
|
||||||
|
|
||||||
|
XmrBidLockTxSigsMessage = _reflection.GeneratedProtocolMessageType('XmrBidLockTxSigsMessage', (_message.Message,), {
|
||||||
|
'DESCRIPTOR' : _XMRBIDLOCKTXSIGSMESSAGE,
|
||||||
|
'__module__' : 'messages_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:basicswap.XmrBidLockTxSigsMessage)
|
||||||
|
})
|
||||||
|
_sym_db.RegisterMessage(XmrBidLockTxSigsMessage)
|
||||||
|
|
||||||
|
XmrBidLockSpendTxMessage = _reflection.GeneratedProtocolMessageType('XmrBidLockSpendTxMessage', (_message.Message,), {
|
||||||
|
'DESCRIPTOR' : _XMRBIDLOCKSPENDTXMESSAGE,
|
||||||
|
'__module__' : 'messages_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:basicswap.XmrBidLockSpendTxMessage)
|
||||||
|
})
|
||||||
|
_sym_db.RegisterMessage(XmrBidLockSpendTxMessage)
|
||||||
|
|
||||||
|
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|
|
@ -135,6 +135,7 @@ def prepareDir(datadir, nodeId, network_key, network_pubkey):
|
||||||
btcdatadir = os.path.join(datadir, str(BTC_NODE))
|
btcdatadir = os.path.join(datadir, str(BTC_NODE))
|
||||||
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
|
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
|
||||||
settings = {
|
settings = {
|
||||||
|
'debug': True,
|
||||||
'zmqhost': 'tcp://127.0.0.1',
|
'zmqhost': 'tcp://127.0.0.1',
|
||||||
'zmqport': BASE_ZMQ_PORT + nodeId,
|
'zmqport': BASE_ZMQ_PORT + nodeId,
|
||||||
'htmlhost': 'localhost',
|
'htmlhost': 'localhost',
|
||||||
|
|
|
@ -139,6 +139,7 @@ def prepareDir(datadir, nodeId, network_key, network_pubkey):
|
||||||
btcdatadir = os.path.join(datadir, str(BTC_NODE))
|
btcdatadir = os.path.join(datadir, str(BTC_NODE))
|
||||||
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
|
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
|
||||||
settings = {
|
settings = {
|
||||||
|
'debug': True,
|
||||||
'zmqhost': 'tcp://127.0.0.1',
|
'zmqhost': 'tcp://127.0.0.1',
|
||||||
'zmqport': BASE_ZMQ_PORT + nodeId,
|
'zmqport': BASE_ZMQ_PORT + nodeId,
|
||||||
'htmlhost': 'localhost',
|
'htmlhost': 'localhost',
|
||||||
|
|
|
@ -198,6 +198,7 @@ def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
|
||||||
|
|
||||||
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
|
settings_path = os.path.join(basicswap_dir, cfg.CONFIG_FILENAME)
|
||||||
settings = {
|
settings = {
|
||||||
|
'debug': True,
|
||||||
'zmqhost': 'tcp://127.0.0.1',
|
'zmqhost': 'tcp://127.0.0.1',
|
||||||
'zmqport': BASE_ZMQ_PORT + node_id,
|
'zmqport': BASE_ZMQ_PORT + node_id,
|
||||||
'htmlhost': 'localhost',
|
'htmlhost': 'localhost',
|
||||||
|
@ -513,9 +514,9 @@ class Test(unittest.TestCase):
|
||||||
return
|
return
|
||||||
raise ValueError('wait_for_offer timed out.')
|
raise ValueError('wait_for_offer timed out.')
|
||||||
|
|
||||||
def wait_for_bid(self, swap_client, bid_id, state=None, sent=False):
|
def wait_for_bid(self, swap_client, bid_id, state=None, sent=False, wait_for=20):
|
||||||
logging.info('wait_for_bid %s', bid_id.hex())
|
logging.info('wait_for_bid %s', bid_id.hex())
|
||||||
for i in range(20):
|
for i in range(wait_for):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
bids = swap_client.listBids(sent=sent)
|
bids = swap_client.listBids(sent=sent)
|
||||||
for bid in bids:
|
for bid in bids:
|
||||||
|
@ -551,7 +552,11 @@ class Test(unittest.TestCase):
|
||||||
|
|
||||||
swap_clients[0].acceptXmrBid(bid_id)
|
swap_clients[0].acceptXmrBid(bid_id)
|
||||||
|
|
||||||
self.wait_for_bid(swap_clients[1], bid_id, BidStates.BID_ACCEPTED, sent=True)
|
self.wait_for_bid(swap_clients[1], bid_id, BidStates.BID_ACCEPTED, sent=True, wait_for=40)
|
||||||
|
|
||||||
|
|
||||||
|
self.wait_for_bid(swap_clients[0], bid_id, BidStates.XMR_SWAP_SCRIPT_COIN_LOCKED, sent=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue