Send MSG2F
This commit is contained in:
		
							parent
							
								
									acae8b4de3
								
							
						
					
					
						commit
						009729aa96
					
				@ -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,13 +756,8 @@ 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, )
 | 
					            msg_buf = OfferMessage()
 | 
				
			||||||
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                msg_buf = OfferMessage()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            msg_buf.coin_from = int(coin_from)
 | 
					            msg_buf.coin_from = int(coin_from)
 | 
				
			||||||
            msg_buf.coin_to = int(coin_to)
 | 
					            msg_buf.coin_to = int(coin_to)
 | 
				
			||||||
@ -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()
 | 
				
			||||||
 | 
					        now = int(time.time())
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            now = int(time.time())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            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 New Issue
	
	Block a user