mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-18 16:44:34 +00:00
Send MSG2F
This commit is contained in:
parent
acae8b4de3
commit
009729aa96
11 changed files with 1551 additions and 234 deletions
|
@ -6,18 +6,20 @@
|
|||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import datetime as dt
|
||||
import zmq
|
||||
import traceback
|
||||
import hashlib
|
||||
import sqlalchemy as sa
|
||||
import shutil
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
import random
|
||||
import logging
|
||||
import secrets
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
import hashlib
|
||||
import datetime as dt
|
||||
import traceback
|
||||
import sqlalchemy as sa
|
||||
|
||||
from enum import IntEnum, auto
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
|
||||
from .interface_part import PARTInterface
|
||||
from .interface_btc import BTCInterface
|
||||
|
@ -39,6 +41,7 @@ from .util import (
|
|||
toWIF,
|
||||
getKeyID,
|
||||
make_int,
|
||||
dumpj
|
||||
)
|
||||
from .chainparams import (
|
||||
chainparams,
|
||||
|
@ -51,6 +54,9 @@ from .messages_pb2 import (
|
|||
OfferMessage,
|
||||
BidMessage,
|
||||
BidAcceptMessage,
|
||||
XmrBidMessage,
|
||||
XmrBidAcceptMessage,
|
||||
XmrSplitMessage,
|
||||
)
|
||||
from .db import (
|
||||
CURRENT_DB_VERSION,
|
||||
|
@ -64,6 +70,9 @@ from .db import (
|
|||
SentOffer,
|
||||
SmsgAddress,
|
||||
EventQueue,
|
||||
XmrOffer,
|
||||
XmrSwap,
|
||||
XmrSplitData,
|
||||
)
|
||||
|
||||
from .explorers import ExplorerInsight, ExplorerBitAps, ExplorerChainz
|
||||
|
@ -83,6 +92,9 @@ class MessageTypes(IntEnum):
|
|||
BID_ACCEPT = auto()
|
||||
|
||||
XMR_OFFER = auto()
|
||||
XMR_BID = auto()
|
||||
XMR_BID_SPLIT = auto()
|
||||
XMR_BID_ACCEPT = auto()
|
||||
|
||||
|
||||
class SwapTypes(IntEnum):
|
||||
|
@ -101,7 +113,9 @@ class OfferStates(IntEnum):
|
|||
|
||||
class BidStates(IntEnum):
|
||||
BID_SENT = auto()
|
||||
BID_RECEIVING = auto() # Partially received
|
||||
BID_RECEIVED = auto()
|
||||
BID_RECEIVING_ACC = auto() # Partially received accept message
|
||||
BID_ACCEPTED = auto() # BidAcceptMessage received/sent
|
||||
SWAP_INITIATED = auto() # Initiate txn validated
|
||||
SWAP_PARTICIPATING = auto() # Participate txn validated
|
||||
|
@ -132,6 +146,11 @@ class EventTypes(IntEnum):
|
|||
ACCEPT_BID = auto()
|
||||
|
||||
|
||||
class XmrSplitMsgTypes(IntEnum):
|
||||
BID = auto()
|
||||
BID_ACCEPT = auto()
|
||||
|
||||
|
||||
SEQUENCE_LOCK_BLOCKS = 1
|
||||
SEQUENCE_LOCK_TIME = 2
|
||||
ABS_LOCK_BLOCKS = 3
|
||||
|
@ -298,10 +317,12 @@ class BasicSwap(BaseApp):
|
|||
self.check_watched_seconds = self.settings.get('check_watched_seconds', 60)
|
||||
self.check_expired_seconds = self.settings.get('check_expired_seconds', 60 * 5)
|
||||
self.check_events_seconds = self.settings.get('check_events_seconds', 10)
|
||||
self.last_checked_progress = 0
|
||||
self.last_checked_watched = 0
|
||||
self.last_checked_expired = 0
|
||||
self.last_checked_events = 0
|
||||
self.check_xmr_swaps_seconds = self.settings.get('check_xmr_swaps_seconds', 20)
|
||||
self._last_checked_progress = 0
|
||||
self._last_checked_watched = 0
|
||||
self._last_checked_expired = 0
|
||||
self._last_checked_events = 0
|
||||
self._last_checked_xmr_swaps = 0
|
||||
|
||||
# TODO: Adjust ranges
|
||||
self.min_delay_auto_accept = self.settings.get('min_delay_auto_accept', 10)
|
||||
|
@ -321,7 +342,7 @@ class BasicSwap(BaseApp):
|
|||
self.network_key = toWIF(wif_prefix, decodeWif(self.settings['network_key']))
|
||||
|
||||
self.network_pubkey = self.settings['network_pubkey']
|
||||
self.network_addr = pubkeyToAddress(chainparams[Coins.PART][self.chain]['pubkey_address'], bytearray.fromhex(self.network_pubkey))
|
||||
self.network_addr = pubkeyToAddress(chainparams[Coins.PART][self.chain]['pubkey_address'], bytes.fromhex(self.network_pubkey))
|
||||
#self.wallet = self.settings.get('wallet', None) # TODO: Move to coin_clients
|
||||
|
||||
self.sqlite_file = os.path.join(self.data_dir, 'db{}.sqlite'.format('' if self.chain == 'mainnet' else ('_' + self.chain)))
|
||||
|
@ -351,15 +372,6 @@ class BasicSwap(BaseApp):
|
|||
value=self._contract_count
|
||||
))
|
||||
session.commit()
|
||||
try:
|
||||
self._offer_count = session.query(DBKVInt).filter_by(key='offer_count').first().value
|
||||
except Exception:
|
||||
self._offer_count = 0
|
||||
session.add(DBKVInt(
|
||||
key='offer_count',
|
||||
value=self._offer_count
|
||||
))
|
||||
session.commit()
|
||||
session.close()
|
||||
session.remove()
|
||||
|
||||
|
@ -450,6 +462,9 @@ class BasicSwap(BaseApp):
|
|||
raise ValueError('Missing XMR wallet rpc credentials.')
|
||||
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
||||
|
||||
def ci(self, coin): # coin interface
|
||||
return self.coin_clients[coin]['interface']
|
||||
|
||||
def createInterface(self, coin):
|
||||
if coin == Coins.PART:
|
||||
return PARTInterface(self.coin_clients[coin])
|
||||
|
@ -741,13 +756,8 @@ class BasicSwap(BaseApp):
|
|||
offer_addr = self.callrpc('getnewaddress') if addr_send_from is None else addr_send_from
|
||||
|
||||
offer_created_at = int(time.time())
|
||||
if swap_type == SwapTypes.XMR_SWAP:
|
||||
msg_buf = XmrOfferMessage()
|
||||
|
||||
key_path = "44445555h/999999/{}/{}/{}/{}".format(int(coin_from), int(coin_to), offer_created_at, )
|
||||
|
||||
else:
|
||||
msg_buf = OfferMessage()
|
||||
msg_buf = OfferMessage()
|
||||
|
||||
msg_buf.coin_from = int(coin_from)
|
||||
msg_buf.coin_to = int(coin_to)
|
||||
|
@ -760,6 +770,18 @@ class BasicSwap(BaseApp):
|
|||
msg_buf.lock_value = lock_value
|
||||
msg_buf.swap_type = swap_type
|
||||
|
||||
if swap_type == SwapTypes.XMR_SWAP:
|
||||
xmr_offer = XmrOffer()
|
||||
|
||||
xmr_offer.lock_time_1 = lock_value # Delay before the chain a lock refund tx can be mined
|
||||
xmr_offer.lock_time_2 = lock_value # Delay before the follower can spend from the chain a lock refund tx
|
||||
|
||||
# TODO: Dynamic fee selection
|
||||
xmr_offer.a_fee_rate = make_int(0.00032595, self.ci(coin_from).exp())
|
||||
xmr_offer.b_fee_rate = make_int(0.0012595, self.ci(coin_to).exp())
|
||||
msg_buf.fee_rate_from = xmr_offer.a_fee_rate
|
||||
msg_buf.fee_rate_to = xmr_offer.b_fee_rate
|
||||
|
||||
offer_bytes = msg_buf.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.OFFER) + offer_bytes.hex()
|
||||
|
||||
|
@ -792,6 +814,10 @@ class BasicSwap(BaseApp):
|
|||
auto_accept_bids=auto_accept_bids,)
|
||||
offer.setState(OfferStates.OFFER_SENT)
|
||||
|
||||
if swap_type == SwapTypes.XMR_SWAP:
|
||||
xmr_offer.offer_id = offer_id
|
||||
session.add(xmr_offer)
|
||||
|
||||
session.add(offer)
|
||||
session.add(SentOffer(offer_id=offer_id))
|
||||
if addr_send_from is None:
|
||||
|
@ -804,6 +830,31 @@ class BasicSwap(BaseApp):
|
|||
self.log.info('Sent OFFER %s', offer_id.hex())
|
||||
return offer_id
|
||||
|
||||
def getPathKey(self, coin_from, coin_to, offer_created_at, contract_count, key_no, for_xmr=False):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
evkey = self.callcoinrpc(Coins.PART, 'extkey', ['account', 'default', 'true'])['evkey']
|
||||
ci = self.ci(coin_to)
|
||||
|
||||
days = offer_created_at // 86400
|
||||
secs = offer_created_at - days * 86400
|
||||
key_path_base = '44445555h/999999/{}/{}/{}/{}/{}/{}'.format(int(coin_from), int(coin_to), days, secs, contract_count, key_no)
|
||||
|
||||
if not for_xmr:
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path_base])['key_info']['result']
|
||||
return decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
nonce = 1
|
||||
while True:
|
||||
key_path = key_path_base + '/{}'.format(nonce)
|
||||
extkey = self.callcoinrpc(Coins.PART, 'extkey', ['info', evkey, key_path])['key_info']['result']
|
||||
privkey = decodeWif(self.callcoinrpc(Coins.PART, 'extkey', ['info', extkey])['key_info']['privkey'])
|
||||
|
||||
if ci.isValidKey(privkey):
|
||||
return privkey
|
||||
nonce += 1
|
||||
if nonce > 1000:
|
||||
raise ValueError('getKeyForXMR failed')
|
||||
|
||||
def getContractPubkey(self, date, contract_count):
|
||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||
|
||||
|
@ -1005,18 +1056,31 @@ class BasicSwap(BaseApp):
|
|||
|
||||
return (sign_for_addr, signature)
|
||||
|
||||
def saveBidInSession(self, bid_id, bid, session):
|
||||
def saveBidInSession(self, bid_id, bid, session, xmr_swap=None):
|
||||
session.add(bid)
|
||||
if bid.initiate_tx:
|
||||
session.add(bid.initiate_tx)
|
||||
if bid.participate_tx:
|
||||
session.add(bid.participate_tx)
|
||||
if xmr_swap is not None:
|
||||
session.add(xmr_swap)
|
||||
|
||||
def saveBid(self, bid_id, bid):
|
||||
def saveBid(self, bid_id, bid, xmr_swap=None):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
session = scoped_session(self.session_factory)
|
||||
self.saveBidInSession(bid_id, bid, session)
|
||||
self.saveBidInSession(bid_id, bid, session, xmr_swap)
|
||||
session.commit()
|
||||
session.close()
|
||||
session.remove()
|
||||
finally:
|
||||
self.mxDB.release()
|
||||
|
||||
def saveToDB(self, db_record):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
session = scoped_session(self.session_factory)
|
||||
session.add(db_record)
|
||||
session.commit()
|
||||
session.close()
|
||||
session.remove()
|
||||
|
@ -1070,6 +1134,8 @@ class BasicSwap(BaseApp):
|
|||
proof_addr, proof_sig = self.getProofOfFunds(coin_to, msg_buf.amount)
|
||||
msg_buf.proof_address = proof_addr
|
||||
msg_buf.proof_signature = proof_sig
|
||||
else:
|
||||
raise ValueError('TODO')
|
||||
|
||||
bid_bytes = msg_buf.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.BID) + bid_bytes.hex()
|
||||
|
@ -1124,6 +1190,34 @@ class BasicSwap(BaseApp):
|
|||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def getXmrBid(self, bid_id, sent=False):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
session = scoped_session(self.session_factory)
|
||||
bid = session.query(Bid).filter_by(bid_id=bid_id).first()
|
||||
xmr_swap = None
|
||||
if bid:
|
||||
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid_id).first()
|
||||
return bid, xmr_swap
|
||||
finally:
|
||||
session.close()
|
||||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def getXmrOffer(self, offer_id, sent=False):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
session = scoped_session(self.session_factory)
|
||||
offer = session.query(Offer).filter_by(offer_id=offer_id).first()
|
||||
xmr_offer = None
|
||||
if offer:
|
||||
xmr_offer = session.query(XmrOffer).filter_by(offer_id=offer_id).first()
|
||||
return offer, xmr_offer
|
||||
finally:
|
||||
session.close()
|
||||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def getBid(self, bid_id):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
|
@ -1244,6 +1338,254 @@ class BasicSwap(BaseApp):
|
|||
self.saveBid(bid_id, bid)
|
||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
||||
|
||||
def postXmrBid(self, offer_id, amount, addr_send_from=None):
|
||||
# Bid to send bid.amount * offer.rate of coin_to in exchange for bid.amount of coin_from
|
||||
# Send MSG1L F -> L
|
||||
self.log.debug('postBid %s %s', offer_id.hex(), format8(amount))
|
||||
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
offer, xmr_offer = self.getXmrOffer(offer_id)
|
||||
|
||||
assert(offer), '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'
|
||||
|
||||
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_to = Coins(offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
self.checkSynced(coin_from, coin_to)
|
||||
|
||||
bid_created_at = int(time.time())
|
||||
if offer.swap_type != SwapTypes.XMR_SWAP:
|
||||
raise ValueError('TODO')
|
||||
|
||||
# Follower to leader
|
||||
xmr_swap = XmrSwap()
|
||||
xmr_swap.contract_count = self.getNewContractId()
|
||||
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)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
|
||||
kaf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 3)
|
||||
karf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, 4)
|
||||
|
||||
xmr_swap.pkaf = ci_from.getPubkey(kaf)
|
||||
xmr_swap.pkarf = ci_from.getPubkey(karf)
|
||||
|
||||
xmr_swap.kbsf_dleag = ci_to.proveDLEAG(kbsf)
|
||||
|
||||
msg_buf.pkaf = xmr_swap.pkaf
|
||||
msg_buf.pkarf = xmr_swap.pkarf
|
||||
msg_buf.kbvf = kbvf
|
||||
msg_buf.kbsf_dleag = xmr_swap.kbsf_dleag[:16000]
|
||||
|
||||
bid_bytes = msg_buf.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID) + bid_bytes.hex()
|
||||
|
||||
if addr_send_from is None:
|
||||
bid_addr = self.callrpc('getnewaddress')
|
||||
else:
|
||||
bid_addr = addr_send_from
|
||||
self.callrpc('smsgaddlocaladdress', [bid_addr]) # Enable receiving smsg
|
||||
options = {'decodehex': True, 'ttl_is_seconds': True}
|
||||
msg_valid = self.SMSG_SECONDS_IN_HOUR * 1
|
||||
ro = self.callrpc('smsgsend', [bid_addr, offer.addr_from, payload_hex, False, msg_valid, False, options])
|
||||
xmr_swap.bid_id = bytes.fromhex(ro['msgid'])
|
||||
|
||||
msg_buf2 = XmrSplitMessage(
|
||||
msg_id=xmr_swap.bid_id,
|
||||
msg_type=XmrSplitMsgTypes.BID,
|
||||
sequence=2,
|
||||
dleag=xmr_swap.kbsf_dleag[16000:32000]
|
||||
)
|
||||
msg_bytes = msg_buf2.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_SPLIT) + msg_bytes.hex()
|
||||
ro = self.callrpc('smsgsend', [bid_addr, offer.addr_from, payload_hex, False, msg_valid, False, options])
|
||||
xmr_swap.bid_msg_id2 = bytes.fromhex(ro['msgid'])
|
||||
|
||||
msg_buf3 = XmrSplitMessage(
|
||||
msg_id=xmr_swap.bid_id,
|
||||
msg_type=XmrSplitMsgTypes.BID,
|
||||
sequence=3,
|
||||
dleag=xmr_swap.kbsf_dleag[32000:]
|
||||
)
|
||||
msg_bytes = msg_buf3.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_SPLIT) + msg_bytes.hex()
|
||||
ro = self.callrpc('smsgsend', [bid_addr, offer.addr_from, payload_hex, False, msg_valid, False, options])
|
||||
xmr_swap.bid_msg_id3 = bytes.fromhex(ro['msgid'])
|
||||
|
||||
|
||||
bid = Bid(
|
||||
bid_id=xmr_swap.bid_id,
|
||||
offer_id=offer_id,
|
||||
amount=msg_buf.amount,
|
||||
#pkhash_buyer=msg_buf.pkhash_buyer,
|
||||
#proof_address=msg_buf.proof_address,
|
||||
|
||||
created_at=bid_created_at,
|
||||
contract_count=xmr_swap.contract_count,
|
||||
amount_to=(msg_buf.amount * offer.rate) // COIN,
|
||||
expire_at=bid_created_at + msg_buf.time_valid,
|
||||
bid_addr=bid_addr,
|
||||
was_sent=True,
|
||||
)
|
||||
bid.setState(BidStates.BID_SENT)
|
||||
|
||||
session = scoped_session(self.session_factory)
|
||||
self.saveBidInSession(xmr_swap.bid_id, bid, session, xmr_swap)
|
||||
if addr_send_from is None:
|
||||
session.add(SmsgAddress(addr=bid_addr, use_type=MessageTypes.BID))
|
||||
session.commit()
|
||||
session.close()
|
||||
session.remove()
|
||||
|
||||
self.log.info('Sent XMR_BID %s', xmr_swap.bid_id.hex())
|
||||
return xmr_swap.bid_id
|
||||
finally:
|
||||
self.mxDB.release()
|
||||
|
||||
def acceptXmrBid(self, bid_id):
|
||||
# MSG1F and MSG2F L -> F
|
||||
self.log.info('Accepting xmr bid %s', bid_id.hex())
|
||||
|
||||
now = int(time.time())
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
bid, xmr_swap = self.getXmrBid(bid_id)
|
||||
assert(bid), 'Bid not found: {}.'.format(bid_id.hex())
|
||||
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid_id.hex())
|
||||
assert(bid.expire_at > now), 'Offer has expired'
|
||||
|
||||
offer, xmr_offer = self.getXmrOffer(bid.offer_id)
|
||||
assert(offer), 'Offer not found: {}.'.format(bid.offer_id.hex())
|
||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(bid.offer_id.hex())
|
||||
assert(offer.expire_at > now), 'Offer has expired'
|
||||
|
||||
coin_from = Coins(offer.coin_from)
|
||||
coin_to = Coins(offer.coin_to)
|
||||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
self.log.debug('[rm] acceptXmrBid bid.created_at %d', bid.created_at)
|
||||
if xmr_swap.contract_count is None:
|
||||
xmr_swap.contract_count = self.getNewContractId()
|
||||
|
||||
contract_secret = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 1)
|
||||
|
||||
kbvl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 2, for_xmr=True)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 3, for_xmr=True)
|
||||
|
||||
kal = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 4)
|
||||
karl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, 5)
|
||||
|
||||
xmr_swap.sh = hashlib.sha256(contract_secret).digest()
|
||||
xmr_swap.pkal = ci_from.getPubkey(kal)
|
||||
xmr_swap.pkarl = ci_from.getPubkey(karl)
|
||||
|
||||
xmr_swap.kbsl_dleag = ci_to.proveDLEAG(kbsl)
|
||||
|
||||
# MSG2F
|
||||
xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script = ci_from.createScriptLockTx(
|
||||
bid.amount,
|
||||
xmr_swap.sh,
|
||||
xmr_swap.pkal, xmr_swap.pkaf,
|
||||
xmr_offer.lock_time_1,
|
||||
xmr_swap.pkarl, xmr_swap.pkarf,
|
||||
)
|
||||
xmr_swap.a_lock_tx = ci_from.fundTx(xmr_swap.a_lock_tx, xmr_offer.a_fee_rate)
|
||||
|
||||
xmr_swap.a_lock_tx_id = ci_from.getTxHash(xmr_swap.a_lock_tx)
|
||||
xmr_swap.a_lock_tx_dest = ci_from.getScriptDest(xmr_swap.a_lock_tx_script)
|
||||
|
||||
xmr_swap.a_lock_refund_tx, xmr_swap.a_lock_refund_tx_script, xmr_swap.a_swap_refund_value = ci_from.createScriptLockRefundTx(
|
||||
xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script,
|
||||
xmr_swap.pkarl, xmr_swap.pkarf,
|
||||
xmr_offer.lock_time_2,
|
||||
xmr_swap.pkaf,
|
||||
xmr_offer.a_fee_rate
|
||||
)
|
||||
|
||||
xmr_swap.al_lock_refund_tx_sig = ci_from.signTx(karl, xmr_swap.a_lock_refund_tx, 0, xmr_swap.a_lock_tx_script, bid.amount)
|
||||
|
||||
v = ci_from.verifyTxSig(xmr_swap.a_lock_refund_tx, xmr_swap.al_lock_refund_tx_sig, xmr_swap.pkarl, 0, xmr_swap.a_lock_tx_script, bid.amount)
|
||||
assert(v)
|
||||
|
||||
xmr_swap.a_lock_refund_spend_tx = ci_from.createScriptLockRefundSpendTx(
|
||||
xmr_swap.a_lock_refund_tx, xmr_swap.a_lock_refund_tx_script,
|
||||
xmr_swap.pkal,
|
||||
xmr_offer.a_fee_rate
|
||||
)
|
||||
|
||||
msg_buf = XmrBidAcceptMessage()
|
||||
msg_buf.bid_msg_id = bid_id
|
||||
msg_buf.sh = xmr_swap.sh
|
||||
msg_buf.pkal = xmr_swap.pkal
|
||||
msg_buf.pkarl = xmr_swap.pkarl
|
||||
msg_buf.kbvl = kbvl
|
||||
msg_buf.kbsl_dleag = xmr_swap.kbsl_dleag[:16000]
|
||||
|
||||
# MSG2F
|
||||
msg_buf.a_lock_tx = xmr_swap.a_lock_tx
|
||||
msg_buf.a_lock_tx_script = xmr_swap.a_lock_tx_script
|
||||
msg_buf.a_lock_refund_tx = xmr_swap.a_lock_refund_tx
|
||||
msg_buf.a_lock_refund_tx_script = xmr_swap.a_lock_refund_tx_script
|
||||
msg_buf.a_lock_refund_spend_tx = xmr_swap.a_lock_refund_spend_tx
|
||||
msg_buf.al_lock_refund_tx_sig = xmr_swap.al_lock_refund_tx_sig
|
||||
|
||||
msg_bytes = msg_buf.SerializeToString()
|
||||
self.log.debug('[rm] acceptXmrBid len(msg_bytes) %d', len(msg_bytes))
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_ACCEPT) + msg_bytes.hex()
|
||||
options = {'decodehex': True, 'ttl_is_seconds': True}
|
||||
msg_valid = self.SMSG_SECONDS_IN_HOUR * 48
|
||||
ro = self.callrpc('smsgsend', [offer.addr_from, bid.bid_addr, payload_hex, False, msg_valid, False, options])
|
||||
msg_id = ro['msgid']
|
||||
bid.accept_msg_id = bytes.fromhex(msg_id)
|
||||
xmr_swap.bid_accept_msg_id = bid.accept_msg_id
|
||||
|
||||
msg_buf2 = XmrSplitMessage(
|
||||
msg_id=bid_id,
|
||||
msg_type=XmrSplitMsgTypes.BID_ACCEPT,
|
||||
sequence=2,
|
||||
dleag=xmr_swap.kbsl_dleag[16000:32000]
|
||||
)
|
||||
msg_bytes = msg_buf2.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_SPLIT) + msg_bytes.hex()
|
||||
ro = self.callrpc('smsgsend', [offer.addr_from, bid.bid_addr, payload_hex, False, msg_valid, False, options])
|
||||
xmr_swap.bid_accept_msg_id2 = bytes.fromhex(ro['msgid'])
|
||||
|
||||
msg_buf3 = XmrSplitMessage(
|
||||
msg_id=bid_id,
|
||||
msg_type=XmrSplitMsgTypes.BID_ACCEPT,
|
||||
sequence=3,
|
||||
dleag=xmr_swap.kbsl_dleag[32000:]
|
||||
)
|
||||
msg_bytes = msg_buf3.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_SPLIT) + msg_bytes.hex()
|
||||
ro = self.callrpc('smsgsend', [offer.addr_from, bid.bid_addr, payload_hex, False, msg_valid, False, options])
|
||||
xmr_swap.bid_accept_msg_id3 = bytes.fromhex(ro['msgid'])
|
||||
|
||||
bid.setState(BidStates.BID_ACCEPTED)
|
||||
|
||||
session = scoped_session(self.session_factory)
|
||||
self.saveBidInSession(bid_id, bid, session, xmr_swap)
|
||||
session.commit()
|
||||
session.close()
|
||||
session.remove()
|
||||
|
||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
||||
self.log.info('Sent XMR_BID_ACCEPT %s', bid_id.hex())
|
||||
return bid_id
|
||||
finally:
|
||||
self.mxDB.release()
|
||||
|
||||
def abandonOffer(self, offer_id):
|
||||
self.log.info('Abandoning Offer %s', offer_id.hex())
|
||||
self.mxDB.acquire()
|
||||
|
@ -1282,10 +1624,10 @@ class BasicSwap(BaseApp):
|
|||
session.remove()
|
||||
self.mxDB.release()
|
||||
|
||||
def setBidError(self, bif_id, bid, error_str):
|
||||
def setBidError(self, bid_id, bid, error_str):
|
||||
bid.setState(BidStates.BID_ERROR)
|
||||
bid.state_note = 'error msg: ' + error_str
|
||||
self.saveBid(bif_id, bid)
|
||||
self.saveBid(bid_id, bid)
|
||||
|
||||
def createInitiateTxn(self, coin_type, bid_id, bid, initiate_script):
|
||||
if self.coin_clients[coin_type]['connection_type'] != 'rpc':
|
||||
|
@ -1771,6 +2113,9 @@ class BasicSwap(BaseApp):
|
|||
return sum_unspent
|
||||
return None
|
||||
|
||||
def checkXmrBidState(self, bid_id, bid, offer):
|
||||
pass
|
||||
|
||||
def checkBidState(self, bid_id, bid, offer):
|
||||
# assert(self.mxDB.locked())
|
||||
# Return True to remove bid from in-progress list
|
||||
|
@ -1778,6 +2123,9 @@ class BasicSwap(BaseApp):
|
|||
state = BidStates(bid.state)
|
||||
self.log.debug('checkBidState %s %s', bid_id.hex(), str(state))
|
||||
|
||||
if offer.swap_type == SwapTypes.XMR_SWAP:
|
||||
return self.checkXmrBidState(bid_id, bid, offer)
|
||||
|
||||
save_bid = False
|
||||
coin_from = Coins(offer.coin_from)
|
||||
coin_to = Coins(offer.coin_to)
|
||||
|
@ -2072,21 +2420,19 @@ class BasicSwap(BaseApp):
|
|||
options = {'encoding': 'none', 'delete': True}
|
||||
del_msg = self.callrpc('smsg', [msg['msgid'], options])
|
||||
|
||||
# TODO: remove offers from db
|
||||
logging.debug('TODO: Expire records from db')
|
||||
|
||||
finally:
|
||||
self.mxDB.release()
|
||||
|
||||
def checkEvents(self):
|
||||
self.mxDB.acquire()
|
||||
now = int(time.time())
|
||||
try:
|
||||
now = int(time.time())
|
||||
|
||||
session = scoped_session(self.session_factory)
|
||||
|
||||
q = session.query(EventQueue).filter(EventQueue.trigger_at >= now)
|
||||
for row in q:
|
||||
|
||||
if row.event_type == EventTypes.ACCEPT_BID:
|
||||
self.acceptBid(row.linked_id)
|
||||
else:
|
||||
|
@ -2100,6 +2446,55 @@ class BasicSwap(BaseApp):
|
|||
finally:
|
||||
self.mxDB.release()
|
||||
|
||||
def checkXmrSwaps(self):
|
||||
self.mxDB.acquire()
|
||||
now = int(time.time())
|
||||
ttl_xmr_split_messages = 60 * 60
|
||||
try:
|
||||
session = scoped_session(self.session_factory)
|
||||
q = session.query(Bid).filter(Bid.state == BidStates.BID_RECEIVING)
|
||||
for bid in q:
|
||||
q = self.engine.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {}'.format(bid.bid_id.hex(), XmrSplitMsgTypes.BID)).first()
|
||||
num_segments = q[0]
|
||||
if num_segments > 1:
|
||||
try:
|
||||
self.receiveXmrBid(bid, session)
|
||||
except Exception as e:
|
||||
self.log.info('Verify xmr bid {} failed: {}'.format(bid.bid_id.hex(), str(e)))
|
||||
bid.setState(BidStates.BID_ERROR, 'Failed validation: ' + str(e))
|
||||
session.add(bid)
|
||||
continue
|
||||
if bid.created_at + ttl_xmr_split_messages < now:
|
||||
self.log.debug('Expiring partially received bid: {}'.format(bid.bid_id.hex()))
|
||||
bid.setState(BidStates.BID_ERROR, 'Timed out')
|
||||
session.add(bid)
|
||||
|
||||
q = session.query(Bid).filter(Bid.state == BidStates.BID_RECEIVING_ACC)
|
||||
for bid in q:
|
||||
q = self.engine.execute('SELECT COUNT(*) FROM xmr_split_data WHERE bid_id = x\'{}\' AND msg_type = {}'.format(bid.bid_id.hex(), XmrSplitMsgTypes.BID_ACCEPT)).first()
|
||||
num_segments = q[0]
|
||||
if num_segments > 1:
|
||||
try:
|
||||
self.receiveXmrBidAccept(bid, session)
|
||||
except Exception as e:
|
||||
self.log.info('Verify xmr bid accept {} failed: {}'.format(bid.bid_id.hex(), str(e)))
|
||||
bid.setState(BidStates.BID_ERROR, 'Failed accept validation: ' + str(e))
|
||||
session.add(bid)
|
||||
continue
|
||||
if bid.created_at + ttl_xmr_split_messages < now:
|
||||
self.log.debug('Expiring partially received bid accept: {}'.format(bid.bid_id.hex()))
|
||||
bid.setState(BidStates.BID_ERROR, 'Timed out')
|
||||
session.add(bid)
|
||||
|
||||
# Expire old records
|
||||
q = session.query(XmrSplitData).filter(XmrSplitData.created_at + ttl_xmr_split_messages < now)
|
||||
q.delete(synchronize_session=False)
|
||||
session.commit()
|
||||
session.close()
|
||||
session.remove()
|
||||
finally:
|
||||
self.mxDB.release()
|
||||
|
||||
def processOffer(self, msg):
|
||||
assert(msg['to'] == self.network_addr), 'Offer received on wrong address'
|
||||
|
||||
|
@ -2159,6 +2554,19 @@ class BasicSwap(BaseApp):
|
|||
was_sent=False)
|
||||
offer.setState(OfferStates.OFFER_RECEIVED)
|
||||
session.add(offer)
|
||||
|
||||
if offer.swap_type == SwapTypes.XMR_SWAP:
|
||||
xmr_offer = XmrOffer()
|
||||
|
||||
xmr_offer.offer_id = offer_id
|
||||
xmr_offer.lock_time_1 = offer_data.lock_value
|
||||
xmr_offer.lock_time_2 = offer_data.lock_value
|
||||
|
||||
xmr_offer.a_fee_rate = offer_data.fee_rate_from
|
||||
xmr_offer.b_fee_rate = offer_data.fee_rate_to
|
||||
|
||||
session.add(xmr_offer)
|
||||
|
||||
self.log.debug('Received new offer %s', offer_id.hex())
|
||||
else:
|
||||
existing_offer.setState(OfferStates.OFFER_RECEIVED)
|
||||
|
@ -2326,6 +2734,179 @@ class BasicSwap(BaseApp):
|
|||
self.saveBid(bid_id, bid)
|
||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
||||
|
||||
def receiveXmrBid(self, bid, session):
|
||||
self.log.debug('Receiving xmr bid %s', bid.bid_id.hex())
|
||||
now = int(time.time())
|
||||
|
||||
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=True)
|
||||
assert(offer and offer.was_sent), 'Offer not found: {}.'.format(offer_id.hex())
|
||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(offer_id.hex())
|
||||
coin_from = Coins(offer.coin_from)
|
||||
coin_to = Coins(offer.coin_to)
|
||||
|
||||
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid.bid_id).first()
|
||||
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid.bid_id.hex())
|
||||
|
||||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
if len(xmr_swap.kbsf_dleag) < ci_to.lengthDLEAG():
|
||||
q = session.query(XmrSplitData).filter(sa.and_(XmrSplitData.bid_id == bid.bid_id, XmrSplitData.msg_type == XmrSplitMsgTypes.BID)).order_by(XmrSplitData.msg_sequence.asc())
|
||||
for row in q:
|
||||
xmr_swap.kbsf_dleag += row.dleag
|
||||
|
||||
if not ci_to.verifyKey(xmr_swap.vkbvf):
|
||||
raise ValueError('Invalid key.')
|
||||
if not ci_to.verifyDLEAG(xmr_swap.kbsf_dleag):
|
||||
raise ValueError('Invalid DLEAG proof.')
|
||||
|
||||
if not ci_from.verifyPubkey(xmr_swap.pkaf):
|
||||
raise ValueError('Invalid pubkey.')
|
||||
if not ci_from.verifyPubkey(xmr_swap.pkarf):
|
||||
raise ValueError('Invalid pubkey.')
|
||||
|
||||
bid.setState(BidStates.BID_RECEIVED)
|
||||
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
||||
|
||||
def receiveXmrBidAccept(self, bid, session):
|
||||
self.log.debug('Receiving xmr bid accept %s', bid.bid_id.hex())
|
||||
now = int(time.time())
|
||||
|
||||
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=True)
|
||||
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)
|
||||
|
||||
xmr_swap = session.query(XmrSwap).filter_by(bid_id=bid.bid_id).first()
|
||||
assert(xmr_swap), 'XMR swap not found: {}.'.format(bid.bid_id.hex())
|
||||
|
||||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
if len(xmr_swap.kbsl_dleag) < ci_to.lengthDLEAG():
|
||||
q = session.query(XmrSplitData).filter(sa.and_(XmrSplitData.bid_id == bid.bid_id, XmrSplitData.msg_type == XmrSplitMsgTypes.BID_ACCEPT)).order_by(XmrSplitData.msg_sequence.asc())
|
||||
for row in q:
|
||||
xmr_swap.kbsl_dleag += row.dleag
|
||||
|
||||
if not ci_to.verifyKey(xmr_swap.vkbvl):
|
||||
raise ValueError('Invalid key.')
|
||||
if not ci_to.verifyDLEAG(xmr_swap.kbsl_dleag):
|
||||
raise ValueError('Invalid DLEAG proof.')
|
||||
|
||||
if not ci_from.verifyPubkey(xmr_swap.pkal):
|
||||
raise ValueError('Invalid pubkey.')
|
||||
if not ci_from.verifyPubkey(xmr_swap.pkarl):
|
||||
raise ValueError('Invalid pubkey.')
|
||||
|
||||
bid.setState(BidStates.BID_ACCEPTED)
|
||||
self.saveBidInSession(bid.bid_id, bid, session, xmr_swap)
|
||||
|
||||
def processXmrBid(self, msg):
|
||||
self.log.debug('Processing xmr bid msg %s', msg['msgid'])
|
||||
now = int(time.time())
|
||||
bid_bytes = bytes.fromhex(msg['hex'][2:-2])
|
||||
bid_data = XmrBidMessage()
|
||||
bid_data.ParseFromString(bid_bytes)
|
||||
|
||||
# Validate data
|
||||
assert(len(bid_data.offer_msg_id) == 28), 'Bad offer_id length'
|
||||
assert(bid_data.time_valid >= MIN_BID_VALID_TIME and bid_data.time_valid <= MAX_BID_VALID_TIME), 'Invalid time_valid'
|
||||
|
||||
offer_id = bid_data.offer_msg_id
|
||||
offer, xmr_offer = self.getXmrOffer(offer_id, sent=True)
|
||||
assert(offer and offer.was_sent), 'Offer not found: {}.'.format(offer_id.hex())
|
||||
assert(xmr_offer), 'XMR offer not found: {}.'.format(offer_id.hex())
|
||||
coin_from = Coins(offer.coin_from)
|
||||
coin_to = Coins(offer.coin_to)
|
||||
|
||||
logging.debug('TODO: xmr bid validation')
|
||||
|
||||
bid_id = bytes.fromhex(msg['msgid'])
|
||||
|
||||
bid, xmr_swap = self.getXmrBid(bid_id)
|
||||
if bid is None:
|
||||
bid = Bid(
|
||||
bid_id=bid_id,
|
||||
offer_id=offer_id,
|
||||
amount=bid_data.amount,
|
||||
#pkhash_buyer=bid_data.pkhash_buyer,
|
||||
|
||||
created_at=msg['sent'],
|
||||
amount_to=(bid_data.amount * offer.rate) // COIN,
|
||||
expire_at=msg['sent'] + bid_data.time_valid,
|
||||
bid_addr=msg['from'],
|
||||
was_received=True,
|
||||
)
|
||||
|
||||
xmr_swap = XmrSwap(
|
||||
bid_id=bid_id,
|
||||
pkaf=bid_data.pkaf,
|
||||
pkarf=bid_data.pkarf,
|
||||
vkbvf=bid_data.kbvf,
|
||||
kbsf_dleag=bid_data.kbsf_dleag,
|
||||
b_restore_height=self.ci(coin_to).getChainHeight(),
|
||||
)
|
||||
else:
|
||||
bid.created_at = msg['sent']
|
||||
bid.expire_at = msg['sent'] + bid_data.time_valid
|
||||
bid.was_received = True
|
||||
|
||||
bid.setState(BidStates.BID_RECEIVING)
|
||||
|
||||
self.log.info('Receiving xmr bid %s for offer %s', bid_id.hex(), bid_data.offer_msg_id.hex())
|
||||
self.saveBid(bid_id, bid, xmr_swap=xmr_swap)
|
||||
|
||||
def processXmrBidAccept(self, msg):
|
||||
# F receiving MSG1F
|
||||
self.log.debug('Processing xmr bid accept msg %s', msg['msgid'])
|
||||
now = int(time.time())
|
||||
msg_bytes = bytes.fromhex(msg['hex'][2:-2])
|
||||
msg_data = XmrBidAcceptMessage()
|
||||
msg_data.ParseFromString(msg_bytes)
|
||||
|
||||
assert(len(msg_data.bid_msg_id) == 28), 'Bad bid_msg_id length'
|
||||
|
||||
self.log.debug('for bid %s', msg_data.bid_msg_id.hex())
|
||||
bid, xmr_swap = self.getXmrBid(msg_data.bid_msg_id)
|
||||
|
||||
offer, xmr_offer = self.getXmrOffer(bid.offer_id, sent=True)
|
||||
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)
|
||||
|
||||
assert(len(msg_data.sh) == 32), 'Bad secret hash length'
|
||||
|
||||
xmr_swap.sh = msg_data.sh
|
||||
xmr_swap.pkal = msg_data.pkal
|
||||
xmr_swap.pkarl = msg_data.pkarl
|
||||
xmr_swap.vkbvl = msg_data.kbvl
|
||||
xmr_swap.kbsl_dleag = msg_data.kbsl_dleag
|
||||
|
||||
bid.setState(BidStates.BID_RECEIVING_ACC)
|
||||
self.saveBid(msg_data.bid_msg_id, bid, xmr_swap=xmr_swap)
|
||||
|
||||
def processXmrSplitMessage(self, msg):
|
||||
self.log.debug('Processing xmr split msg %s', msg['msgid'])
|
||||
now = int(time.time())
|
||||
msg_bytes = bytes.fromhex(msg['hex'][2:-2])
|
||||
msg_data = XmrSplitMessage()
|
||||
msg_data.ParseFromString(msg_bytes)
|
||||
|
||||
# Validate data
|
||||
print('[rm] msg_data.msg_id', msg_data.msg_id.hex())
|
||||
assert(len(msg_data.msg_id) == 28), 'Bad msg_id length'
|
||||
|
||||
if msg_data.msg_type == XmrSplitMsgTypes.BID or msg_data.msg_type == XmrSplitMsgTypes.BID_ACCEPT:
|
||||
dbr = XmrSplitData()
|
||||
dbr.bid_id = msg_data.msg_id
|
||||
dbr.msg_type = msg_data.msg_type
|
||||
dbr.msg_sequence = msg_data.sequence
|
||||
dbr.dleag = msg_data.dleag
|
||||
dbr.created_at = now
|
||||
self.saveToDB(dbr)
|
||||
|
||||
def processMsg(self, msg):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
|
@ -2338,6 +2919,12 @@ class BasicSwap(BaseApp):
|
|||
self.processBid(msg)
|
||||
elif msg_type == MessageTypes.BID_ACCEPT:
|
||||
self.processBidAccept(msg)
|
||||
elif msg_type == MessageTypes.XMR_BID:
|
||||
self.processXmrBid(msg)
|
||||
elif msg_type == MessageTypes.XMR_BID_ACCEPT:
|
||||
self.processXmrBidAccept(msg)
|
||||
elif msg_type == MessageTypes.XMR_BID_SPLIT:
|
||||
self.processXmrSplitMessage(msg)
|
||||
|
||||
except Exception as ex:
|
||||
self.log.error('processMsg %s', str(ex))
|
||||
|
@ -2373,7 +2960,7 @@ class BasicSwap(BaseApp):
|
|||
try:
|
||||
# TODO: Wait for blocks / txns, would need to check multiple coins
|
||||
now = int(time.time())
|
||||
if now - self.last_checked_progress >= self.check_progress_seconds:
|
||||
if now - self._last_checked_progress >= self.check_progress_seconds:
|
||||
to_remove = []
|
||||
for bid_id, v in self.swaps_in_progress.items():
|
||||
try:
|
||||
|
@ -2387,21 +2974,25 @@ class BasicSwap(BaseApp):
|
|||
for bid_id in to_remove:
|
||||
self.log.debug('Removing bid from in-progress: %s', bid_id.hex())
|
||||
del self.swaps_in_progress[bid_id]
|
||||
self.last_checked_progress = now
|
||||
self._last_checked_progress = now
|
||||
|
||||
if now - self.last_checked_watched >= self.check_watched_seconds:
|
||||
if now - self._last_checked_watched >= self.check_watched_seconds:
|
||||
for k, c in self.coin_clients.items():
|
||||
if len(c['watched_outputs']) > 0:
|
||||
self.checkForSpends(k, c)
|
||||
self.last_checked_watched = now
|
||||
self._last_checked_watched = now
|
||||
|
||||
if now - self.last_checked_expired >= self.check_expired_seconds:
|
||||
if now - self._last_checked_expired >= self.check_expired_seconds:
|
||||
self.expireMessages()
|
||||
self.last_checked_expired = now
|
||||
self._last_checked_expired = now
|
||||
|
||||
if now - self.last_checked_events >= self.check_events_seconds:
|
||||
if now - self._last_checked_events >= self.check_events_seconds:
|
||||
self.checkEvents()
|
||||
self.last_checked_events = now
|
||||
self._last_checked_events = now
|
||||
|
||||
if now - self._last_checked_xmr_swaps >= self.check_xmr_swaps_seconds:
|
||||
self.checkXmrSwaps()
|
||||
self._last_checked_xmr_swaps = now
|
||||
|
||||
except Exception as ex:
|
||||
self.log.error('update %s', str(ex))
|
||||
|
@ -2542,6 +3133,9 @@ class BasicSwap(BaseApp):
|
|||
else:
|
||||
q = session.query(Offer).filter(Offer.expire_at > now)
|
||||
|
||||
filter_offer_id = filters.get('offer_id', None)
|
||||
if filter_offer_id is not None:
|
||||
q = q.filter(Offer.offer_id == filter_offer_id)
|
||||
filter_coin_from = filters.get('coin_from', None)
|
||||
if filter_coin_from and filter_coin_from > -1:
|
||||
q = q.filter(Offer.coin_from == int(filter_coin_from))
|
||||
|
|
356
basicswap/contrib/ed25519_fast.py
Normal file
356
basicswap/contrib/ed25519_fast.py
Normal file
|
@ -0,0 +1,356 @@
|
|||
# ed25519.py - Optimized version of the reference implementation of Ed25519
|
||||
#
|
||||
# Written in 2011? by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
# 2013 by Donald Stufft <donald@stufft.io>
|
||||
# 2013 by Alex Gaynor <alex.gaynor@gmail.com>
|
||||
# 2013 by Greg Price <price@mit.edu>
|
||||
#
|
||||
# To the extent possible under law, the author(s) have dedicated all copyright
|
||||
# and related and neighboring rights to this software to the public domain
|
||||
# worldwide. This software is distributed without any warranty.
|
||||
#
|
||||
# You should have received a copy of the CC0 Public Domain Dedication along
|
||||
# with this software. If not, see
|
||||
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
|
||||
"""
|
||||
NB: This code is not safe for use with secret keys or secret data.
|
||||
The only safe use of this code is for verifying signatures on public messages.
|
||||
|
||||
Functions for computing the public key of a secret key and for signing
|
||||
a message are included, namely publickey_unsafe and signature_unsafe,
|
||||
for testing purposes only.
|
||||
|
||||
The root of the problem is that Python's long-integer arithmetic is
|
||||
not designed for use in cryptography. Specifically, it may take more
|
||||
or less time to execute an operation depending on the values of the
|
||||
inputs, and its memory access patterns may also depend on the inputs.
|
||||
This opens it to timing and cache side-channel attacks which can
|
||||
disclose data to an attacker. We rely on Python's long-integer
|
||||
arithmetic, so we cannot handle secrets without risking their disclosure.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import operator
|
||||
import sys
|
||||
|
||||
|
||||
__version__ = "1.0.dev0"
|
||||
|
||||
|
||||
# Useful for very coarse version differentiation.
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
indexbytes = operator.getitem
|
||||
intlist2bytes = bytes
|
||||
int2byte = operator.methodcaller("to_bytes", 1, "big")
|
||||
else:
|
||||
int2byte = chr
|
||||
range = xrange
|
||||
|
||||
def indexbytes(buf, i):
|
||||
return ord(buf[i])
|
||||
|
||||
def intlist2bytes(l):
|
||||
return b"".join(chr(c) for c in l)
|
||||
|
||||
|
||||
b = 256
|
||||
q = 2 ** 255 - 19
|
||||
l = 2 ** 252 + 27742317777372353535851937790883648493
|
||||
|
||||
|
||||
def H(m):
|
||||
return hashlib.sha512(m).digest()
|
||||
|
||||
|
||||
def pow2(x, p):
|
||||
"""== pow(x, 2**p, q)"""
|
||||
while p > 0:
|
||||
x = x * x % q
|
||||
p -= 1
|
||||
return x
|
||||
|
||||
|
||||
def inv(z):
|
||||
"""$= z^{-1} \mod q$, for z != 0"""
|
||||
# Adapted from curve25519_athlon.c in djb's Curve25519.
|
||||
z2 = z * z % q # 2
|
||||
z9 = pow2(z2, 2) * z % q # 9
|
||||
z11 = z9 * z2 % q # 11
|
||||
z2_5_0 = (z11 * z11) % q * z9 % q # 31 == 2^5 - 2^0
|
||||
z2_10_0 = pow2(z2_5_0, 5) * z2_5_0 % q # 2^10 - 2^0
|
||||
z2_20_0 = pow2(z2_10_0, 10) * z2_10_0 % q # ...
|
||||
z2_40_0 = pow2(z2_20_0, 20) * z2_20_0 % q
|
||||
z2_50_0 = pow2(z2_40_0, 10) * z2_10_0 % q
|
||||
z2_100_0 = pow2(z2_50_0, 50) * z2_50_0 % q
|
||||
z2_200_0 = pow2(z2_100_0, 100) * z2_100_0 % q
|
||||
z2_250_0 = pow2(z2_200_0, 50) * z2_50_0 % q # 2^250 - 2^0
|
||||
return pow2(z2_250_0, 5) * z11 % q # 2^255 - 2^5 + 11 = q - 2
|
||||
|
||||
|
||||
d = -121665 * inv(121666) % q
|
||||
I = pow(2, (q - 1) // 4, q)
|
||||
|
||||
|
||||
def xrecover(y, sign=0):
|
||||
xx = (y * y - 1) * inv(d * y * y + 1)
|
||||
x = pow(xx, (q + 3) // 8, q)
|
||||
|
||||
if (x * x - xx) % q != 0:
|
||||
x = (x * I) % q
|
||||
|
||||
if x % 2 != sign:
|
||||
x = q-x
|
||||
|
||||
return x
|
||||
|
||||
|
||||
By = 4 * inv(5)
|
||||
Bx = xrecover(By)
|
||||
B = (Bx % q, By % q, 1, (Bx * By) % q)
|
||||
ident = (0, 1, 1, 0)
|
||||
|
||||
|
||||
def edwards_add(P, Q):
|
||||
# This is formula sequence 'addition-add-2008-hwcd-3' from
|
||||
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
(x1, y1, z1, t1) = P
|
||||
(x2, y2, z2, t2) = Q
|
||||
|
||||
a = (y1-x1)*(y2-x2) % q
|
||||
b = (y1+x1)*(y2+x2) % q
|
||||
c = t1*2*d*t2 % q
|
||||
dd = z1*2*z2 % q
|
||||
e = b - a
|
||||
f = dd - c
|
||||
g = dd + c
|
||||
h = b + a
|
||||
x3 = e*f
|
||||
y3 = g*h
|
||||
t3 = e*h
|
||||
z3 = f*g
|
||||
|
||||
return (x3 % q, y3 % q, z3 % q, t3 % q)
|
||||
|
||||
|
||||
def edwards_sub(P, Q):
|
||||
# This is formula sequence 'addition-add-2008-hwcd-3' from
|
||||
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
(x1, y1, z1, t1) = P
|
||||
(x2, y2, z2, t2) = Q
|
||||
|
||||
# https://eprint.iacr.org/2008/522.pdf
|
||||
# The negative of (X:Y:Z)is (−X:Y:Z)
|
||||
#x2 = q-x2
|
||||
"""
|
||||
doesn't work
|
||||
x2 = q-x2
|
||||
t2 = (x2*y2) % q
|
||||
"""
|
||||
|
||||
zi = inv(z2)
|
||||
x2 = q-((x2 * zi) % q)
|
||||
y2 = (y2 * zi) % q
|
||||
z2 = 1
|
||||
t2 = (x2*y2) % q
|
||||
|
||||
|
||||
a = (y1-x1)*(y2-x2) % q
|
||||
b = (y1+x1)*(y2+x2) % q
|
||||
c = t1*2*d*t2 % q
|
||||
dd = z1*2*z2 % q
|
||||
e = b - a
|
||||
f = dd - c
|
||||
g = dd + c
|
||||
h = b + a
|
||||
x3 = e*f
|
||||
y3 = g*h
|
||||
t3 = e*h
|
||||
z3 = f*g
|
||||
|
||||
return (x3 % q, y3 % q, z3 % q, t3 % q)
|
||||
|
||||
|
||||
def edwards_double(P):
|
||||
# This is formula sequence 'dbl-2008-hwcd' from
|
||||
# http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
(x1, y1, z1, t1) = P
|
||||
|
||||
a = x1*x1 % q
|
||||
b = y1*y1 % q
|
||||
c = 2*z1*z1 % q
|
||||
# dd = -a
|
||||
e = ((x1+y1)*(x1+y1) - a - b) % q
|
||||
g = -a + b # dd + b
|
||||
f = g - c
|
||||
h = -a - b # dd - b
|
||||
x3 = e*f
|
||||
y3 = g*h
|
||||
t3 = e*h
|
||||
z3 = f*g
|
||||
|
||||
return (x3 % q, y3 % q, z3 % q, t3 % q)
|
||||
|
||||
|
||||
def scalarmult(P, e):
|
||||
if e == 0:
|
||||
return ident
|
||||
Q = scalarmult(P, e // 2)
|
||||
Q = edwards_double(Q)
|
||||
if e & 1:
|
||||
Q = edwards_add(Q, P)
|
||||
return Q
|
||||
|
||||
|
||||
# Bpow[i] == scalarmult(B, 2**i)
|
||||
Bpow = []
|
||||
|
||||
|
||||
def make_Bpow():
|
||||
P = B
|
||||
for i in range(253):
|
||||
Bpow.append(P)
|
||||
P = edwards_double(P)
|
||||
make_Bpow()
|
||||
|
||||
|
||||
def scalarmult_B(e):
|
||||
"""
|
||||
Implements scalarmult(B, e) more efficiently.
|
||||
"""
|
||||
# scalarmult(B, l) is the identity
|
||||
e = e % l
|
||||
P = ident
|
||||
for i in range(253):
|
||||
if e & 1:
|
||||
P = edwards_add(P, Bpow[i])
|
||||
e = e // 2
|
||||
assert e == 0, e
|
||||
return P
|
||||
|
||||
|
||||
def encodeint(y):
|
||||
bits = [(y >> i) & 1 for i in range(b)]
|
||||
return b''.join([
|
||||
int2byte(sum([bits[i * 8 + j] << j for j in range(8)]))
|
||||
for i in range(b//8)
|
||||
])
|
||||
|
||||
|
||||
def encodepoint(P):
|
||||
(x, y, z, t) = P
|
||||
zi = inv(z)
|
||||
x = (x * zi) % q
|
||||
y = (y * zi) % q
|
||||
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
|
||||
return b''.join([
|
||||
int2byte(sum([bits[i * 8 + j] << j for j in range(8)]))
|
||||
for i in range(b // 8)
|
||||
])
|
||||
|
||||
|
||||
def bit(h, i):
|
||||
return (indexbytes(h, i // 8) >> (i % 8)) & 1
|
||||
|
||||
|
||||
def publickey_unsafe(sk):
|
||||
"""
|
||||
Not safe to use with secret keys or secret data.
|
||||
|
||||
See module docstring. This function should be used for testing only.
|
||||
"""
|
||||
h = H(sk)
|
||||
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
|
||||
A = scalarmult_B(a)
|
||||
return encodepoint(A)
|
||||
|
||||
|
||||
def Hint(m):
|
||||
h = H(m)
|
||||
return sum(2 ** i * bit(h, i) for i in range(2 * b))
|
||||
|
||||
|
||||
def signature_unsafe(m, sk, pk):
|
||||
"""
|
||||
Not safe to use with secret keys or secret data.
|
||||
|
||||
See module docstring. This function should be used for testing only.
|
||||
"""
|
||||
h = H(sk)
|
||||
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
|
||||
r = Hint(
|
||||
intlist2bytes([indexbytes(h, j) for j in range(b // 8, b // 4)]) + m
|
||||
)
|
||||
R = scalarmult_B(r)
|
||||
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
|
||||
return encodepoint(R) + encodeint(S)
|
||||
|
||||
|
||||
def isoncurve(P):
|
||||
(x, y, z, t) = P
|
||||
return (z % q != 0 and
|
||||
x*y % q == z*t % q and
|
||||
(y*y - x*x - z*z - d*t*t) % q == 0)
|
||||
|
||||
|
||||
def decodeint(s):
|
||||
return sum(2 ** i * bit(s, i) for i in range(0, b))
|
||||
|
||||
|
||||
def decodepoint(s):
|
||||
y = sum(2 ** i * bit(s, i) for i in range(0, b - 1))
|
||||
x = xrecover(y)
|
||||
if x & 1 != bit(s, b-1):
|
||||
x = q - x
|
||||
P = (x, y, 1, (x*y) % q)
|
||||
if not isoncurve(P):
|
||||
raise ValueError("decoding point that is not on curve")
|
||||
return P
|
||||
|
||||
|
||||
class SignatureMismatch(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def checkvalid(s, m, pk):
|
||||
"""
|
||||
Not safe to use when any argument is secret.
|
||||
|
||||
See module docstring. This function should be used only for
|
||||
verifying public signatures of public messages.
|
||||
"""
|
||||
if len(s) != b // 4:
|
||||
raise ValueError("signature length is wrong")
|
||||
|
||||
if len(pk) != b // 8:
|
||||
raise ValueError("public-key length is wrong")
|
||||
|
||||
R = decodepoint(s[:b // 8])
|
||||
A = decodepoint(pk)
|
||||
S = decodeint(s[b // 8:b // 4])
|
||||
h = Hint(encodepoint(R) + pk + m)
|
||||
|
||||
(x1, y1, z1, t1) = P = scalarmult_B(S)
|
||||
(x2, y2, z2, t2) = Q = edwards_add(R, scalarmult(A, h))
|
||||
|
||||
if (not isoncurve(P) or not isoncurve(Q) or
|
||||
(x1*z2 - x2*z1) % q != 0 or (y1*z2 - y2*z1) % q != 0):
|
||||
raise SignatureMismatch("signature does not pass verification")
|
||||
|
||||
|
||||
def is_identity(P):
|
||||
return True if P[0] == 0 else False
|
||||
|
||||
|
||||
def edwards_negated(P):
|
||||
(x, y, z, t) = P
|
||||
|
||||
zi = inv(z)
|
||||
x = q - ((x * zi) % q)
|
||||
y = (y * zi) % q
|
||||
z = 1
|
||||
t = (x * y) % q
|
||||
|
||||
return (x, y, z, t)
|
|
@ -53,6 +53,9 @@ class Offer(Base):
|
|||
expire_at = sa.Column(sa.BigInteger)
|
||||
was_sent = sa.Column(sa.Boolean)
|
||||
|
||||
from_feerate = sa.Column(sa.BigInteger)
|
||||
to_feerate = sa.Column(sa.BigInteger)
|
||||
|
||||
auto_accept_bids = sa.Column(sa.Boolean)
|
||||
|
||||
state = sa.Column(sa.Integer)
|
||||
|
@ -125,10 +128,13 @@ class Bid(Base):
|
|||
self.participate_tx.state = new_state
|
||||
self.participate_tx.states = (self.participate_tx.states if self.participate_tx.states is not None else bytes()) + struct.pack('<iq', new_state, int(time.time()))
|
||||
|
||||
def setState(self, new_state):
|
||||
def setState(self, new_state, state_note=None):
|
||||
now = int(time.time())
|
||||
self.state = new_state
|
||||
self.state_time = now
|
||||
|
||||
if state_note is not None:
|
||||
self.state_note = state_note
|
||||
if self.states is None:
|
||||
self.states = struct.pack('<iq', new_state, now)
|
||||
else:
|
||||
|
@ -195,3 +201,75 @@ class EventQueue(Base):
|
|||
linked_id = sa.Column(sa.LargeBinary)
|
||||
event_type = sa.Column(sa.Integer)
|
||||
event_data = sa.Column(sa.LargeBinary)
|
||||
|
||||
|
||||
class XmrOffer(Base):
|
||||
__tablename__ = 'xmr_offers'
|
||||
|
||||
swap_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
||||
offer_id = sa.Column(sa.LargeBinary, sa.ForeignKey('offers.offer_id'))
|
||||
|
||||
a_fee_rate = sa.Column(sa.BigInteger)
|
||||
b_fee_rate = sa.Column(sa.BigInteger)
|
||||
|
||||
lock_time_1 = sa.Column(sa.Integer) # Delay before the chain a lock refund tx can be mined
|
||||
lock_time_2 = sa.Column(sa.Integer) # Delay before the follower can spend from the chain a lock refund tx
|
||||
|
||||
|
||||
class XmrSwap(Base):
|
||||
__tablename__ = 'xmr_swaps'
|
||||
|
||||
swap_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
||||
bid_id = sa.Column(sa.LargeBinary, sa.ForeignKey('bids.bid_id'))
|
||||
bid_msg_id2 = sa.Column(sa.LargeBinary)
|
||||
bid_msg_id3 = sa.Column(sa.LargeBinary)
|
||||
|
||||
bid_accept_msg_id = sa.Column(sa.LargeBinary)
|
||||
bid_accept_msg_id2 = sa.Column(sa.LargeBinary)
|
||||
bid_accept_msg_id3 = sa.Column(sa.LargeBinary)
|
||||
|
||||
contract_count = sa.Column(sa.Integer)
|
||||
|
||||
sh = sa.Column(sa.LargeBinary) # Secret hash
|
||||
|
||||
pkal = sa.Column(sa.LargeBinary)
|
||||
pkarl = sa.Column(sa.LargeBinary)
|
||||
|
||||
pkaf = sa.Column(sa.LargeBinary)
|
||||
pkarf = sa.Column(sa.LargeBinary)
|
||||
|
||||
vkbvl = sa.Column(sa.LargeBinary)
|
||||
vkbsl = sa.Column(sa.LargeBinary)
|
||||
pkbvl = sa.Column(sa.LargeBinary)
|
||||
pkbsl = sa.Column(sa.LargeBinary)
|
||||
|
||||
vkbvf = sa.Column(sa.LargeBinary)
|
||||
vkbsf = sa.Column(sa.LargeBinary)
|
||||
pkbvf = sa.Column(sa.LargeBinary)
|
||||
pkbsf = sa.Column(sa.LargeBinary)
|
||||
|
||||
kbsl_dleag = sa.Column(sa.LargeBinary)
|
||||
kbsf_dleag = sa.Column(sa.LargeBinary)
|
||||
|
||||
a_lock_tx = sa.Column(sa.LargeBinary)
|
||||
a_lock_tx_script = sa.Column(sa.LargeBinary)
|
||||
|
||||
a_lock_refund_tx = sa.Column(sa.LargeBinary)
|
||||
a_lock_refund_tx_script = sa.Column(sa.LargeBinary)
|
||||
a_swap_refund_value = sa.Column(sa.BigInteger)
|
||||
|
||||
a_lock_refund_spend_tx = sa.Column(sa.LargeBinary)
|
||||
|
||||
b_restore_height = sa.Column(sa.Integer) # Height of xmr chain before the swap
|
||||
|
||||
|
||||
class XmrSplitData(Base):
|
||||
__tablename__ = 'xmr_split_data'
|
||||
|
||||
record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
||||
bid_id = sa.Column(sa.LargeBinary)
|
||||
msg_type = sa.Column(sa.Integer)
|
||||
msg_sequence = sa.Column(sa.Integer)
|
||||
dleag = sa.Column(sa.LargeBinary)
|
||||
created_at = sa.Column(sa.BigInteger)
|
||||
|
||||
|
|
36
basicswap/ed25519_fast_util.py
Normal file
36
basicswap/ed25519_fast_util.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import secrets
|
||||
import hashlib
|
||||
import basicswap.contrib.ed25519_fast as edf
|
||||
|
||||
|
||||
def get_secret():
|
||||
return 9 + secrets.randbelow(edf.l - 9)
|
||||
|
||||
|
||||
def encodepoint(P):
|
||||
zi = edf.inv(P[2])
|
||||
x = (P[0] * zi) % edf.q
|
||||
y = (P[1] * zi) % edf.q
|
||||
y += ((x & 1) << 255)
|
||||
return y.to_bytes(32, byteorder='little')
|
||||
|
||||
|
||||
def hashToEd25519(bytes_in):
|
||||
hashed = hashlib.sha256(bytes_in).digest()
|
||||
for i in range(1000):
|
||||
h255 = bytearray(hashed)
|
||||
x_sign = 0 if h255[31] & 0x80 == 0 else 1
|
||||
h255[31] &= 0x7f # Clear top bit
|
||||
y = int.from_bytes(h255, byteorder='little')
|
||||
x = edf.xrecover(y, x_sign)
|
||||
if x == 0 and y == 1: # Skip infinity point
|
||||
continue
|
||||
|
||||
P = [x, y, 1, (x * y) % edf.q]
|
||||
# Keep trying until the point is in the correct subgroup
|
||||
if edf.isoncurve(P) and edf.is_identity(edf.scalarmult(P, edf.l)):
|
||||
return P
|
||||
hashed = hashlib.sha256(hashed).digest()
|
||||
raise ValueError('hashToEd25519 failed')
|
|
@ -17,6 +17,10 @@ from .util import (
|
|||
format_amount,
|
||||
make_int
|
||||
)
|
||||
from coincurve.keys import (
|
||||
PublicKey)
|
||||
from coincurve.dleag import (
|
||||
verify_secp256k1_point)
|
||||
|
||||
from .ecc_util import (
|
||||
G, ep,
|
||||
|
@ -126,6 +130,16 @@ class BTCInterface(CoinInterface):
|
|||
def pubkey(self, key):
|
||||
return G * key
|
||||
|
||||
def getPubkey(self, privkey):
|
||||
return PublicKey.from_secret(privkey).format()
|
||||
|
||||
def verifyKey(self, k):
|
||||
i = b2i(k)
|
||||
return(i < ep.o and i > 0)
|
||||
|
||||
def verifyPubkey(self, pubkey_bytes):
|
||||
return verify_secp256k1_point(pubkey_bytes)
|
||||
|
||||
def encodePubkey(self, pk):
|
||||
return pointToCPK(pk)
|
||||
|
||||
|
@ -192,14 +206,20 @@ class BTCInterface(CoinInterface):
|
|||
return secret_hash, pk1, pk2, csv_val, pk3, pk4
|
||||
|
||||
def genScriptLockTxScript(self, sh, Kal, Kaf, lock_blocks, Karl, Karf):
|
||||
|
||||
Kal_enc = Kal if len(Kal) == 33 else self.encodePubkey(Kal)
|
||||
Kaf_enc = Kaf if len(Kaf) == 33 else self.encodePubkey(Kaf)
|
||||
Karl_enc = Karl if len(Karl) == 33 else self.encodePubkey(Karl)
|
||||
Karf_enc = Karf if len(Karf) == 33 else self.encodePubkey(Karf)
|
||||
|
||||
return CScript([
|
||||
CScriptOp(OP_IF),
|
||||
CScriptOp(OP_SIZE), 32, CScriptOp(OP_EQUALVERIFY),
|
||||
CScriptOp(OP_SHA256), sh, CScriptOp(OP_EQUALVERIFY),
|
||||
2, self.encodePubkey(Kal), self.encodePubkey(Kaf), 2, CScriptOp(OP_CHECKMULTISIG),
|
||||
2, Kal_enc, Kaf_enc, 2, CScriptOp(OP_CHECKMULTISIG),
|
||||
CScriptOp(OP_ELSE),
|
||||
lock_blocks, CScriptOp(OP_CHECKSEQUENCEVERIFY), CScriptOp(OP_DROP),
|
||||
2, self.encodePubkey(Karl), self.encodePubkey(Karf), 2, CScriptOp(OP_CHECKMULTISIG),
|
||||
2, Karl_enc, Karf_enc, 2, CScriptOp(OP_CHECKMULTISIG),
|
||||
CScriptOp(OP_ENDIF)])
|
||||
|
||||
def createScriptLockTx(self, value, sh, Kal, Kaf, lock_blocks, Karl, Karf):
|
||||
|
@ -209,7 +229,7 @@ class BTCInterface(CoinInterface):
|
|||
tx.nVersion = self.txVersion()
|
||||
tx.vout.append(self.txoType(value, CScript([OP_0, hashlib.sha256(script).digest()])))
|
||||
|
||||
return tx, script
|
||||
return tx.serialize(), script
|
||||
|
||||
def extractScriptLockRefundScriptValues(self, script_bytes):
|
||||
script_len = len(script_bytes)
|
||||
|
@ -243,15 +263,22 @@ class BTCInterface(CoinInterface):
|
|||
return pk1, pk2, csv_val, pk3
|
||||
|
||||
def genScriptLockRefundTxScript(self, Karl, Karf, csv_val, Kaf):
|
||||
|
||||
Kaf_enc = Kaf if len(Kaf) == 33 else self.encodePubkey(Kaf)
|
||||
Karl_enc = Karl if len(Karl) == 33 else self.encodePubkey(Karl)
|
||||
Karf_enc = Karf if len(Karf) == 33 else self.encodePubkey(Karf)
|
||||
|
||||
return CScript([
|
||||
CScriptOp(OP_IF),
|
||||
2, self.encodePubkey(Karl), self.encodePubkey(Karf), 2, CScriptOp(OP_CHECKMULTISIG),
|
||||
2, Karl_enc, Karf_enc, 2, CScriptOp(OP_CHECKMULTISIG),
|
||||
CScriptOp(OP_ELSE),
|
||||
csv_val, CScriptOp(OP_CHECKSEQUENCEVERIFY), CScriptOp(OP_DROP),
|
||||
self.encodePubkey(Kaf), CScriptOp(OP_CHECKSIG),
|
||||
Kaf_enc, CScriptOp(OP_CHECKSIG),
|
||||
CScriptOp(OP_ENDIF)])
|
||||
|
||||
def createScriptLockRefundTx(self, tx_lock, script_lock, Karl, Karf, csv_val, Kaf, tx_fee_rate):
|
||||
def createScriptLockRefundTx(self, tx_lock_bytes, script_lock, Karl, Karf, csv_val, Kaf, tx_fee_rate):
|
||||
tx_lock = CTransaction()
|
||||
tx_lock = FromHex(tx_lock, tx_lock_bytes.hex())
|
||||
|
||||
output_script = CScript([OP_0, hashlib.sha256(script_lock).digest()])
|
||||
locked_n = findOutput(tx_lock, output_script)
|
||||
|
@ -281,13 +308,15 @@ class BTCInterface(CoinInterface):
|
|||
logging.info('createScriptLockRefundTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||
|
||||
return tx, refund_script, tx.vout[0].nValue
|
||||
return tx.serialize(), refund_script, tx.vout[0].nValue
|
||||
|
||||
def createScriptLockRefundSpendTx(self, tx_lock_refund, script_lock_refund, Kal, tx_fee_rate):
|
||||
def createScriptLockRefundSpendTx(self, tx_lock_refund_bytes, script_lock_refund, Kal, tx_fee_rate):
|
||||
# Returns the coinA locked coin to the leader
|
||||
# The follower will sign the multisig path with a signature encumbered by the leader's coinB spend pubkey
|
||||
# When the leader publishes the decrypted signature the leader's coinB spend privatekey will be revealed to the follower
|
||||
|
||||
tx_lock_refund = self.loadTx(tx_lock_refund_bytes)
|
||||
|
||||
output_script = CScript([OP_0, hashlib.sha256(script_lock_refund).digest()])
|
||||
locked_n = findOutput(tx_lock_refund, output_script)
|
||||
assert_cond(locked_n is not None, 'Output not found in tx')
|
||||
|
@ -300,7 +329,8 @@ class BTCInterface(CoinInterface):
|
|||
tx.nVersion = self.txVersion()
|
||||
tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=0))
|
||||
|
||||
pubkeyhash = hash160(self.encodePubkey(Kal))
|
||||
#pubkeyhash = hash160(self.encodePubkey(Kal))
|
||||
pubkeyhash = hash160(Kal)
|
||||
tx.vout.append(self.txoType(locked_coin, CScript([OP_0, pubkeyhash])))
|
||||
|
||||
witness_bytes = len(script_lock_refund)
|
||||
|
@ -315,7 +345,7 @@ class BTCInterface(CoinInterface):
|
|||
logging.info('createScriptLockRefundSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||
|
||||
return tx
|
||||
return tx.serialize()
|
||||
|
||||
def createScriptLockRefundSpendToFTx(self, tx_lock_refund, script_lock_refund, pkh_dest, tx_fee_rate):
|
||||
# Sends the coinA locked coin to the follower
|
||||
|
@ -347,7 +377,7 @@ class BTCInterface(CoinInterface):
|
|||
logging.info('createScriptLockRefundSpendToFTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||
|
||||
return tx
|
||||
return tx.serialize()
|
||||
|
||||
def createScriptLockSpendTx(self, tx_lock, script_lock, pkh_dest, tx_fee_rate):
|
||||
|
||||
|
@ -379,7 +409,7 @@ class BTCInterface(CoinInterface):
|
|||
logging.info('createScriptLockSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||
|
||||
return tx
|
||||
return tx.serialize()
|
||||
|
||||
def verifyLockTx(self, tx, script_out,
|
||||
swap_value,
|
||||
|
@ -592,11 +622,13 @@ class BTCInterface(CoinInterface):
|
|||
|
||||
return True
|
||||
|
||||
def signTx(self, key_int, tx, prevout_n, prevout_script, prevout_value):
|
||||
def signTx(self, key_bytes, tx_bytes, prevout_n, prevout_script, prevout_value):
|
||||
# TODO: use libsecp356k1
|
||||
tx = self.loadTx(tx_bytes)
|
||||
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
||||
|
||||
eck = ECKey()
|
||||
eck.set(i2b(key_int), compressed=True)
|
||||
eck.set(key_bytes, compressed=True)
|
||||
|
||||
return eck.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
||||
|
||||
|
@ -611,22 +643,25 @@ class BTCInterface(CoinInterface):
|
|||
def decryptOtVES(self, k, esig):
|
||||
return otves.DecSig(k, esig) + b'\x01' # 0x1 is SIGHASH_ALL
|
||||
|
||||
def verifyTxSig(self, tx, 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)
|
||||
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
||||
|
||||
ecK = ECPubKey()
|
||||
ecK.set_int(K.x(), K.y())
|
||||
#ecK.set_int(K.x(), K.y())
|
||||
ecK.set(K)
|
||||
return ecK.verify_ecdsa(sig[: -1], sig_hash) # Pop the hashtype byte
|
||||
|
||||
def fundTx(self, tx, feerate):
|
||||
feerate_str = format_amount(feerate, self.exp())
|
||||
rv = self.rpc_callback('fundrawtransaction', [ToHex(tx), {'feeRate': feerate_str}])
|
||||
return FromHex(tx, rv['hex'])
|
||||
rv = self.rpc_callback('fundrawtransaction', [tx.hex(), {'feeRate': feerate_str}])
|
||||
return bytes.fromhex(rv['hex'])
|
||||
|
||||
def signTxWithWallet(self, tx):
|
||||
rv = self.rpc_callback('signrawtransactionwithwallet', [ToHex(tx)])
|
||||
|
||||
return FromHex(tx, rv['hex'])
|
||||
#return FromHex(tx, rv['hex'])
|
||||
return bytes.fromhex(rv['hex'])
|
||||
|
||||
def publishTx(self, tx):
|
||||
return self.rpc_callback('sendrawtransaction', [ToHex(tx)])
|
||||
|
@ -640,7 +675,9 @@ class BTCInterface(CoinInterface):
|
|||
tx.deserialize(BytesIO(tx_bytes))
|
||||
return tx
|
||||
|
||||
def getTxHash(self, tx):
|
||||
def getTxHash(self, tx_bytes):
|
||||
tx = CTransaction()
|
||||
tx = FromHex(tx, tx_bytes.hex())
|
||||
tx.rehash()
|
||||
return i2b(tx.sha256)
|
||||
|
||||
|
@ -680,7 +717,7 @@ class BTCInterface(CoinInterface):
|
|||
tx.nVersion = self.txVersion()
|
||||
p2wpkh = self.getPkDest(Kbs)
|
||||
tx.vout.append(self.txoType(output_amount, p2wpkh))
|
||||
return tx
|
||||
return tx.serialize()
|
||||
|
||||
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate):
|
||||
b_lock_tx = self.createBLockTx(Kbs, output_amount)
|
||||
|
|
|
@ -8,11 +8,24 @@
|
|||
import time
|
||||
import logging
|
||||
|
||||
from .chainparams import CoinInterface
|
||||
from .rpc_xmr import make_xmr_rpc_func, make_xmr_wallet_rpc_func
|
||||
import basicswap.contrib.ed25519_fast as edf
|
||||
import basicswap.ed25519_fast_util as edu
|
||||
from coincurve.ed25519 import ed25519_get_pubkey
|
||||
from coincurve.keys import PrivateKey
|
||||
from coincurve.dleag import (
|
||||
verify_ed25519_point,
|
||||
dleag_proof_len,
|
||||
dleag_verify,
|
||||
dleag_prove)
|
||||
|
||||
from .util import (
|
||||
format_amount
|
||||
)
|
||||
format_amount)
|
||||
from .rpc_xmr import (
|
||||
make_xmr_rpc_func,
|
||||
make_xmr_wallet_rpc_func)
|
||||
from .ecc_util import (
|
||||
b2i)
|
||||
from .chainparams import CoinInterface
|
||||
|
||||
XMR_COIN = 10 ** 12
|
||||
|
||||
|
@ -49,6 +62,9 @@ class XMRInterface(CoinInterface):
|
|||
rv['verificationprogress'] = 0 # TODO
|
||||
return rv
|
||||
|
||||
def getChainHeight(self):
|
||||
return self.rpc_cb('get_block_count')['count']
|
||||
|
||||
def getWalletInfo(self):
|
||||
rv = {}
|
||||
balance_info = self.rpc_wallet_cb('get_balance')
|
||||
|
@ -60,6 +76,10 @@ class XMRInterface(CoinInterface):
|
|||
logging.debug('TODO - subaddress?')
|
||||
return self.rpc_wallet_cb('get_address')['address']
|
||||
|
||||
def isValidKey(self, key_bytes):
|
||||
ki = b2i(key_bytes)
|
||||
return ki < edf.l and ki > 8
|
||||
|
||||
def getNewSecretKey(self):
|
||||
return edu.get_secret()
|
||||
|
||||
|
@ -72,6 +92,26 @@ class XMRInterface(CoinInterface):
|
|||
def decodePubkey(self, pke):
|
||||
return edf.decodepoint(pke)
|
||||
|
||||
def getPubkey(self, privkey):
|
||||
return ed25519_get_pubkey(privkey)
|
||||
|
||||
def verifyKey(self, k):
|
||||
i = b2i(k)
|
||||
return(i < edf.l and i > 8)
|
||||
|
||||
def verifyPubkey(self, pubkey_bytes):
|
||||
return verify_ed25519_point(pubkey_bytes)
|
||||
|
||||
def proveDLEAG(self, key):
|
||||
privkey = PrivateKey(key)
|
||||
return dleag_prove(privkey)
|
||||
|
||||
def verifyDLEAG(self, dleag_bytes):
|
||||
return dleag_verify(dleag_bytes)
|
||||
|
||||
def lengthDLEAG(self):
|
||||
return dleag_proof_len()
|
||||
|
||||
def decodeKey(self, k):
|
||||
i = b2i(k)
|
||||
assert(i < edf.l and i > 8)
|
||||
|
|
|
@ -26,6 +26,9 @@ message OfferMessage {
|
|||
string proof_signature = 11;
|
||||
bytes pkhash_seller = 12;
|
||||
bytes secret_hash = 13;
|
||||
|
||||
uint64 fee_rate_from = 14;
|
||||
uint64 fee_rate_to = 15;
|
||||
}
|
||||
|
||||
/* Step 2, buyer -> seller */
|
||||
|
@ -48,29 +51,44 @@ message BidAcceptMessage {
|
|||
}
|
||||
|
||||
|
||||
message XmrOfferMessage {
|
||||
uint32 coin_from = 1;
|
||||
uint32 coin_to = 2;
|
||||
uint64 amount_from = 3;
|
||||
uint64 rate = 4;
|
||||
uint64 min_bid_amount = 5;
|
||||
uint64 time_valid = 6;
|
||||
enum LockType {
|
||||
NOT_SET = 0;
|
||||
SEQUENCE_LOCK_BLOCKS = 1;
|
||||
SEQUENCE_LOCK_TIME = 2;
|
||||
ABS_LOCK_BLOCKS = 3;
|
||||
ABS_LOCK_TIME = 4;
|
||||
}
|
||||
LockType lock_type = 7;
|
||||
uint32 lock_value = 8;
|
||||
uint32 swap_type = 9;
|
||||
|
||||
/* Step 2, buyer -> seller */
|
||||
message XmrBidMessage {
|
||||
bytes offer_msg_id = 1;
|
||||
uint64 time_valid = 2; /* seconds bid is valid for */
|
||||
uint64 amount = 3; /* amount of amount_from bid is for */
|
||||
|
||||
bytes pkaf = 4;
|
||||
bytes pkarf = 5;
|
||||
|
||||
/* optional */
|
||||
string proof_address = 10;
|
||||
string proof_signature = 11;
|
||||
bytes pkhash_seller = 12;
|
||||
bytes secret_hash = 13;
|
||||
bytes kbvf = 6;
|
||||
bytes kbsf_dleag = 7;
|
||||
}
|
||||
|
||||
message XmrSplitMessage {
|
||||
bytes msg_id = 1;
|
||||
uint32 msg_type = 2; /* 1 XmrBid, 2 XmrBidAccept */
|
||||
uint32 sequence = 3;
|
||||
bytes dleag = 4;
|
||||
}
|
||||
|
||||
|
||||
message XmrBidAcceptMessage {
|
||||
bytes bid_msg_id = 1;
|
||||
|
||||
bytes sh = 2;
|
||||
bytes pkal = 3;
|
||||
bytes pkarl = 4;
|
||||
|
||||
bytes kbvl = 5;
|
||||
bytes kbsl_dleag = 6;
|
||||
|
||||
/* MSG2F */
|
||||
bytes a_lock_tx = 7;
|
||||
bytes a_lock_tx_script = 8;
|
||||
bytes a_lock_refund_tx = 9;
|
||||
bytes a_lock_refund_tx_script = 10;
|
||||
bytes a_lock_refund_spend_tx = 11;
|
||||
bytes al_lock_refund_tx_sig = 12;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
|||
syntax='proto3',
|
||||
serialized_options=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\xac\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\"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\"\xb2\x03\n\x0fXmrOfferMessage\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\x36\n\tlock_type\x18\x07 \x01(\x0e\x32#.basicswap.XmrOfferMessage.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\"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\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\"\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'
|
||||
)
|
||||
|
||||
|
||||
|
@ -59,51 +59,11 @@ _OFFERMESSAGE_LOCKTYPE = _descriptor.EnumDescriptor(
|
|||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=345,
|
||||
serialized_end=458,
|
||||
serialized_start=389,
|
||||
serialized_end=502,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_OFFERMESSAGE_LOCKTYPE)
|
||||
|
||||
_XMROFFERMESSAGE_LOCKTYPE = _descriptor.EnumDescriptor(
|
||||
name='LockType',
|
||||
full_name='basicswap.XmrOfferMessage.LockType',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NOT_SET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SEQUENCE_LOCK_BLOCKS', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SEQUENCE_LOCK_TIME', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ABS_LOCK_BLOCKS', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ABS_LOCK_TIME', index=4, number=4,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=345,
|
||||
serialized_end=458,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_XMROFFERMESSAGE_LOCKTYPE)
|
||||
|
||||
|
||||
_OFFERMESSAGE = _descriptor.Descriptor(
|
||||
name='OfferMessage',
|
||||
|
@ -204,6 +164,20 @@ _OFFERMESSAGE = _descriptor.Descriptor(
|
|||
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='fee_rate_from', full_name='basicswap.OfferMessage.fee_rate_from', index=13,
|
||||
number=14, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='fee_rate_to', full_name='basicswap.OfferMessage.fee_rate_to', index=14,
|
||||
number=15, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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=[
|
||||
],
|
||||
|
@ -218,7 +192,7 @@ _OFFERMESSAGE = _descriptor.Descriptor(
|
|||
oneofs=[
|
||||
],
|
||||
serialized_start=30,
|
||||
serialized_end=458,
|
||||
serialized_end=502,
|
||||
)
|
||||
|
||||
|
||||
|
@ -284,8 +258,8 @@ _BIDMESSAGE = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=461,
|
||||
serialized_end=601,
|
||||
serialized_start=505,
|
||||
serialized_end=645,
|
||||
)
|
||||
|
||||
|
||||
|
@ -330,106 +304,64 @@ _BIDACCEPTMESSAGE = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=603,
|
||||
serialized_end=689,
|
||||
serialized_start=647,
|
||||
serialized_end=733,
|
||||
)
|
||||
|
||||
|
||||
_XMROFFERMESSAGE = _descriptor.Descriptor(
|
||||
name='XmrOfferMessage',
|
||||
full_name='basicswap.XmrOfferMessage',
|
||||
_XMRBIDMESSAGE = _descriptor.Descriptor(
|
||||
name='XmrBidMessage',
|
||||
full_name='basicswap.XmrBidMessage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='coin_from', full_name='basicswap.XmrOfferMessage.coin_from', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
name='offer_msg_id', full_name='basicswap.XmrBidMessage.offer_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='time_valid', full_name='basicswap.XmrBidMessage.time_valid', index=1,
|
||||
number=2, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='coin_to', full_name='basicswap.XmrOfferMessage.coin_to', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='amount_from', full_name='basicswap.XmrOfferMessage.amount_from', index=2,
|
||||
name='amount', full_name='basicswap.XmrBidMessage.amount', index=2,
|
||||
number=3, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='rate', full_name='basicswap.XmrOfferMessage.rate', index=3,
|
||||
number=4, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='min_bid_amount', full_name='basicswap.XmrOfferMessage.min_bid_amount', index=4,
|
||||
number=5, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='time_valid', full_name='basicswap.XmrOfferMessage.time_valid', index=5,
|
||||
number=6, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='lock_type', full_name='basicswap.XmrOfferMessage.lock_type', index=6,
|
||||
number=7, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='lock_value', full_name='basicswap.XmrOfferMessage.lock_value', index=7,
|
||||
number=8, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='swap_type', full_name='basicswap.XmrOfferMessage.swap_type', index=8,
|
||||
number=9, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='proof_address', full_name='basicswap.XmrOfferMessage.proof_address', index=9,
|
||||
number=10, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
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='proof_signature', full_name='basicswap.XmrOfferMessage.proof_signature', index=10,
|
||||
number=11, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
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='pkhash_seller', full_name='basicswap.XmrOfferMessage.pkhash_seller', index=11,
|
||||
number=12, type=12, cpp_type=9, label=1,
|
||||
name='pkaf', full_name='basicswap.XmrBidMessage.pkaf', index=3,
|
||||
number=4, 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='secret_hash', full_name='basicswap.XmrOfferMessage.secret_hash', index=12,
|
||||
number=13, type=12, cpp_type=9, label=1,
|
||||
name='pkarf', full_name='basicswap.XmrBidMessage.pkarf', index=4,
|
||||
number=5, 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='kbvf', full_name='basicswap.XmrBidMessage.kbvf', index=5,
|
||||
number=6, 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='kbsf_dleag', full_name='basicswap.XmrBidMessage.kbsf_dleag', index=6,
|
||||
number=7, 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,
|
||||
|
@ -439,7 +371,6 @@ _XMROFFERMESSAGE = _descriptor.Descriptor(
|
|||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_XMROFFERMESSAGE_LOCKTYPE,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
|
@ -447,18 +378,180 @@ _XMROFFERMESSAGE = _descriptor.Descriptor(
|
|||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=692,
|
||||
serialized_end=1126,
|
||||
serialized_start=736,
|
||||
serialized_end=872,
|
||||
)
|
||||
|
||||
|
||||
_XMRSPLITMESSAGE = _descriptor.Descriptor(
|
||||
name='XmrSplitMessage',
|
||||
full_name='basicswap.XmrSplitMessage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='msg_id', full_name='basicswap.XmrSplitMessage.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='msg_type', full_name='basicswap.XmrSplitMessage.msg_type', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='sequence', full_name='basicswap.XmrSplitMessage.sequence', index=2,
|
||||
number=3, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
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='dleag', full_name='basicswap.XmrSplitMessage.dleag', index=3,
|
||||
number=4, 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=874,
|
||||
serialized_end=958,
|
||||
)
|
||||
|
||||
|
||||
_XMRBIDACCEPTMESSAGE = _descriptor.Descriptor(
|
||||
name='XmrBidAcceptMessage',
|
||||
full_name='basicswap.XmrBidAcceptMessage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='bid_msg_id', full_name='basicswap.XmrBidAcceptMessage.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='sh', full_name='basicswap.XmrBidAcceptMessage.sh', 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='pkal', full_name='basicswap.XmrBidAcceptMessage.pkal', 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),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='pkarl', full_name='basicswap.XmrBidAcceptMessage.pkarl', index=3,
|
||||
number=4, 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='kbvl', full_name='basicswap.XmrBidAcceptMessage.kbvl', index=4,
|
||||
number=5, 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='kbsl_dleag', full_name='basicswap.XmrBidAcceptMessage.kbsl_dleag', index=5,
|
||||
number=6, 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_tx', full_name='basicswap.XmrBidAcceptMessage.a_lock_tx', index=6,
|
||||
number=7, 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_tx_script', full_name='basicswap.XmrBidAcceptMessage.a_lock_tx_script', 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),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='a_lock_refund_tx', full_name='basicswap.XmrBidAcceptMessage.a_lock_refund_tx', index=8,
|
||||
number=9, 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_refund_tx_script', full_name='basicswap.XmrBidAcceptMessage.a_lock_refund_tx_script', index=9,
|
||||
number=10, 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_refund_spend_tx', full_name='basicswap.XmrBidAcceptMessage.a_lock_refund_spend_tx', index=10,
|
||||
number=11, 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_refund_tx_sig', full_name='basicswap.XmrBidAcceptMessage.al_lock_refund_tx_sig', index=11,
|
||||
number=12, 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=961,
|
||||
serialized_end=1244,
|
||||
)
|
||||
|
||||
_OFFERMESSAGE.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE
|
||||
_OFFERMESSAGE_LOCKTYPE.containing_type = _OFFERMESSAGE
|
||||
_XMROFFERMESSAGE.fields_by_name['lock_type'].enum_type = _XMROFFERMESSAGE_LOCKTYPE
|
||||
_XMROFFERMESSAGE_LOCKTYPE.containing_type = _XMROFFERMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['OfferMessage'] = _OFFERMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['BidMessage'] = _BIDMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['BidAcceptMessage'] = _BIDACCEPTMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['XmrOfferMessage'] = _XMROFFERMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['XmrBidMessage'] = _XMRBIDMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['XmrSplitMessage'] = _XMRSPLITMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['XmrBidAcceptMessage'] = _XMRBIDACCEPTMESSAGE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), {
|
||||
|
@ -482,12 +575,26 @@ BidAcceptMessage = _reflection.GeneratedProtocolMessageType('BidAcceptMessage',
|
|||
})
|
||||
_sym_db.RegisterMessage(BidAcceptMessage)
|
||||
|
||||
XmrOfferMessage = _reflection.GeneratedProtocolMessageType('XmrOfferMessage', (_message.Message,), {
|
||||
'DESCRIPTOR' : _XMROFFERMESSAGE,
|
||||
XmrBidMessage = _reflection.GeneratedProtocolMessageType('XmrBidMessage', (_message.Message,), {
|
||||
'DESCRIPTOR' : _XMRBIDMESSAGE,
|
||||
'__module__' : 'messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:basicswap.XmrOfferMessage)
|
||||
# @@protoc_insertion_point(class_scope:basicswap.XmrBidMessage)
|
||||
})
|
||||
_sym_db.RegisterMessage(XmrOfferMessage)
|
||||
_sym_db.RegisterMessage(XmrBidMessage)
|
||||
|
||||
XmrSplitMessage = _reflection.GeneratedProtocolMessageType('XmrSplitMessage', (_message.Message,), {
|
||||
'DESCRIPTOR' : _XMRSPLITMESSAGE,
|
||||
'__module__' : 'messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:basicswap.XmrSplitMessage)
|
||||
})
|
||||
_sym_db.RegisterMessage(XmrSplitMessage)
|
||||
|
||||
XmrBidAcceptMessage = _reflection.GeneratedProtocolMessageType('XmrBidAcceptMessage', (_message.Message,), {
|
||||
'DESCRIPTOR' : _XMRBIDACCEPTMESSAGE,
|
||||
'__module__' : 'messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:basicswap.XmrBidAcceptMessage)
|
||||
})
|
||||
_sym_db.RegisterMessage(XmrBidAcceptMessage)
|
||||
|
||||
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import json
|
||||
import decimal
|
||||
import hashlib
|
||||
from .contrib.segwit_addr import bech32_decode, convertbits, bech32_encode
|
||||
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2019 tecnovert
|
||||
# Copyright (c) 2019-2020 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
import unittest
|
||||
|
||||
import basicswap.contrib.ed25519_fast as edf
|
||||
import basicswap.ed25519_fast_util as edu
|
||||
|
||||
from basicswap.ecc_util import i2b
|
||||
from coincurve.ed25519 import ed25519_get_pubkey
|
||||
|
||||
|
||||
from basicswap.util import (
|
||||
SerialiseNum,
|
||||
DeserialiseNum,
|
||||
make_int,
|
||||
format8,
|
||||
format_amount,
|
||||
validate_amount,
|
||||
)
|
||||
from basicswap.basicswap import (
|
||||
Coins,
|
||||
|
@ -134,6 +144,14 @@ class Test(unittest.TestCase):
|
|||
except Exception as e:
|
||||
assert('Too many decimal places' in str(e))
|
||||
|
||||
def test_ed25519(self):
|
||||
privkey = edu.get_secret()
|
||||
pubkey = edu.encodepoint(edf.scalarmult_B(privkey))
|
||||
|
||||
privkey_bytes = i2b(privkey)
|
||||
pubkey_test = ed25519_get_pubkey(privkey_bytes)
|
||||
assert(pubkey == pubkey_test)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -67,6 +67,8 @@ from tests.basicswap.common import (
|
|||
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
|
||||
from bin.basicswap_run import startDaemon
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
NUM_NODES = 3
|
||||
|
@ -239,6 +241,7 @@ def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
|
|||
'check_watched_seconds': 4,
|
||||
'check_expired_seconds': 60,
|
||||
'check_events_seconds': 1,
|
||||
'check_xmr_swaps_seconds': 1,
|
||||
'min_delay_auto_accept': 1,
|
||||
'max_delay_auto_accept': 5
|
||||
}
|
||||
|
@ -310,7 +313,7 @@ def run_loop(cls):
|
|||
btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr))
|
||||
|
||||
if cls.xmr_addr is not None:
|
||||
callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': 1})
|
||||
callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': 1})
|
||||
time.sleep(1.0)
|
||||
|
||||
|
||||
|
@ -335,6 +338,7 @@ class Test(unittest.TestCase):
|
|||
logger.propagate = False
|
||||
logger.handlers = []
|
||||
logger.setLevel(logging.INFO) # DEBUG shows many messages from requests.post
|
||||
#logger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
||||
stream_stdout = logging.StreamHandler()
|
||||
stream_stdout.setFormatter(formatter)
|
||||
|
@ -417,7 +421,7 @@ class Test(unittest.TestCase):
|
|||
t.start()
|
||||
|
||||
cls.btc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT)
|
||||
cls.xmr_addr = cls.callxmrnodewallet(cls, 0, 'get_address')['address']
|
||||
cls.xmr_addr = cls.callxmrnodewallet(cls, 1, 'get_address')['address']
|
||||
|
||||
num_blocks = 500
|
||||
logging.info('Mining %d bitcoin blocks to %s', num_blocks, cls.btc_addr)
|
||||
|
@ -425,10 +429,10 @@ class Test(unittest.TestCase):
|
|||
|
||||
checkForks(callnoderpc(0, 'getblockchaininfo', base_rpc_port=BTC_BASE_RPC_PORT))
|
||||
|
||||
if callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'get_block_count')['count'] < num_blocks:
|
||||
if callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'] < num_blocks:
|
||||
logging.info('Mining %d Monero blocks.', num_blocks)
|
||||
callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': num_blocks})
|
||||
rv = callrpc_xmr_na(XMR_BASE_RPC_PORT + 0, 'get_block_count')
|
||||
callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': num_blocks})
|
||||
rv = callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')
|
||||
logging.info('XMR blocks: %d', rv['count'])
|
||||
|
||||
logging.info('Starting update thread.')
|
||||
|
@ -509,21 +513,49 @@ class Test(unittest.TestCase):
|
|||
return
|
||||
raise ValueError('wait_for_offer timed out.')
|
||||
|
||||
def wait_for_bid(self, swap_client, bid_id, state=None, sent=False):
|
||||
logging.info('wait_for_bid %s', bid_id.hex())
|
||||
for i in range(20):
|
||||
time.sleep(1)
|
||||
bids = swap_client.listBids(sent=sent)
|
||||
for bid in bids:
|
||||
if bid[1] == bid_id:
|
||||
if state is not None and state != bid[4]:
|
||||
continue
|
||||
return
|
||||
raise ValueError('wait_for_bid timed out.')
|
||||
|
||||
def test_01_part_xmr(self):
|
||||
logging.info('---------- Test PART to XMR')
|
||||
swap_clients = self.swap_clients
|
||||
|
||||
js_0 = json.loads(urlopen('http://localhost:1800/json/wallets').read())
|
||||
js_0 = json.loads(urlopen('http://localhost:1801/json/wallets').read())
|
||||
assert(make_int(js_0[str(int(Coins.XMR))]['balance'], scale=12) > 0)
|
||||
assert(make_int(js_0[str(int(Coins.XMR))]['unconfirmed'], scale=12) > 0)
|
||||
|
||||
offer_id = swap_clients[0].postOffer(Coins.PART, Coins.XMR, 100 * COIN, 10 * XMR_COIN, 100 * COIN, SwapTypes.XMR_SWAP)
|
||||
|
||||
self.wait_for_offer(swap_clients[1], offer_id)
|
||||
offers = swap_clients[1].listOffers()
|
||||
offer = swap_clients[1].getOffer(offer_id)
|
||||
|
||||
offers = swap_clients[1].listOffers(filters={'offer_id': offer_id})
|
||||
assert(len(offers) == 1)
|
||||
for offer in offers:
|
||||
print('offer', offer)
|
||||
offer = offers[0]
|
||||
pprint(vars(offer))
|
||||
|
||||
bid_id = swap_clients[1].postXmrBid(offer_id, offer.amount_from)
|
||||
|
||||
self.wait_for_bid(swap_clients[0], bid_id, BidStates.BID_RECEIVED)
|
||||
|
||||
bid, xmr_swap = swap_clients[0].getXmrBid(bid_id)
|
||||
assert(xmr_swap)
|
||||
|
||||
swap_clients[0].acceptXmrBid(bid_id)
|
||||
|
||||
self.wait_for_bid(swap_clients[1], bid_id, BidStates.BID_ACCEPTED, sent=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in a new issue