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 os
|
||||||
import re
|
import re
|
||||||
import time
|
|
||||||
import datetime as dt
|
|
||||||
import zmq
|
import zmq
|
||||||
import traceback
|
|
||||||
import hashlib
|
|
||||||
import sqlalchemy as sa
|
|
||||||
import shutil
|
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
import random
|
import random
|
||||||
|
import logging
|
||||||
import secrets
|
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 enum import IntEnum, auto
|
||||||
|
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||||
|
|
||||||
from .interface_part import PARTInterface
|
from .interface_part import PARTInterface
|
||||||
from .interface_btc import BTCInterface
|
from .interface_btc import BTCInterface
|
||||||
|
@ -39,6 +41,7 @@ from .util import (
|
||||||
toWIF,
|
toWIF,
|
||||||
getKeyID,
|
getKeyID,
|
||||||
make_int,
|
make_int,
|
||||||
|
dumpj
|
||||||
)
|
)
|
||||||
from .chainparams import (
|
from .chainparams import (
|
||||||
chainparams,
|
chainparams,
|
||||||
|
@ -51,6 +54,9 @@ from .messages_pb2 import (
|
||||||
OfferMessage,
|
OfferMessage,
|
||||||
BidMessage,
|
BidMessage,
|
||||||
BidAcceptMessage,
|
BidAcceptMessage,
|
||||||
|
XmrBidMessage,
|
||||||
|
XmrBidAcceptMessage,
|
||||||
|
XmrSplitMessage,
|
||||||
)
|
)
|
||||||
from .db import (
|
from .db import (
|
||||||
CURRENT_DB_VERSION,
|
CURRENT_DB_VERSION,
|
||||||
|
@ -64,6 +70,9 @@ from .db import (
|
||||||
SentOffer,
|
SentOffer,
|
||||||
SmsgAddress,
|
SmsgAddress,
|
||||||
EventQueue,
|
EventQueue,
|
||||||
|
XmrOffer,
|
||||||
|
XmrSwap,
|
||||||
|
XmrSplitData,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .explorers import ExplorerInsight, ExplorerBitAps, ExplorerChainz
|
from .explorers import ExplorerInsight, ExplorerBitAps, ExplorerChainz
|
||||||
|
@ -83,6 +92,9 @@ class MessageTypes(IntEnum):
|
||||||
BID_ACCEPT = auto()
|
BID_ACCEPT = auto()
|
||||||
|
|
||||||
XMR_OFFER = auto()
|
XMR_OFFER = auto()
|
||||||
|
XMR_BID = auto()
|
||||||
|
XMR_BID_SPLIT = auto()
|
||||||
|
XMR_BID_ACCEPT = auto()
|
||||||
|
|
||||||
|
|
||||||
class SwapTypes(IntEnum):
|
class SwapTypes(IntEnum):
|
||||||
|
@ -101,7 +113,9 @@ class OfferStates(IntEnum):
|
||||||
|
|
||||||
class BidStates(IntEnum):
|
class BidStates(IntEnum):
|
||||||
BID_SENT = auto()
|
BID_SENT = auto()
|
||||||
|
BID_RECEIVING = auto() # Partially received
|
||||||
BID_RECEIVED = auto()
|
BID_RECEIVED = auto()
|
||||||
|
BID_RECEIVING_ACC = auto() # Partially received accept message
|
||||||
BID_ACCEPTED = auto() # BidAcceptMessage received/sent
|
BID_ACCEPTED = auto() # BidAcceptMessage received/sent
|
||||||
SWAP_INITIATED = auto() # Initiate txn validated
|
SWAP_INITIATED = auto() # Initiate txn validated
|
||||||
SWAP_PARTICIPATING = auto() # Participate txn validated
|
SWAP_PARTICIPATING = auto() # Participate txn validated
|
||||||
|
@ -132,6 +146,11 @@ class EventTypes(IntEnum):
|
||||||
ACCEPT_BID = auto()
|
ACCEPT_BID = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class XmrSplitMsgTypes(IntEnum):
|
||||||
|
BID = auto()
|
||||||
|
BID_ACCEPT = auto()
|
||||||
|
|
||||||
|
|
||||||
SEQUENCE_LOCK_BLOCKS = 1
|
SEQUENCE_LOCK_BLOCKS = 1
|
||||||
SEQUENCE_LOCK_TIME = 2
|
SEQUENCE_LOCK_TIME = 2
|
||||||
ABS_LOCK_BLOCKS = 3
|
ABS_LOCK_BLOCKS = 3
|
||||||
|
@ -298,10 +317,12 @@ class BasicSwap(BaseApp):
|
||||||
self.check_watched_seconds = self.settings.get('check_watched_seconds', 60)
|
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_expired_seconds = self.settings.get('check_expired_seconds', 60 * 5)
|
||||||
self.check_events_seconds = self.settings.get('check_events_seconds', 10)
|
self.check_events_seconds = self.settings.get('check_events_seconds', 10)
|
||||||
self.last_checked_progress = 0
|
self.check_xmr_swaps_seconds = self.settings.get('check_xmr_swaps_seconds', 20)
|
||||||
self.last_checked_watched = 0
|
self._last_checked_progress = 0
|
||||||
self.last_checked_expired = 0
|
self._last_checked_watched = 0
|
||||||
self.last_checked_events = 0
|
self._last_checked_expired = 0
|
||||||
|
self._last_checked_events = 0
|
||||||
|
self._last_checked_xmr_swaps = 0
|
||||||
|
|
||||||
# TODO: Adjust ranges
|
# TODO: Adjust ranges
|
||||||
self.min_delay_auto_accept = self.settings.get('min_delay_auto_accept', 10)
|
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_key = toWIF(wif_prefix, decodeWif(self.settings['network_key']))
|
||||||
|
|
||||||
self.network_pubkey = self.settings['network_pubkey']
|
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.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)))
|
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
|
value=self._contract_count
|
||||||
))
|
))
|
||||||
session.commit()
|
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.close()
|
||||||
session.remove()
|
session.remove()
|
||||||
|
|
||||||
|
@ -450,6 +462,9 @@ class BasicSwap(BaseApp):
|
||||||
raise ValueError('Missing XMR wallet rpc credentials.')
|
raise ValueError('Missing XMR wallet rpc credentials.')
|
||||||
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
self.coin_clients[coin]['interface'] = self.createInterface(coin)
|
||||||
|
|
||||||
|
def ci(self, coin): # coin interface
|
||||||
|
return self.coin_clients[coin]['interface']
|
||||||
|
|
||||||
def createInterface(self, coin):
|
def createInterface(self, coin):
|
||||||
if coin == Coins.PART:
|
if coin == Coins.PART:
|
||||||
return PARTInterface(self.coin_clients[coin])
|
return PARTInterface(self.coin_clients[coin])
|
||||||
|
@ -741,12 +756,7 @@ class BasicSwap(BaseApp):
|
||||||
offer_addr = self.callrpc('getnewaddress') if addr_send_from is None else addr_send_from
|
offer_addr = self.callrpc('getnewaddress') if addr_send_from is None else addr_send_from
|
||||||
|
|
||||||
offer_created_at = int(time.time())
|
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_from = int(coin_from)
|
||||||
|
@ -760,6 +770,18 @@ class BasicSwap(BaseApp):
|
||||||
msg_buf.lock_value = lock_value
|
msg_buf.lock_value = lock_value
|
||||||
msg_buf.swap_type = swap_type
|
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()
|
offer_bytes = msg_buf.SerializeToString()
|
||||||
payload_hex = str.format('{:02x}', MessageTypes.OFFER) + offer_bytes.hex()
|
payload_hex = str.format('{:02x}', MessageTypes.OFFER) + offer_bytes.hex()
|
||||||
|
|
||||||
|
@ -792,6 +814,10 @@ class BasicSwap(BaseApp):
|
||||||
auto_accept_bids=auto_accept_bids,)
|
auto_accept_bids=auto_accept_bids,)
|
||||||
offer.setState(OfferStates.OFFER_SENT)
|
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(offer)
|
||||||
session.add(SentOffer(offer_id=offer_id))
|
session.add(SentOffer(offer_id=offer_id))
|
||||||
if addr_send_from is None:
|
if addr_send_from is None:
|
||||||
|
@ -804,6 +830,31 @@ class BasicSwap(BaseApp):
|
||||||
self.log.info('Sent OFFER %s', offer_id.hex())
|
self.log.info('Sent OFFER %s', offer_id.hex())
|
||||||
return offer_id
|
return offer_id
|
||||||
|
|
||||||
|
def 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):
|
def getContractPubkey(self, date, contract_count):
|
||||||
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
account = self.callcoinrpc(Coins.PART, 'extkey', ['account'])
|
||||||
|
|
||||||
|
@ -1005,18 +1056,31 @@ class BasicSwap(BaseApp):
|
||||||
|
|
||||||
return (sign_for_addr, signature)
|
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)
|
session.add(bid)
|
||||||
if bid.initiate_tx:
|
if bid.initiate_tx:
|
||||||
session.add(bid.initiate_tx)
|
session.add(bid.initiate_tx)
|
||||||
if bid.participate_tx:
|
if bid.participate_tx:
|
||||||
session.add(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()
|
self.mxDB.acquire()
|
||||||
try:
|
try:
|
||||||
session = scoped_session(self.session_factory)
|
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.commit()
|
||||||
session.close()
|
session.close()
|
||||||
session.remove()
|
session.remove()
|
||||||
|
@ -1070,6 +1134,8 @@ class BasicSwap(BaseApp):
|
||||||
proof_addr, proof_sig = self.getProofOfFunds(coin_to, msg_buf.amount)
|
proof_addr, proof_sig = self.getProofOfFunds(coin_to, msg_buf.amount)
|
||||||
msg_buf.proof_address = proof_addr
|
msg_buf.proof_address = proof_addr
|
||||||
msg_buf.proof_signature = proof_sig
|
msg_buf.proof_signature = proof_sig
|
||||||
|
else:
|
||||||
|
raise ValueError('TODO')
|
||||||
|
|
||||||
bid_bytes = msg_buf.SerializeToString()
|
bid_bytes = msg_buf.SerializeToString()
|
||||||
payload_hex = str.format('{:02x}', MessageTypes.BID) + bid_bytes.hex()
|
payload_hex = str.format('{:02x}', MessageTypes.BID) + bid_bytes.hex()
|
||||||
|
@ -1124,6 +1190,34 @@ class BasicSwap(BaseApp):
|
||||||
session.remove()
|
session.remove()
|
||||||
self.mxDB.release()
|
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):
|
def getBid(self, bid_id):
|
||||||
self.mxDB.acquire()
|
self.mxDB.acquire()
|
||||||
try:
|
try:
|
||||||
|
@ -1244,6 +1338,254 @@ class BasicSwap(BaseApp):
|
||||||
self.saveBid(bid_id, bid)
|
self.saveBid(bid_id, bid)
|
||||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
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):
|
def abandonOffer(self, offer_id):
|
||||||
self.log.info('Abandoning Offer %s', offer_id.hex())
|
self.log.info('Abandoning Offer %s', offer_id.hex())
|
||||||
self.mxDB.acquire()
|
self.mxDB.acquire()
|
||||||
|
@ -1282,10 +1624,10 @@ class BasicSwap(BaseApp):
|
||||||
session.remove()
|
session.remove()
|
||||||
self.mxDB.release()
|
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.setState(BidStates.BID_ERROR)
|
||||||
bid.state_note = 'error msg: ' + error_str
|
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):
|
def createInitiateTxn(self, coin_type, bid_id, bid, initiate_script):
|
||||||
if self.coin_clients[coin_type]['connection_type'] != 'rpc':
|
if self.coin_clients[coin_type]['connection_type'] != 'rpc':
|
||||||
|
@ -1771,6 +2113,9 @@ class BasicSwap(BaseApp):
|
||||||
return sum_unspent
|
return sum_unspent
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def checkXmrBidState(self, bid_id, bid, offer):
|
||||||
|
pass
|
||||||
|
|
||||||
def checkBidState(self, bid_id, bid, offer):
|
def checkBidState(self, bid_id, bid, offer):
|
||||||
# assert(self.mxDB.locked())
|
# assert(self.mxDB.locked())
|
||||||
# Return True to remove bid from in-progress list
|
# Return True to remove bid from in-progress list
|
||||||
|
@ -1778,6 +2123,9 @@ class BasicSwap(BaseApp):
|
||||||
state = BidStates(bid.state)
|
state = BidStates(bid.state)
|
||||||
self.log.debug('checkBidState %s %s', bid_id.hex(), str(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
|
save_bid = False
|
||||||
coin_from = Coins(offer.coin_from)
|
coin_from = Coins(offer.coin_from)
|
||||||
coin_to = Coins(offer.coin_to)
|
coin_to = Coins(offer.coin_to)
|
||||||
|
@ -2072,21 +2420,19 @@ class BasicSwap(BaseApp):
|
||||||
options = {'encoding': 'none', 'delete': True}
|
options = {'encoding': 'none', 'delete': True}
|
||||||
del_msg = self.callrpc('smsg', [msg['msgid'], options])
|
del_msg = self.callrpc('smsg', [msg['msgid'], options])
|
||||||
|
|
||||||
# TODO: remove offers from db
|
logging.debug('TODO: Expire records from db')
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
||||||
def checkEvents(self):
|
def checkEvents(self):
|
||||||
self.mxDB.acquire()
|
self.mxDB.acquire()
|
||||||
try:
|
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
|
try:
|
||||||
session = scoped_session(self.session_factory)
|
session = scoped_session(self.session_factory)
|
||||||
|
|
||||||
q = session.query(EventQueue).filter(EventQueue.trigger_at >= now)
|
q = session.query(EventQueue).filter(EventQueue.trigger_at >= now)
|
||||||
for row in q:
|
for row in q:
|
||||||
|
|
||||||
if row.event_type == EventTypes.ACCEPT_BID:
|
if row.event_type == EventTypes.ACCEPT_BID:
|
||||||
self.acceptBid(row.linked_id)
|
self.acceptBid(row.linked_id)
|
||||||
else:
|
else:
|
||||||
|
@ -2100,6 +2446,55 @@ class BasicSwap(BaseApp):
|
||||||
finally:
|
finally:
|
||||||
self.mxDB.release()
|
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):
|
def processOffer(self, msg):
|
||||||
assert(msg['to'] == self.network_addr), 'Offer received on wrong address'
|
assert(msg['to'] == self.network_addr), 'Offer received on wrong address'
|
||||||
|
|
||||||
|
@ -2159,6 +2554,19 @@ class BasicSwap(BaseApp):
|
||||||
was_sent=False)
|
was_sent=False)
|
||||||
offer.setState(OfferStates.OFFER_RECEIVED)
|
offer.setState(OfferStates.OFFER_RECEIVED)
|
||||||
session.add(offer)
|
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())
|
self.log.debug('Received new offer %s', offer_id.hex())
|
||||||
else:
|
else:
|
||||||
existing_offer.setState(OfferStates.OFFER_RECEIVED)
|
existing_offer.setState(OfferStates.OFFER_RECEIVED)
|
||||||
|
@ -2326,6 +2734,179 @@ class BasicSwap(BaseApp):
|
||||||
self.saveBid(bid_id, bid)
|
self.saveBid(bid_id, bid)
|
||||||
self.swaps_in_progress[bid_id] = (bid, offer)
|
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):
|
def processMsg(self, msg):
|
||||||
self.mxDB.acquire()
|
self.mxDB.acquire()
|
||||||
try:
|
try:
|
||||||
|
@ -2338,6 +2919,12 @@ class BasicSwap(BaseApp):
|
||||||
self.processBid(msg)
|
self.processBid(msg)
|
||||||
elif msg_type == MessageTypes.BID_ACCEPT:
|
elif msg_type == MessageTypes.BID_ACCEPT:
|
||||||
self.processBidAccept(msg)
|
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:
|
except Exception as ex:
|
||||||
self.log.error('processMsg %s', str(ex))
|
self.log.error('processMsg %s', str(ex))
|
||||||
|
@ -2373,7 +2960,7 @@ class BasicSwap(BaseApp):
|
||||||
try:
|
try:
|
||||||
# TODO: Wait for blocks / txns, would need to check multiple coins
|
# TODO: Wait for blocks / txns, would need to check multiple coins
|
||||||
now = int(time.time())
|
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 = []
|
to_remove = []
|
||||||
for bid_id, v in self.swaps_in_progress.items():
|
for bid_id, v in self.swaps_in_progress.items():
|
||||||
try:
|
try:
|
||||||
|
@ -2387,21 +2974,25 @@ class BasicSwap(BaseApp):
|
||||||
for bid_id in to_remove:
|
for bid_id in to_remove:
|
||||||
self.log.debug('Removing bid from in-progress: %s', bid_id.hex())
|
self.log.debug('Removing bid from in-progress: %s', bid_id.hex())
|
||||||
del self.swaps_in_progress[bid_id]
|
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():
|
for k, c in self.coin_clients.items():
|
||||||
if len(c['watched_outputs']) > 0:
|
if len(c['watched_outputs']) > 0:
|
||||||
self.checkForSpends(k, c)
|
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.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.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:
|
except Exception as ex:
|
||||||
self.log.error('update %s', str(ex))
|
self.log.error('update %s', str(ex))
|
||||||
|
@ -2542,6 +3133,9 @@ class BasicSwap(BaseApp):
|
||||||
else:
|
else:
|
||||||
q = session.query(Offer).filter(Offer.expire_at > now)
|
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)
|
filter_coin_from = filters.get('coin_from', None)
|
||||||
if filter_coin_from and filter_coin_from > -1:
|
if filter_coin_from and filter_coin_from > -1:
|
||||||
q = q.filter(Offer.coin_from == int(filter_coin_from))
|
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)
|
expire_at = sa.Column(sa.BigInteger)
|
||||||
was_sent = sa.Column(sa.Boolean)
|
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)
|
auto_accept_bids = sa.Column(sa.Boolean)
|
||||||
|
|
||||||
state = sa.Column(sa.Integer)
|
state = sa.Column(sa.Integer)
|
||||||
|
@ -125,10 +128,13 @@ class Bid(Base):
|
||||||
self.participate_tx.state = new_state
|
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()))
|
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())
|
now = int(time.time())
|
||||||
self.state = new_state
|
self.state = new_state
|
||||||
self.state_time = now
|
self.state_time = now
|
||||||
|
|
||||||
|
if state_note is not None:
|
||||||
|
self.state_note = state_note
|
||||||
if self.states is None:
|
if self.states is None:
|
||||||
self.states = struct.pack('<iq', new_state, now)
|
self.states = struct.pack('<iq', new_state, now)
|
||||||
else:
|
else:
|
||||||
|
@ -195,3 +201,75 @@ class EventQueue(Base):
|
||||||
linked_id = sa.Column(sa.LargeBinary)
|
linked_id = sa.Column(sa.LargeBinary)
|
||||||
event_type = sa.Column(sa.Integer)
|
event_type = sa.Column(sa.Integer)
|
||||||
event_data = sa.Column(sa.LargeBinary)
|
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,
|
format_amount,
|
||||||
make_int
|
make_int
|
||||||
)
|
)
|
||||||
|
from coincurve.keys import (
|
||||||
|
PublicKey)
|
||||||
|
from coincurve.dleag import (
|
||||||
|
verify_secp256k1_point)
|
||||||
|
|
||||||
from .ecc_util import (
|
from .ecc_util import (
|
||||||
G, ep,
|
G, ep,
|
||||||
|
@ -126,6 +130,16 @@ class BTCInterface(CoinInterface):
|
||||||
def pubkey(self, key):
|
def pubkey(self, key):
|
||||||
return G * 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):
|
def encodePubkey(self, pk):
|
||||||
return pointToCPK(pk)
|
return pointToCPK(pk)
|
||||||
|
|
||||||
|
@ -192,14 +206,20 @@ class BTCInterface(CoinInterface):
|
||||||
return secret_hash, pk1, pk2, csv_val, pk3, pk4
|
return secret_hash, pk1, pk2, csv_val, pk3, pk4
|
||||||
|
|
||||||
def genScriptLockTxScript(self, sh, Kal, Kaf, lock_blocks, Karl, Karf):
|
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([
|
return CScript([
|
||||||
CScriptOp(OP_IF),
|
CScriptOp(OP_IF),
|
||||||
CScriptOp(OP_SIZE), 32, CScriptOp(OP_EQUALVERIFY),
|
CScriptOp(OP_SIZE), 32, CScriptOp(OP_EQUALVERIFY),
|
||||||
CScriptOp(OP_SHA256), sh, 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),
|
CScriptOp(OP_ELSE),
|
||||||
lock_blocks, CScriptOp(OP_CHECKSEQUENCEVERIFY), CScriptOp(OP_DROP),
|
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)])
|
CScriptOp(OP_ENDIF)])
|
||||||
|
|
||||||
def createScriptLockTx(self, value, sh, Kal, Kaf, lock_blocks, Karl, Karf):
|
def createScriptLockTx(self, value, sh, Kal, Kaf, lock_blocks, Karl, Karf):
|
||||||
|
@ -209,7 +229,7 @@ class BTCInterface(CoinInterface):
|
||||||
tx.nVersion = self.txVersion()
|
tx.nVersion = self.txVersion()
|
||||||
tx.vout.append(self.txoType(value, CScript([OP_0, hashlib.sha256(script).digest()])))
|
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):
|
def extractScriptLockRefundScriptValues(self, script_bytes):
|
||||||
script_len = len(script_bytes)
|
script_len = len(script_bytes)
|
||||||
|
@ -243,15 +263,22 @@ class BTCInterface(CoinInterface):
|
||||||
return pk1, pk2, csv_val, pk3
|
return pk1, pk2, csv_val, pk3
|
||||||
|
|
||||||
def genScriptLockRefundTxScript(self, Karl, Karf, csv_val, Kaf):
|
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([
|
return CScript([
|
||||||
CScriptOp(OP_IF),
|
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),
|
CScriptOp(OP_ELSE),
|
||||||
csv_val, CScriptOp(OP_CHECKSEQUENCEVERIFY), CScriptOp(OP_DROP),
|
csv_val, CScriptOp(OP_CHECKSEQUENCEVERIFY), CScriptOp(OP_DROP),
|
||||||
self.encodePubkey(Kaf), CScriptOp(OP_CHECKSIG),
|
Kaf_enc, CScriptOp(OP_CHECKSIG),
|
||||||
CScriptOp(OP_ENDIF)])
|
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()])
|
output_script = CScript([OP_0, hashlib.sha256(script_lock).digest()])
|
||||||
locked_n = findOutput(tx_lock, output_script)
|
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.',
|
logging.info('createScriptLockRefundTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||||
|
|
||||||
return tx, 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
|
# 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
|
# 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
|
# 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()])
|
output_script = CScript([OP_0, hashlib.sha256(script_lock_refund).digest()])
|
||||||
locked_n = findOutput(tx_lock_refund, output_script)
|
locked_n = findOutput(tx_lock_refund, output_script)
|
||||||
assert_cond(locked_n is not None, 'Output not found in tx')
|
assert_cond(locked_n is not None, 'Output not found in tx')
|
||||||
|
@ -300,7 +329,8 @@ class BTCInterface(CoinInterface):
|
||||||
tx.nVersion = self.txVersion()
|
tx.nVersion = self.txVersion()
|
||||||
tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=0))
|
tx.vin.append(CTxIn(COutPoint(tx_lock_refund_hash_int, locked_n), nSequence=0))
|
||||||
|
|
||||||
pubkeyhash = hash160(self.encodePubkey(Kal))
|
#pubkeyhash = hash160(self.encodePubkey(Kal))
|
||||||
|
pubkeyhash = hash160(Kal)
|
||||||
tx.vout.append(self.txoType(locked_coin, CScript([OP_0, pubkeyhash])))
|
tx.vout.append(self.txoType(locked_coin, CScript([OP_0, pubkeyhash])))
|
||||||
|
|
||||||
witness_bytes = len(script_lock_refund)
|
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.',
|
logging.info('createScriptLockRefundSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||||
|
|
||||||
return tx
|
return tx.serialize()
|
||||||
|
|
||||||
def createScriptLockRefundSpendToFTx(self, tx_lock_refund, script_lock_refund, pkh_dest, tx_fee_rate):
|
def createScriptLockRefundSpendToFTx(self, tx_lock_refund, script_lock_refund, pkh_dest, tx_fee_rate):
|
||||||
# Sends the coinA locked coin to the follower
|
# 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.',
|
logging.info('createScriptLockRefundSpendToFTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||||
|
|
||||||
return tx
|
return tx.serialize()
|
||||||
|
|
||||||
def createScriptLockSpendTx(self, tx_lock, script_lock, pkh_dest, tx_fee_rate):
|
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.',
|
logging.info('createScriptLockSpendTx %s:\n fee_rate, vsize, fee: %ld, %ld, %ld.',
|
||||||
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
i2h(tx.sha256), tx_fee_rate, vsize, pay_fee)
|
||||||
|
|
||||||
return tx
|
return tx.serialize()
|
||||||
|
|
||||||
def verifyLockTx(self, tx, script_out,
|
def verifyLockTx(self, tx, script_out,
|
||||||
swap_value,
|
swap_value,
|
||||||
|
@ -592,11 +622,13 @@ class BTCInterface(CoinInterface):
|
||||||
|
|
||||||
return True
|
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)
|
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
||||||
|
|
||||||
eck = ECKey()
|
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
|
return eck.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
|
||||||
|
|
||||||
|
@ -611,22 +643,25 @@ class BTCInterface(CoinInterface):
|
||||||
def decryptOtVES(self, k, esig):
|
def decryptOtVES(self, k, esig):
|
||||||
return otves.DecSig(k, esig) + b'\x01' # 0x1 is SIGHASH_ALL
|
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)
|
sig_hash = SegwitV0SignatureHash(prevout_script, tx, prevout_n, SIGHASH_ALL, prevout_value)
|
||||||
|
|
||||||
ecK = ECPubKey()
|
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
|
return ecK.verify_ecdsa(sig[: -1], sig_hash) # Pop the hashtype byte
|
||||||
|
|
||||||
def fundTx(self, tx, feerate):
|
def fundTx(self, tx, feerate):
|
||||||
feerate_str = format_amount(feerate, self.exp())
|
feerate_str = format_amount(feerate, self.exp())
|
||||||
rv = self.rpc_callback('fundrawtransaction', [ToHex(tx), {'feeRate': feerate_str}])
|
rv = self.rpc_callback('fundrawtransaction', [tx.hex(), {'feeRate': feerate_str}])
|
||||||
return FromHex(tx, rv['hex'])
|
return bytes.fromhex(rv['hex'])
|
||||||
|
|
||||||
def signTxWithWallet(self, tx):
|
def signTxWithWallet(self, tx):
|
||||||
rv = self.rpc_callback('signrawtransactionwithwallet', [ToHex(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):
|
def publishTx(self, tx):
|
||||||
return self.rpc_callback('sendrawtransaction', [ToHex(tx)])
|
return self.rpc_callback('sendrawtransaction', [ToHex(tx)])
|
||||||
|
@ -640,7 +675,9 @@ class BTCInterface(CoinInterface):
|
||||||
tx.deserialize(BytesIO(tx_bytes))
|
tx.deserialize(BytesIO(tx_bytes))
|
||||||
return tx
|
return tx
|
||||||
|
|
||||||
def getTxHash(self, tx):
|
def getTxHash(self, tx_bytes):
|
||||||
|
tx = CTransaction()
|
||||||
|
tx = FromHex(tx, tx_bytes.hex())
|
||||||
tx.rehash()
|
tx.rehash()
|
||||||
return i2b(tx.sha256)
|
return i2b(tx.sha256)
|
||||||
|
|
||||||
|
@ -680,7 +717,7 @@ class BTCInterface(CoinInterface):
|
||||||
tx.nVersion = self.txVersion()
|
tx.nVersion = self.txVersion()
|
||||||
p2wpkh = self.getPkDest(Kbs)
|
p2wpkh = self.getPkDest(Kbs)
|
||||||
tx.vout.append(self.txoType(output_amount, p2wpkh))
|
tx.vout.append(self.txoType(output_amount, p2wpkh))
|
||||||
return tx
|
return tx.serialize()
|
||||||
|
|
||||||
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate):
|
def publishBLockTx(self, Kbv, Kbs, output_amount, feerate):
|
||||||
b_lock_tx = self.createBLockTx(Kbs, output_amount)
|
b_lock_tx = self.createBLockTx(Kbs, output_amount)
|
||||||
|
|
|
@ -8,11 +8,24 @@
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from .chainparams import CoinInterface
|
import basicswap.contrib.ed25519_fast as edf
|
||||||
from .rpc_xmr import make_xmr_rpc_func, make_xmr_wallet_rpc_func
|
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 (
|
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
|
XMR_COIN = 10 ** 12
|
||||||
|
|
||||||
|
@ -49,6 +62,9 @@ class XMRInterface(CoinInterface):
|
||||||
rv['verificationprogress'] = 0 # TODO
|
rv['verificationprogress'] = 0 # TODO
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
def getChainHeight(self):
|
||||||
|
return self.rpc_cb('get_block_count')['count']
|
||||||
|
|
||||||
def getWalletInfo(self):
|
def getWalletInfo(self):
|
||||||
rv = {}
|
rv = {}
|
||||||
balance_info = self.rpc_wallet_cb('get_balance')
|
balance_info = self.rpc_wallet_cb('get_balance')
|
||||||
|
@ -60,6 +76,10 @@ class XMRInterface(CoinInterface):
|
||||||
logging.debug('TODO - subaddress?')
|
logging.debug('TODO - subaddress?')
|
||||||
return self.rpc_wallet_cb('get_address')['address']
|
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):
|
def getNewSecretKey(self):
|
||||||
return edu.get_secret()
|
return edu.get_secret()
|
||||||
|
|
||||||
|
@ -72,6 +92,26 @@ class XMRInterface(CoinInterface):
|
||||||
def decodePubkey(self, pke):
|
def decodePubkey(self, pke):
|
||||||
return edf.decodepoint(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):
|
def decodeKey(self, k):
|
||||||
i = b2i(k)
|
i = b2i(k)
|
||||||
assert(i < edf.l and i > 8)
|
assert(i < edf.l and i > 8)
|
||||||
|
|
|
@ -26,6 +26,9 @@ message OfferMessage {
|
||||||
string proof_signature = 11;
|
string proof_signature = 11;
|
||||||
bytes pkhash_seller = 12;
|
bytes pkhash_seller = 12;
|
||||||
bytes secret_hash = 13;
|
bytes secret_hash = 13;
|
||||||
|
|
||||||
|
uint64 fee_rate_from = 14;
|
||||||
|
uint64 fee_rate_to = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 2, buyer -> seller */
|
/* 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 */
|
bytes kbvf = 6;
|
||||||
string proof_address = 10;
|
bytes kbsf_dleag = 7;
|
||||||
string proof_signature = 11;
|
|
||||||
bytes pkhash_seller = 12;
|
|
||||||
bytes secret_hash = 13;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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',
|
syntax='proto3',
|
||||||
serialized_options=None,
|
serialized_options=None,
|
||||||
create_key=_descriptor._internal_create_key,
|
create_key=_descriptor._internal_create_key,
|
||||||
serialized_pb=b'\n\x0emessages.proto\x12\tbasicswap\"\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,
|
containing_type=None,
|
||||||
serialized_options=None,
|
serialized_options=None,
|
||||||
serialized_start=345,
|
serialized_start=389,
|
||||||
serialized_end=458,
|
serialized_end=502,
|
||||||
)
|
)
|
||||||
_sym_db.RegisterEnumDescriptor(_OFFERMESSAGE_LOCKTYPE)
|
_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(
|
_OFFERMESSAGE = _descriptor.Descriptor(
|
||||||
name='OfferMessage',
|
name='OfferMessage',
|
||||||
|
@ -204,6 +164,20 @@ _OFFERMESSAGE = _descriptor.Descriptor(
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='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=[
|
extensions=[
|
||||||
],
|
],
|
||||||
|
@ -218,7 +192,7 @@ _OFFERMESSAGE = _descriptor.Descriptor(
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=30,
|
serialized_start=30,
|
||||||
serialized_end=458,
|
serialized_end=502,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -284,8 +258,8 @@ _BIDMESSAGE = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=461,
|
serialized_start=505,
|
||||||
serialized_end=601,
|
serialized_end=645,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,106 +304,64 @@ _BIDACCEPTMESSAGE = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=603,
|
serialized_start=647,
|
||||||
serialized_end=689,
|
serialized_end=733,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_XMROFFERMESSAGE = _descriptor.Descriptor(
|
_XMRBIDMESSAGE = _descriptor.Descriptor(
|
||||||
name='XmrOfferMessage',
|
name='XmrBidMessage',
|
||||||
full_name='basicswap.XmrOfferMessage',
|
full_name='basicswap.XmrBidMessage',
|
||||||
filename=None,
|
filename=None,
|
||||||
file=DESCRIPTOR,
|
file=DESCRIPTOR,
|
||||||
containing_type=None,
|
containing_type=None,
|
||||||
create_key=_descriptor._internal_create_key,
|
create_key=_descriptor._internal_create_key,
|
||||||
fields=[
|
fields=[
|
||||||
_descriptor.FieldDescriptor(
|
_descriptor.FieldDescriptor(
|
||||||
name='coin_from', full_name='basicswap.XmrOfferMessage.coin_from', index=0,
|
name='offer_msg_id', full_name='basicswap.XmrBidMessage.offer_msg_id', index=0,
|
||||||
number=1, type=13, cpp_type=3, label=1,
|
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,
|
has_default_value=False, default_value=0,
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
_descriptor.FieldDescriptor(
|
_descriptor.FieldDescriptor(
|
||||||
name='coin_to', full_name='basicswap.XmrOfferMessage.coin_to', index=1,
|
name='amount', full_name='basicswap.XmrBidMessage.amount', index=2,
|
||||||
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,
|
|
||||||
number=3, type=4, cpp_type=4, label=1,
|
number=3, type=4, cpp_type=4, label=1,
|
||||||
has_default_value=False, default_value=0,
|
has_default_value=False, default_value=0,
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
_descriptor.FieldDescriptor(
|
_descriptor.FieldDescriptor(
|
||||||
name='rate', full_name='basicswap.XmrOfferMessage.rate', index=3,
|
name='pkaf', full_name='basicswap.XmrBidMessage.pkaf', index=3,
|
||||||
number=4, type=4, cpp_type=4, label=1,
|
number=4, type=12, cpp_type=9, 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,
|
|
||||||
has_default_value=False, default_value=b"",
|
has_default_value=False, default_value=b"",
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
|
||||||
_descriptor.FieldDescriptor(
|
_descriptor.FieldDescriptor(
|
||||||
name='secret_hash', full_name='basicswap.XmrOfferMessage.secret_hash', index=12,
|
name='pkarf', full_name='basicswap.XmrBidMessage.pkarf', index=4,
|
||||||
number=13, type=12, cpp_type=9, label=1,
|
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"",
|
has_default_value=False, default_value=b"",
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
|
@ -439,7 +371,6 @@ _XMROFFERMESSAGE = _descriptor.Descriptor(
|
||||||
],
|
],
|
||||||
nested_types=[],
|
nested_types=[],
|
||||||
enum_types=[
|
enum_types=[
|
||||||
_XMROFFERMESSAGE_LOCKTYPE,
|
|
||||||
],
|
],
|
||||||
serialized_options=None,
|
serialized_options=None,
|
||||||
is_extendable=False,
|
is_extendable=False,
|
||||||
|
@ -447,18 +378,180 @@ _XMROFFERMESSAGE = _descriptor.Descriptor(
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
oneofs=[
|
oneofs=[
|
||||||
],
|
],
|
||||||
serialized_start=692,
|
serialized_start=736,
|
||||||
serialized_end=1126,
|
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.fields_by_name['lock_type'].enum_type = _OFFERMESSAGE_LOCKTYPE
|
||||||
_OFFERMESSAGE_LOCKTYPE.containing_type = _OFFERMESSAGE
|
_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['OfferMessage'] = _OFFERMESSAGE
|
||||||
DESCRIPTOR.message_types_by_name['BidMessage'] = _BIDMESSAGE
|
DESCRIPTOR.message_types_by_name['BidMessage'] = _BIDMESSAGE
|
||||||
DESCRIPTOR.message_types_by_name['BidAcceptMessage'] = _BIDACCEPTMESSAGE
|
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)
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), {
|
OfferMessage = _reflection.GeneratedProtocolMessageType('OfferMessage', (_message.Message,), {
|
||||||
|
@ -482,12 +575,26 @@ BidAcceptMessage = _reflection.GeneratedProtocolMessageType('BidAcceptMessage',
|
||||||
})
|
})
|
||||||
_sym_db.RegisterMessage(BidAcceptMessage)
|
_sym_db.RegisterMessage(BidAcceptMessage)
|
||||||
|
|
||||||
XmrOfferMessage = _reflection.GeneratedProtocolMessageType('XmrOfferMessage', (_message.Message,), {
|
XmrBidMessage = _reflection.GeneratedProtocolMessageType('XmrBidMessage', (_message.Message,), {
|
||||||
'DESCRIPTOR' : _XMROFFERMESSAGE,
|
'DESCRIPTOR' : _XMRBIDMESSAGE,
|
||||||
'__module__' : 'messages_pb2'
|
'__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)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import decimal
|
||||||
import hashlib
|
import hashlib
|
||||||
from .contrib.segwit_addr import bech32_decode, convertbits, bech32_encode
|
from .contrib.segwit_addr import bech32_decode, convertbits, bech32_encode
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,26 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright (c) 2019 tecnovert
|
# Copyright (c) 2019-2020 tecnovert
|
||||||
# Distributed under the MIT software license, see the accompanying
|
# Distributed under the MIT software license, see the accompanying
|
||||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
import unittest
|
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 (
|
from basicswap.util import (
|
||||||
SerialiseNum,
|
SerialiseNum,
|
||||||
DeserialiseNum,
|
DeserialiseNum,
|
||||||
make_int,
|
make_int,
|
||||||
format8,
|
format8,
|
||||||
|
format_amount,
|
||||||
|
validate_amount,
|
||||||
)
|
)
|
||||||
from basicswap.basicswap import (
|
from basicswap.basicswap import (
|
||||||
Coins,
|
Coins,
|
||||||
|
@ -134,6 +144,14 @@ class Test(unittest.TestCase):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
assert('Too many decimal places' in str(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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -67,6 +67,8 @@ from tests.basicswap.common import (
|
||||||
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
|
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
|
||||||
from bin.basicswap_run import startDaemon
|
from bin.basicswap_run import startDaemon
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
NUM_NODES = 3
|
NUM_NODES = 3
|
||||||
|
@ -239,6 +241,7 @@ def prepare_swapclient_dir(datadir, node_id, network_key, network_pubkey):
|
||||||
'check_watched_seconds': 4,
|
'check_watched_seconds': 4,
|
||||||
'check_expired_seconds': 60,
|
'check_expired_seconds': 60,
|
||||||
'check_events_seconds': 1,
|
'check_events_seconds': 1,
|
||||||
|
'check_xmr_swaps_seconds': 1,
|
||||||
'min_delay_auto_accept': 1,
|
'min_delay_auto_accept': 1,
|
||||||
'max_delay_auto_accept': 5
|
'max_delay_auto_accept': 5
|
||||||
}
|
}
|
||||||
|
@ -310,7 +313,7 @@ def run_loop(cls):
|
||||||
btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr))
|
btcRpc('generatetoaddress 1 {}'.format(cls.btc_addr))
|
||||||
|
|
||||||
if cls.xmr_addr is not None:
|
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)
|
time.sleep(1.0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -335,6 +338,7 @@ class Test(unittest.TestCase):
|
||||||
logger.propagate = False
|
logger.propagate = False
|
||||||
logger.handlers = []
|
logger.handlers = []
|
||||||
logger.setLevel(logging.INFO) # DEBUG shows many messages from requests.post
|
logger.setLevel(logging.INFO) # DEBUG shows many messages from requests.post
|
||||||
|
#logger.setLevel(logging.DEBUG)
|
||||||
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
formatter = logging.Formatter('%(asctime)s %(levelname)s : %(message)s')
|
||||||
stream_stdout = logging.StreamHandler()
|
stream_stdout = logging.StreamHandler()
|
||||||
stream_stdout.setFormatter(formatter)
|
stream_stdout.setFormatter(formatter)
|
||||||
|
@ -417,7 +421,7 @@ class Test(unittest.TestCase):
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
cls.btc_addr = callnoderpc(0, 'getnewaddress', ['mining_addr', 'bech32'], base_rpc_port=BTC_BASE_RPC_PORT)
|
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
|
num_blocks = 500
|
||||||
logging.info('Mining %d bitcoin blocks to %s', num_blocks, cls.btc_addr)
|
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))
|
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)
|
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})
|
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 + 0, 'get_block_count')
|
rv = callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')
|
||||||
logging.info('XMR blocks: %d', rv['count'])
|
logging.info('XMR blocks: %d', rv['count'])
|
||||||
|
|
||||||
logging.info('Starting update thread.')
|
logging.info('Starting update thread.')
|
||||||
|
@ -509,21 +513,49 @@ class Test(unittest.TestCase):
|
||||||
return
|
return
|
||||||
raise ValueError('wait_for_offer timed out.')
|
raise ValueError('wait_for_offer timed out.')
|
||||||
|
|
||||||
|
def wait_for_bid(self, swap_client, bid_id, state=None, sent=False):
|
||||||
|
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):
|
def test_01_part_xmr(self):
|
||||||
logging.info('---------- Test PART to XMR')
|
logging.info('---------- Test PART to XMR')
|
||||||
swap_clients = self.swap_clients
|
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))]['balance'], scale=12) > 0)
|
||||||
assert(make_int(js_0[str(int(Coins.XMR))]['unconfirmed'], 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)
|
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)
|
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)
|
assert(len(offers) == 1)
|
||||||
for offer in offers:
|
offer = offers[0]
|
||||||
print('offer', offer)
|
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__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in a new issue