From 270bd7000f6068952c58c953fe14928fd60252d7 Mon Sep 17 00:00:00 2001 From: James Prestwich Date: Mon, 4 Sep 2017 17:03:17 -0600 Subject: [PATCH] refactor protocol, put test stubs in place, linting, prep for cli tests --- xcat/cli.py | 60 ++++-- xcat/db.py | 15 +- xcat/protocol.py | 425 +++++++++++++++++++++-------------------- xcat/tests/test_cli.py | 79 ++++---- xcat/tests/utils.py | 28 ++- 5 files changed, 337 insertions(+), 270 deletions(-) diff --git a/xcat/cli.py b/xcat/cli.py index 5b41fc1..aa10367 100644 --- a/xcat/cli.py +++ b/xcat/cli.py @@ -1,29 +1,32 @@ -import argparse, textwrap -from xcat.utils import * +import argparse +import textwrap +import subprocess import xcat.db as db import xcat.userInput as userInput +from xcat.protocol import Protocol from xcat.trades import * -from xcat.protocol import * -import subprocess +from xcat.utils import * + def save_state(trade, tradeid): save(trade) db.create(trade, tradeid) + def checkSellStatus(tradeid): trade = db.get(tradeid) status = seller_check_status(trade) print("Trade status: {0}\n".format(status)) if status == 'init': userInput.authorize_fund_sell(trade) - fund_tx = fund_sell_contract(trade) + fund_tx = protocol.fund_sell_contract(trade) print("Sent fund_tx", fund_tx) trade.sell.fund_tx = fund_tx save_state(trade, tradeid) elif status == 'buyerFunded': secret = db.get_secret(tradeid) print("Retrieved secret to redeem funds for {0}: {1}".format(tradeid, secret)) - txs = seller_redeem_p2sh(trade, secret) + txs = protocol.seller_redeem_p2sh(trade, secret) if 'redeem_tx' in txs: trade.buy.redeem_tx = txs['redeem_tx'] print("Redeem tx: ", txs['redeem_tx']) @@ -38,9 +41,10 @@ def checkSellStatus(tradeid): elif status == 'sellerRedeemed': print("You have already redeemed the p2sh on the second chain of this trade.") + def buyer_check_status(trade): - sellState = check_fund_status(trade.sell.currency, trade.sell.p2sh) - buyState = check_fund_status(trade.buy.currency, trade.buy.p2sh) + sellState = protocol.check_fund_status(trade.sell.currency, trade.sell.p2sh) + buyState = protocol.check_fund_status(trade.buy.currency, trade.buy.p2sh) if sellState == 'funded' and buyState == 'empty': return 'sellerFunded' # step1 # TODO: Find funding txid. How does buyer get seller redeemed tx? @@ -54,9 +58,10 @@ def buyer_check_status(trade): else: return 'init' + def seller_check_status(trade): - sellState = check_fund_status(trade.sell.currency, trade.sell.p2sh) - buyState = check_fund_status(trade.buy.currency, trade.buy.p2sh) + sellState = protocol.check_fund_status(trade.sell.currency, trade.sell.p2sh) + buyState = protocol.check_fund_status(trade.buy.currency, trade.buy.p2sh) if sellState == 'funded' and buyState == 'empty': return 'sellerFunded' # step1 elif sellState == 'funded' and hasattr(trade.buy, 'redeem_tx'): @@ -70,6 +75,7 @@ def seller_check_status(trade): else: return 'init' # step0 + def checkBuyStatus(tradeid): trade = db.get(tradeid) status = buyer_check_status(trade) @@ -83,15 +89,17 @@ def checkBuyStatus(tradeid): input("Type 'enter' to allow this program to send funds on your behalf.") print("Trade commitment", trade.commitment) # if verify_p2sh(trade): - fund_tx = fund_contract(trade.buy) + fund_tx = protocol.fund_contract(trade.buy) print("\nYou sent this funding tx: ", fund_tx) trade.buy.fund_tx = fund_tx save_state(trade, tradeid) elif status == 'sellerRedeemed': - secret = find_secret_from_fundtx(trade.buy.currency, trade.buy.p2sh, trade.buy.fund_tx) + secret = protocol.find_secret_from_fundtx(trade.buy.currency, + trade.buy.p2sh, + trade.buy.fund_tx) if secret != None: print("Found secret on blockchain in seller's redeem tx: ", secret) - txs = redeem_p2sh(trade.sell, secret) + txs = protocol.redeem_p2sh(trade.sell, secret) if 'redeem_tx' in txs: trade.sell.redeem_tx = txs['redeem_tx'] print("Redeem txid: ", trade.sell.redeem_tx) @@ -103,14 +111,16 @@ def checkBuyStatus(tradeid): else: print("Secret not found in redeemtx") + # Import a trade in hex, and save to db def importtrade(tradeid, hexstr=''): trade = x2s(hexstr) trade = db.instantiate(trade) - import_addrs(trade) + protocol.import_addrs(trade) print(trade.toJSON()) save_state(trade, tradeid) + def wormhole_importtrade(): res = subprocess.call('wormhole receive', shell=True) if res == 0: @@ -123,9 +133,10 @@ def wormhole_importtrade(): else: print("Importing trade using magic-wormhole failed.") + # Export a trade by its tradeid def exporttrade(tradeid, wormhole=False): - trade = db.get(tradeid) + trade = db.get(tradeid) hexstr = s2x(trade.toJSON()) if wormhole: tradefile = os.path.join(ROOT_DIR, '.tmp/{0}'.format(tradeid)) @@ -138,20 +149,24 @@ def exporttrade(tradeid, wormhole=False): print(hexstr) return hexstr + def findtrade(tradeid): trade = db.get(tradeid) print(trade.toJSON()) return trade + def find_role(contract): # When regtest created both addrs on same machine, role is both. - if is_myaddr(contract.initiator) and is_myaddr(contract.fulfiller): - return 'test' - elif is_myaddr(contract.initiator): - return 'initiator' + if protocol.is_myaddr(contract.initiator): + if protocol.is_myaddr(contract.fulfiller): + return 'test' + else: + return 'initiator' else: return 'fulfiller' + def checktrade(tradeid): print("In checktrade") trade = db.get(tradeid) @@ -170,22 +185,25 @@ def checktrade(tradeid): role = 'buyer' checkBuyStatus(tradeid) + def newtrade(tradeid, **kwargs): print("Creating new XCAT trade...") erase_trade() - tradeid, trade= initialize_trade(tradeid, conf=kwargs['conf']) + tradeid, trade = protocol.initialize_trade(tradeid, conf=kwargs['conf']) print("Trade", trade) - trade = seller_init(tradeid, trade) + trade = protocol.seller_init(tradeid, trade) print("\nUse 'xcat exporttrade [tradeid]' to export the trade and sent to the buyer.\n") save_state(trade, tradeid) return trade + def listtrades(): print("Trades") trades = db.dump() for trade in trades: print("{0}: {1}".format(trade[0], trade[1])) + def main(): parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description=textwrap.dedent('''\ diff --git a/xcat/db.py b/xcat/db.py index c976f45..42fc2d6 100644 --- a/xcat/db.py +++ b/xcat/db.py @@ -1,10 +1,10 @@ import plyvel -from xcat.utils import * -import binascii -import sys import json -import ast +# import binascii +# import sys +# import ast from xcat.trades import * +from xcat.utils import * db = plyvel.DB('/tmp/xcatDB', create_if_missing=True) preimageDB = plyvel.DB('/tmp/preimageDB', create_if_missing=True) @@ -13,6 +13,7 @@ preimageDB = plyvel.DB('/tmp/preimageDB', create_if_missing=True) ######## Trades stored by tradeid ########### ############################################# + # Takes dict or obj, saves json str as bytes def create(trade, tradeid): if type(trade) == dict: @@ -21,6 +22,7 @@ def create(trade, tradeid): trade = trade.toJSON() db.put(b(tradeid), b(trade)) + # Uses the funding txid as the key to save trade def createByFundtx(trade): trade = trade.toJSON() @@ -29,12 +31,14 @@ def createByFundtx(trade): txid = jt['sell']['fund_tx'] db.put(b(txid), b(trade)) + def get(tradeid): rawtrade = db.get(b(tradeid)) tradestr = str(rawtrade, 'utf-8') trade = instantiate(tradestr) return trade + def instantiate(trade): if type(trade) == str: tradestr = json.loads(trade) @@ -45,10 +49,12 @@ def instantiate(trade): ###### Preimages stored by tradeid ########## ############################################# + # Stores secret locally in key/value store by tradeid def save_secret(tradeid, secret): res = preimageDB.put(b(tradeid), b(secret)) + def get_secret(tradeid): secret = preimageDB.get(b(tradeid)) secret = str(secret, 'utf-8') @@ -67,6 +73,7 @@ def dump(): results.append((str(k, 'utf-8'), j)) return results + def print_entries(): it = db.iterator() with db.iterator() as it: diff --git a/xcat/protocol.py b/xcat/protocol.py index 27f8721..f8f10c8 100644 --- a/xcat/protocol.py +++ b/xcat/protocol.py @@ -1,224 +1,245 @@ -import json -import os, sys -from pprint import pprint -from xcat.utils import * -from xcat.trades import Contract, Trade import xcat.userInput as userInput import xcat.db as db -from xcat.xcatconf import * +import xcat.utils as utils +from xcat.xcatconf import ADDRS +from xcat.trades import Contract, Trade from xcat.bitcoinRPC import bitcoinProxy from xcat.zcashRPC import zcashProxy -bitcoinRPC = bitcoinProxy() -zcashRPC = zcashProxy() -def is_myaddr(address): - if address[:1] == 'm': - status = bitcoinRPC.validateaddress(address) - else: - status = zcashRPC.validateaddress(address) - status = status['ismine'] - # print("Address {0} is mine: {1}".format(address, status)) - return status +class Protocol(): -def find_secret_from_fundtx(currency, p2sh, fundtx): - if currency == 'bitcoin': - secret = bitcoinRPC.find_secret(p2sh, fundtx) - else: - secret = zcashRPC.find_secret(p2sh, fundtx) - return secret + def __init__(self): + self.bitcoinRPC = bitcoinProxy() + self.zcashRPC = zcashProxy() -def import_addrs(trade): - check_fund_status(trade.sell.currency, trade.sell.p2sh) - check_fund_status(trade.buy.currency, trade.buy.p2sh) - -def check_p2sh(currency, address): - if currency == 'bitcoin': - print("Checking funds in Bitcoin p2sh") - return bitcoinRPC.check_funds(address) - else: - print("Checking funds in Zcash p2sh") - return zcashRPC.check_funds(address) - -def check_fund_status(currency, address): - if currency == 'bitcoin': - print("Checking funds in Bitcoin p2sh") - return bitcoinRPC.get_fund_status(address) - else: - print("Checking funds in Zcash p2sh") - return zcashRPC.get_fund_status(address) - -# TODO: function to calculate appropriate locktimes between chains -# def verify_p2sh(trade): - # htlc = create_htlc(trade.buy.currency, trade.buy.fulfiller, trade.buy.initiator, trade.commitment, trade.buy.locktime) - # buyer_p2sh = htlc['p2sh'] - # print("Buyer p2sh:", buyer_p2sh) - # If the two p2sh match... - # if buyer_p2sh == trade.buy.p2sh: - # else: - # print("Compiled p2sh for htlc does not match what seller sent.") - -def create_htlc(currency, funder, redeemer, commitment, locktime): - if currency == 'bitcoin': - sell_p2sh = bitcoinRPC.hashtimelockcontract(funder, redeemer, commitment, locktime) - else: - sell_p2sh = zcashRPC.hashtimelockcontract(funder, redeemer, commitment, locktime) - return sell_p2sh - -def fund_htlc(currency, p2sh, amount): - if currency == 'bitcoin': - txid = bitcoinRPC.fund_htlc(p2sh, amount) - else: - txid = zcashRPC.fund_htlc(p2sh, amount) - return txid - -def fund_contract(contract): - txid = fund_htlc(contract.currency, contract.p2sh, contract.amount) - return txid - -def fund_sell_contract(trade): - sell = trade.sell - txid = fund_htlc(sell.currency, sell.p2sh, sell.amount) - setattr(trade.sell, 'fund_tx', txid) - save(trade) - return txid - -def create_sell_p2sh(trade, commitment, locktime): - # CREATE SELL CONTRACT - sell = trade.sell - contract = create_htlc(sell.currency, sell.initiator, sell.fulfiller, commitment, locktime) - print("sell contract", contract) - setattr(trade.sell, 'p2sh', contract['p2sh']) - setattr(trade.sell, 'redeemScript', contract['redeemScript']) - setattr(trade.sell, 'redeemblocknum', contract['redeemblocknum']) - setattr(trade.buy, 'locktime', contract['locktime']) - save(trade) - -def create_buy_p2sh(trade, commitment, locktime): - ## CREATE BUY CONTRACT - buy = trade.buy - print("\nNow creating buy contract on the {0} blockchain where you will wait for the buyer to send funds...".format(buy.currency)) - buy_contract = create_htlc(buy.currency, buy.fulfiller, buy.initiator, commitment, locktime) - print("Buy contract", buy_contract) - - setattr(trade.buy, 'p2sh', buy_contract['p2sh']) - setattr(trade.buy, 'redeemScript', buy_contract['redeemScript']) - setattr(trade.buy, 'redeemblocknum', buy_contract['redeemblocknum']) - setattr(trade.buy, 'locktime', buy_contract['locktime']) - print("\nNow contact the buyer and tell them to send funds to this p2sh: {0}\n".format(trade.buy.p2sh)) - - save(trade) - -def redeem_p2sh(contract, secret): - currency = contract.currency - if currency == 'bitcoin': - res = bitcoinRPC.redeem_contract(contract, secret) - else: - res = zcashRPC.redeem_contract(contract, secret) - return res - -def parse_secret(chain, txid): - if chain == 'bitcoin': - secret = bitcoinRPC.parse_secret(txid) - else: - secret = zcashRPC.parse_secret(txid) - return secret - -#### Main functions determining user flow from command line -def buyer_redeem(trade): - userInput.authorize_buyer_redeem(trade) - if trade.sell.get_status() == 'redeemed': - print("You already redeemed the funds and acquired {0} {1}".format(trade.sell.amount, trade.sell.currency)) - exit() - else: - # Buyer redeems seller's funded tx - p2sh = trade.sell.p2sh - currency = trade.sell.currency - # Buy contract is where seller disclosed secret in redeeming - if trade.buy.currency == 'bitcoin': - secret = bitcoinRPC.parse_secret(trade.buy.redeem_tx) + def is_myaddr(self, address): + if address[:1] == 'm': + status = self.bitcoinRPC.validateaddress(address) else: - secret = zcashRPC.parse_secret(trade.buy.redeem_tx) - print("Found secret in seller's redeem tx", secret) - redeem_tx = redeem_p2sh(trade.sell, secret) - setattr(trade.sell, 'redeem_tx', redeem_tx) - save(trade) - exit() + status = self.zcashRPC.validateaddress(address) + status = status['ismine'] + # print("Address {0} is mine: {1}".format(address, status)) + return status -def seller_redeem_p2sh(trade, secret): - buy = trade.buy - userInput.authorize_seller_redeem(buy) + def find_secret_from_fundtx(self, currency, p2sh, fundtx): + if currency == 'bitcoin': + secret = self.bitcoinRPC.find_secret(p2sh, fundtx) + else: + secret = self.zcashRPC.find_secret(p2sh, fundtx) + return secret - if trade.sell.get_status() == 'redeemed': - print("You already redeemed the funds and acquired {0} {1}".format(buy.amount, buy.currency)) + def import_addrs(self, trade): + self.check_fund_status(trade.sell.currency, trade.sell.p2sh) + self.check_fund_status(trade.buy.currency, trade.buy.p2sh) + + def check_p2sh(self, currency, address): + if currency == 'bitcoin': + print("Checking funds in Bitcoin p2sh") + return self.bitcoinRPC.check_funds(address) + else: + print("Checking funds in Zcash p2sh") + return self.zcashRPC.check_funds(address) + + def check_fund_status(self, currency, address): + if currency == 'bitcoin': + print("Checking funds in Bitcoin p2sh") + return self.bitcoinRPC.get_fund_status(address) + else: + print("Checking funds in Zcash p2sh") + return self.zcashRPC.get_fund_status(address) + + # TODO: function to calculate appropriate locktimes between chains + # def verify_p2sh(trade): + # htlc = self.create_htlc( + # trade.buy.currency, trade.buy.fulfiller, + # trade.buy.initiator, trade.commitment, + # trade.buy.locktime) + # buyer_p2sh = htlc['p2sh'] + # print("Buyer p2sh:", buyer_p2sh) + # If the two p2sh match... + # if buyer_p2sh == trade.buy.p2sh: + # else: + # print("Compiled p2sh for htlc does not match what seller sent.") + + def create_htlc(self, currency, funder, redeemer, commitment, locktime): + if currency == 'bitcoin': + sell_p2sh = self.bitcoinRPC.hashtimelockcontract( + funder, redeemer, commitment, locktime) + else: + sell_p2sh = self.zcashRPC.hashtimelockcontract( + funder, redeemer, commitment, locktime) + return sell_p2sh + + def fund_htlc(self, currency, p2sh, amount): + if currency == 'bitcoin': + txid = self.bitcoinRPC.fund_htlc(p2sh, amount) + else: + txid = self.zcashRPC.fund_htlc(p2sh, amount) + return txid + + def fund_contract(self, contract): + txid = self.fund_htlc( + contract.currency, contract.p2sh, contract.amount) + return txid + + def fund_sell_contract(self, trade): + sell = trade.sell + txid = self.fund_htlc(sell.currency, sell.p2sh, sell.amount) + setattr(trade.sell, 'fund_tx', txid) + utils.save(trade) + return txid + + def create_sell_p2sh(self, trade, commitment, locktime): + # CREATE SELL CONTRACT + sell = trade.sell + contract = self.create_htlc(sell.currency, sell.initiator, + sell.fulfiller, commitment, locktime) + print("sell contract", contract) + setattr(trade.sell, 'p2sh', contract['p2sh']) + setattr(trade.sell, 'redeemScript', contract['redeemScript']) + setattr(trade.sell, 'redeemblocknum', contract['redeemblocknum']) + setattr(trade.buy, 'locktime', contract['locktime']) + utils.save(trade) + + def create_buy_p2sh(self, trade, commitment, locktime): + # CREATE BUY CONTRACT + buy = trade.buy + print("\nNow creating buy contract on the {0} blockchain where you " + "will wait for the buyer to send funds...".format(buy.currency)) + buy_contract = self.create_htlc( + buy.currency, buy.fulfiller, buy.initiator, commitment, locktime) + print("Buy contract", buy_contract) + + setattr(trade.buy, 'p2sh', buy_contract['p2sh']) + setattr(trade.buy, 'redeemScript', buy_contract['redeemScript']) + setattr(trade.buy, 'redeemblocknum', buy_contract['redeemblocknum']) + setattr(trade.buy, 'locktime', buy_contract['locktime']) + print("\nNow contact the buyer and tell them to send funds to this " + "p2sh: {0}\n".format(trade.buy.p2sh)) + + utils.save(trade) + + def redeem_p2sh(self, contract, secret): + currency = contract.currency + if currency == 'bitcoin': + res = self.bitcoinRPC.redeem_contract(contract, secret) + else: + res = self.zcashRPC.redeem_contract(contract, secret) + return res + + def parse_secret(self, chain, txid): + if chain == 'bitcoin': + secret = self.bitcoinRPC.parse_secret(txid) + else: + secret = self.zcashRPC.parse_secret(txid) + return secret + + # Main functions determining user flow from command line + def buyer_redeem(self, trade): + userInput.authorize_buyer_redeem(trade) + if trade.sell.get_status() == 'redeemed': + print("You already redeemed the funds and acquired " + "{0} {1}".format(trade.sell.amount, trade.sell.currency)) + exit() + else: + # Buyer redeems seller's funded tx + # p2sh = trade.sell.p2sh + # currency = trade.sell.currency + # Buy contract is where seller disclosed secret in redeeming + if trade.buy.currency == 'bitcoin': + secret = self.bitcoinRPC.parse_secret(trade.buy.redeem_tx) + else: + secret = self.zcashRPC.parse_secret(trade.buy.redeem_tx) + print("Found secret in seller's redeem tx", secret) + redeem_tx = self.redeem_p2sh(trade.sell, secret) + setattr(trade.sell, 'redeem_tx', redeem_tx) + utils.save(trade) exit() - else: - # Seller redeems buyer's funded tx (contract in p2sh) - txs = redeem_p2sh(trade.buy, secret) - print("You have redeemed {0} {1}!".format(buy.amount, buy.currency)) - return txs -def buyer_fulfill(trade): - buy = trade.buy - sell = trade.sell - buy_p2sh_balance = check_p2sh(buy.currency, buy.p2sh) - sell_p2sh_balance = check_p2sh(sell.currency, sell.p2sh) + def seller_redeem_p2sh(self, trade, secret): + buy = trade.buy + userInput.authorize_seller_redeem(buy) - if buy_p2sh_balance == 0: - userInput.authorize_buyer_fulfill(sell_p2sh_balance, sell.currency, buy_p2sh_balance, buy.currency) - print("Buy amt:", buy.amount) - txid = fund_buy_contract(trade) - print("Fund tx txid:", txid) - else: - print("It looks like you've already funded the contract to buy {1}, the amount in escrow in the p2sh is {0}.".format(buy_p2sh_balance, buy.currency)) - print("Please wait for the seller to remove your funds from escrow to complete the trade.") - print_trade('buyer') + if trade.sell.get_status() == 'redeemed': + print("You already redeemed the funds and acquired " + "{0} {1}".format(buy.amount, buy.currency)) + exit() + else: + # Seller redeems buyer's funded tx (contract in p2sh) + txs = self.redeem_p2sh(trade.buy, secret) + print("You have redeemed " + "{0} {1}!".format(buy.amount, buy.currency)) + return txs -def initialize_trade(tradeid, **kwargs): - trade = Trade() - conf = kwargs['conf'] - if conf == 'cli': - init_addrs = userInput.get_initiator_addresses() - fulfill_addrs = userInput.get_fulfiller_addresses() - amounts = userInput.get_trade_amounts() - print("AMOUNTS", amounts) - else: - init_addrs = ADDRS[conf]['initiator'] - fulfill_addrs = ADDRS[conf]['fulfiller'] - amounts = ADDRS[conf]['amounts'] + def buyer_fulfill(self, trade): + buy = trade.buy + sell = trade.sell + buy_p2sh_balance = self.check_p2sh(buy.currency, buy.p2sh) + sell_p2sh_balance = self.check_p2sh(sell.currency, sell.p2sh) - sell = amounts['sell'] - buy = amounts['buy'] - sell_currency = sell['currency'] - buy_currency = buy['currency'] - sell['initiator'] = init_addrs[sell_currency] - buy['initiator'] = init_addrs[buy_currency] - sell['fulfiller'] = fulfill_addrs[sell_currency] - buy['fulfiller'] = fulfill_addrs[buy_currency] + if buy_p2sh_balance == 0: + userInput.authorize_buyer_fulfill( + sell_p2sh_balance, + sell.currency, + buy_p2sh_balance, + buy.currency) + print("Buy amt:", buy.amount) + txid = fund_buy_contract(trade) + print("Fund tx txid:", txid) + else: + print("It looks like you've already funded the contract to buy " + "{1}, the amount in escrow in the p2sh is " + "{0}.".format(buy_p2sh_balance, buy.currency)) + print("Please wait for the seller to remove your funds from " + "escrow to complete the trade.") + print_trade('buyer') - # initializing contract classes with addresses, currencies, and amounts - trade.sell = Contract(sell) - trade.buy = Contract(buy) - print(trade.sell.__dict__) - print(trade.buy.__dict__) - return tradeid, trade + def initialize_trade(self, tradeid, **kwargs): + trade = Trade() + conf = kwargs['conf'] + if conf == 'cli': + init_addrs = userInput.get_initiator_addresses() + fulfill_addrs = userInput.get_fulfiller_addresses() + amounts = userInput.get_trade_amounts() + print("AMOUNTS", amounts) + else: + init_addrs = ADDRS[conf]['initiator'] + fulfill_addrs = ADDRS[conf]['fulfiller'] + amounts = ADDRS[conf]['amounts'] + sell = amounts['sell'] + buy = amounts['buy'] + sell_currency = sell['currency'] + buy_currency = buy['currency'] + sell['initiator'] = init_addrs[sell_currency] + buy['initiator'] = init_addrs[buy_currency] + sell['fulfiller'] = fulfill_addrs[sell_currency] + buy['fulfiller'] = fulfill_addrs[buy_currency] -def seller_init(tradeid, trade): - secret = generate_password() - db.save_secret(tradeid, secret) - print("\nGenerated a secret preimage to lock funds. This will only be stored locally: ", secret) + # initializing contract classes with addresses, currencies, and amounts + trade.sell = Contract(sell) + trade.buy = Contract(buy) + print(trade.sell.__dict__) + print(trade.buy.__dict__) + return tradeid, trade - hash_of_secret = sha256(secret) - # TODO: Implement locktimes and mock block passage of time - sell_locktime = 20 - buy_locktime = 10 # Must be more than first tx - print("Creating pay-to-script-hash for sell contract...") + def seller_init(self, tradeid, trade): + secret = utils.generate_password() + db.save_secret(tradeid, secret) + print("\nGenerated a secret preimage to lock funds. This will only " + "be stored locally: ", secret) - # create the p2sh addrs - create_sell_p2sh(trade, hash_of_secret, sell_locktime) - create_buy_p2sh(trade, hash_of_secret, buy_locktime) + hash_of_secret = utils.sha256(secret) + # TODO: Implement locktimes and mock block passage of time + sell_locktime = 20 + buy_locktime = 10 # Must be more than first tx + print("Creating pay-to-script-hash for sell contract...") - trade.commitment = b2x(hash_of_secret) - print("TRADE after seller init", trade.toJSON()) - return trade + # create the p2sh addrs + self.create_sell_p2sh(trade, hash_of_secret, sell_locktime) + self.create_buy_p2sh(trade, hash_of_secret, buy_locktime) + + trade.commitment = utils.b2x(hash_of_secret) + print("TRADE after seller init", trade.toJSON()) + return trade diff --git a/xcat/tests/test_cli.py b/xcat/tests/test_cli.py index 7fb8367..d952d75 100644 --- a/xcat/tests/test_cli.py +++ b/xcat/tests/test_cli.py @@ -1,53 +1,62 @@ import unittest +import unittest.mock as mock import xcat.cli as cli -import xcat.db as db -from xcat.tests.utils import mktrade -from xcat.trades import Trade, Contract +from xcat.tests.utils import test_trade +from xcat.trades import Trade -class SimpleTestCase(unittest.TestCase): - def setUp(self): - self.trade = mktrade() +class TestCLI(unittest.TestCase): - def test_exporttrade(self): - self.__class__.hexstr = cli.exporttrade('test') - self.assertTrue(int(self.hexstr, 16)) + def test_save_state(self): + pass + + def test_checkSellStatus(self): + pass + + def test_buyer_check_status(self): + pass + + def test_seller_check_status(self): + pass + + def test_checkBuyStatus(self): + pass def test_importtrade(self): - trade = cli.importtrade('test', self.__class__.hexstr) + pass + def test_wormhole_importtrade(self): + pass + + def test_exporttrade(self): + pass -class CliTest(SimpleTestCase): def test_findtrade(self): - trade = cli.findtrade('test') + pass + + def test_find_role(self): + pass + + def test_checktrade(self): + pass def test_newtrade(self): - trade = cli.newtrade('new', conf='regtest') - self.assertTrue(isinstance(trade, Trade)) + pass + + def test_listtrades(self): + pass def test_fundsell(self): - trade = db.get('new') - status = cli.seller_check_status(trade) - print("Trade status: {0}\n".format(status)) - self.assertEqual(status, 'init') - fund_tx = cli.fund_sell_contract(trade) - print("Sent fund_tx", fund_tx) + pass - # def test_fundbuy(self): - # trade = db.get('new') - # status = cli.buyer_check_status(trade) - # self.assertEqual(status, 'sellerFunded') - # fund_tx = cli.fund_contract(trade.buy) - # - # def test_seller_redeem(self): - # trade = db.get('new') - # status = cli.seller_check_status(trade) - # self.assertEqual(status, 'buyerFunded') - # - # def test_buyer_redeem(self): - # trade = db.get('new') - # status = cli.buyer_check_status(trade) - # self.assertEqual(status, 'sellerFunded') + def test_fundbuy(self): + pass + + def test_seller_redeem(self): + pass + + def test_buyer_redeem(self): + pass if __name__ == '__main__': diff --git a/xcat/tests/utils.py b/xcat/tests/utils.py index 867b7a5..8a82b68 100644 --- a/xcat/tests/utils.py +++ b/xcat/tests/utils.py @@ -1,8 +1,20 @@ -import xcat.db as db - -test_trade = {"sell": {"amount": 3.5, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9147788b4511a25fba1092e67b307a6dcdb6da125d967022a04b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", "redeemblocknum": 1066, "currency": "bitcoin", "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp", "p2sh": "2MuYSQ1uQ4CJg5Y5QL2vMmVPHNJ2KT5aJ6f", "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", "fund_tx": "5c5e91a89a08b2d6698f50c9fd9bb2fa22da6c74e226c3dd63d59511566a2fdb"}, "buy": {"amount": 1.2, "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b167023f0db17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", "redeemblocknum": 3391, "currency": "zcash", "locktime": 10, "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ", "p2sh": "t2HP59RpfR34nBCWH4VVD497tkc2ikzgniP", "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY"}, "commitment": "03d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b6"} - -def mktrade(): - db.create(test_trade, 'test') - trade = db.get('test') - return trade +test_trade = { + "sell": { + "amount": 3.5, + "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9147788b4511a25fba1092e67b307a6dcdb6da125d967022a04b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", + "redeemblocknum": 1066, + "currency": "bitcoin", + "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp", + "p2sh": "2MuYSQ1uQ4CJg5Y5QL2vMmVPHNJ2KT5aJ6f", + "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", + "fund_tx": "5c5e91a89a08b2d6698f50c9fd9bb2fa22da6c74e226c3dd63d59511566a2fdb"}, + "buy": { + "amount": 1.2, + "redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b167023f0db17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", + "redeemblocknum": 3391, + "currency": "zcash", + "locktime": 10, + "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ", + "p2sh": "t2HP59RpfR34nBCWH4VVD497tkc2ikzgniP", + "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY"}, + "commitment": "03d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b6"}