refactor protocol, put test stubs in place, linting, prep for cli tests

This commit is contained in:
James Prestwich 2017-09-04 17:03:17 -06:00
parent 9157d12081
commit 270bd7000f
No known key found for this signature in database
GPG Key ID: 519E010A79028CCC
5 changed files with 337 additions and 270 deletions

View File

@ -1,29 +1,32 @@
import argparse, textwrap import argparse
from xcat.utils import * import textwrap
import subprocess
import xcat.db as db import xcat.db as db
import xcat.userInput as userInput import xcat.userInput as userInput
from xcat.protocol import Protocol
from xcat.trades import * from xcat.trades import *
from xcat.protocol import * from xcat.utils import *
import subprocess
def save_state(trade, tradeid): def save_state(trade, tradeid):
save(trade) save(trade)
db.create(trade, tradeid) db.create(trade, tradeid)
def checkSellStatus(tradeid): def checkSellStatus(tradeid):
trade = db.get(tradeid) trade = db.get(tradeid)
status = seller_check_status(trade) status = seller_check_status(trade)
print("Trade status: {0}\n".format(status)) print("Trade status: {0}\n".format(status))
if status == 'init': if status == 'init':
userInput.authorize_fund_sell(trade) userInput.authorize_fund_sell(trade)
fund_tx = fund_sell_contract(trade) fund_tx = protocol.fund_sell_contract(trade)
print("Sent fund_tx", fund_tx) print("Sent fund_tx", fund_tx)
trade.sell.fund_tx = fund_tx trade.sell.fund_tx = fund_tx
save_state(trade, tradeid) save_state(trade, tradeid)
elif status == 'buyerFunded': elif status == 'buyerFunded':
secret = db.get_secret(tradeid) secret = db.get_secret(tradeid)
print("Retrieved secret to redeem funds for {0}: {1}".format(tradeid, secret)) 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: if 'redeem_tx' in txs:
trade.buy.redeem_tx = txs['redeem_tx'] trade.buy.redeem_tx = txs['redeem_tx']
print("Redeem tx: ", txs['redeem_tx']) print("Redeem tx: ", txs['redeem_tx'])
@ -38,9 +41,10 @@ def checkSellStatus(tradeid):
elif status == 'sellerRedeemed': elif status == 'sellerRedeemed':
print("You have already redeemed the p2sh on the second chain of this trade.") print("You have already redeemed the p2sh on the second chain of this trade.")
def buyer_check_status(trade): def buyer_check_status(trade):
sellState = check_fund_status(trade.sell.currency, trade.sell.p2sh) sellState = protocol.check_fund_status(trade.sell.currency, trade.sell.p2sh)
buyState = check_fund_status(trade.buy.currency, trade.buy.p2sh) buyState = protocol.check_fund_status(trade.buy.currency, trade.buy.p2sh)
if sellState == 'funded' and buyState == 'empty': if sellState == 'funded' and buyState == 'empty':
return 'sellerFunded' # step1 return 'sellerFunded' # step1
# TODO: Find funding txid. How does buyer get seller redeemed tx? # TODO: Find funding txid. How does buyer get seller redeemed tx?
@ -54,9 +58,10 @@ def buyer_check_status(trade):
else: else:
return 'init' return 'init'
def seller_check_status(trade): def seller_check_status(trade):
sellState = check_fund_status(trade.sell.currency, trade.sell.p2sh) sellState = protocol.check_fund_status(trade.sell.currency, trade.sell.p2sh)
buyState = check_fund_status(trade.buy.currency, trade.buy.p2sh) buyState = protocol.check_fund_status(trade.buy.currency, trade.buy.p2sh)
if sellState == 'funded' and buyState == 'empty': if sellState == 'funded' and buyState == 'empty':
return 'sellerFunded' # step1 return 'sellerFunded' # step1
elif sellState == 'funded' and hasattr(trade.buy, 'redeem_tx'): elif sellState == 'funded' and hasattr(trade.buy, 'redeem_tx'):
@ -70,6 +75,7 @@ def seller_check_status(trade):
else: else:
return 'init' # step0 return 'init' # step0
def checkBuyStatus(tradeid): def checkBuyStatus(tradeid):
trade = db.get(tradeid) trade = db.get(tradeid)
status = buyer_check_status(trade) 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.") input("Type 'enter' to allow this program to send funds on your behalf.")
print("Trade commitment", trade.commitment) print("Trade commitment", trade.commitment)
# if verify_p2sh(trade): # 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) print("\nYou sent this funding tx: ", fund_tx)
trade.buy.fund_tx = fund_tx trade.buy.fund_tx = fund_tx
save_state(trade, tradeid) save_state(trade, tradeid)
elif status == 'sellerRedeemed': 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: if secret != None:
print("Found secret on blockchain in seller's redeem tx: ", secret) 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: if 'redeem_tx' in txs:
trade.sell.redeem_tx = txs['redeem_tx'] trade.sell.redeem_tx = txs['redeem_tx']
print("Redeem txid: ", trade.sell.redeem_tx) print("Redeem txid: ", trade.sell.redeem_tx)
@ -103,14 +111,16 @@ def checkBuyStatus(tradeid):
else: else:
print("Secret not found in redeemtx") print("Secret not found in redeemtx")
# Import a trade in hex, and save to db # Import a trade in hex, and save to db
def importtrade(tradeid, hexstr=''): def importtrade(tradeid, hexstr=''):
trade = x2s(hexstr) trade = x2s(hexstr)
trade = db.instantiate(trade) trade = db.instantiate(trade)
import_addrs(trade) protocol.import_addrs(trade)
print(trade.toJSON()) print(trade.toJSON())
save_state(trade, tradeid) save_state(trade, tradeid)
def wormhole_importtrade(): def wormhole_importtrade():
res = subprocess.call('wormhole receive', shell=True) res = subprocess.call('wormhole receive', shell=True)
if res == 0: if res == 0:
@ -123,6 +133,7 @@ def wormhole_importtrade():
else: else:
print("Importing trade using magic-wormhole failed.") print("Importing trade using magic-wormhole failed.")
# Export a trade by its tradeid # Export a trade by its tradeid
def exporttrade(tradeid, wormhole=False): def exporttrade(tradeid, wormhole=False):
trade = db.get(tradeid) trade = db.get(tradeid)
@ -138,20 +149,24 @@ def exporttrade(tradeid, wormhole=False):
print(hexstr) print(hexstr)
return hexstr return hexstr
def findtrade(tradeid): def findtrade(tradeid):
trade = db.get(tradeid) trade = db.get(tradeid)
print(trade.toJSON()) print(trade.toJSON())
return trade return trade
def find_role(contract): def find_role(contract):
# When regtest created both addrs on same machine, role is both. # When regtest created both addrs on same machine, role is both.
if is_myaddr(contract.initiator) and is_myaddr(contract.fulfiller): if protocol.is_myaddr(contract.initiator):
if protocol.is_myaddr(contract.fulfiller):
return 'test' return 'test'
elif is_myaddr(contract.initiator): else:
return 'initiator' return 'initiator'
else: else:
return 'fulfiller' return 'fulfiller'
def checktrade(tradeid): def checktrade(tradeid):
print("In checktrade") print("In checktrade")
trade = db.get(tradeid) trade = db.get(tradeid)
@ -170,22 +185,25 @@ def checktrade(tradeid):
role = 'buyer' role = 'buyer'
checkBuyStatus(tradeid) checkBuyStatus(tradeid)
def newtrade(tradeid, **kwargs): def newtrade(tradeid, **kwargs):
print("Creating new XCAT trade...") print("Creating new XCAT trade...")
erase_trade() erase_trade()
tradeid, trade= initialize_trade(tradeid, conf=kwargs['conf']) tradeid, trade = protocol.initialize_trade(tradeid, conf=kwargs['conf'])
print("Trade", trade) 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") print("\nUse 'xcat exporttrade [tradeid]' to export the trade and sent to the buyer.\n")
save_state(trade, tradeid) save_state(trade, tradeid)
return trade return trade
def listtrades(): def listtrades():
print("Trades") print("Trades")
trades = db.dump() trades = db.dump()
for trade in trades: for trade in trades:
print("{0}: {1}".format(trade[0], trade[1])) print("{0}: {1}".format(trade[0], trade[1]))
def main(): def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent('''\ description=textwrap.dedent('''\

View File

@ -1,10 +1,10 @@
import plyvel import plyvel
from xcat.utils import *
import binascii
import sys
import json import json
import ast # import binascii
# import sys
# import ast
from xcat.trades import * from xcat.trades import *
from xcat.utils import *
db = plyvel.DB('/tmp/xcatDB', create_if_missing=True) db = plyvel.DB('/tmp/xcatDB', create_if_missing=True)
preimageDB = plyvel.DB('/tmp/preimageDB', 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 ########### ######## Trades stored by tradeid ###########
############################################# #############################################
# Takes dict or obj, saves json str as bytes # Takes dict or obj, saves json str as bytes
def create(trade, tradeid): def create(trade, tradeid):
if type(trade) == dict: if type(trade) == dict:
@ -21,6 +22,7 @@ def create(trade, tradeid):
trade = trade.toJSON() trade = trade.toJSON()
db.put(b(tradeid), b(trade)) db.put(b(tradeid), b(trade))
# Uses the funding txid as the key to save trade # Uses the funding txid as the key to save trade
def createByFundtx(trade): def createByFundtx(trade):
trade = trade.toJSON() trade = trade.toJSON()
@ -29,12 +31,14 @@ def createByFundtx(trade):
txid = jt['sell']['fund_tx'] txid = jt['sell']['fund_tx']
db.put(b(txid), b(trade)) db.put(b(txid), b(trade))
def get(tradeid): def get(tradeid):
rawtrade = db.get(b(tradeid)) rawtrade = db.get(b(tradeid))
tradestr = str(rawtrade, 'utf-8') tradestr = str(rawtrade, 'utf-8')
trade = instantiate(tradestr) trade = instantiate(tradestr)
return trade return trade
def instantiate(trade): def instantiate(trade):
if type(trade) == str: if type(trade) == str:
tradestr = json.loads(trade) tradestr = json.loads(trade)
@ -45,10 +49,12 @@ def instantiate(trade):
###### Preimages stored by tradeid ########## ###### Preimages stored by tradeid ##########
############################################# #############################################
# Stores secret locally in key/value store by tradeid # Stores secret locally in key/value store by tradeid
def save_secret(tradeid, secret): def save_secret(tradeid, secret):
res = preimageDB.put(b(tradeid), b(secret)) res = preimageDB.put(b(tradeid), b(secret))
def get_secret(tradeid): def get_secret(tradeid):
secret = preimageDB.get(b(tradeid)) secret = preimageDB.get(b(tradeid))
secret = str(secret, 'utf-8') secret = str(secret, 'utf-8')
@ -67,6 +73,7 @@ def dump():
results.append((str(k, 'utf-8'), j)) results.append((str(k, 'utf-8'), j))
return results return results
def print_entries(): def print_entries():
it = db.iterator() it = db.iterator()
with db.iterator() as it: with db.iterator() as it:

View File

@ -1,56 +1,60 @@
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.userInput as userInput
import xcat.db as db 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.bitcoinRPC import bitcoinProxy
from xcat.zcashRPC import zcashProxy from xcat.zcashRPC import zcashProxy
bitcoinRPC = bitcoinProxy()
zcashRPC = zcashProxy()
def is_myaddr(address): class Protocol():
def __init__(self):
self.bitcoinRPC = bitcoinProxy()
self.zcashRPC = zcashProxy()
def is_myaddr(self, address):
if address[:1] == 'm': if address[:1] == 'm':
status = bitcoinRPC.validateaddress(address) status = self.bitcoinRPC.validateaddress(address)
else: else:
status = zcashRPC.validateaddress(address) status = self.zcashRPC.validateaddress(address)
status = status['ismine'] status = status['ismine']
# print("Address {0} is mine: {1}".format(address, status)) # print("Address {0} is mine: {1}".format(address, status))
return status return status
def find_secret_from_fundtx(currency, p2sh, fundtx): def find_secret_from_fundtx(self, currency, p2sh, fundtx):
if currency == 'bitcoin': if currency == 'bitcoin':
secret = bitcoinRPC.find_secret(p2sh, fundtx) secret = self.bitcoinRPC.find_secret(p2sh, fundtx)
else: else:
secret = zcashRPC.find_secret(p2sh, fundtx) secret = self.zcashRPC.find_secret(p2sh, fundtx)
return secret return secret
def import_addrs(trade): def import_addrs(self, trade):
check_fund_status(trade.sell.currency, trade.sell.p2sh) self.check_fund_status(trade.sell.currency, trade.sell.p2sh)
check_fund_status(trade.buy.currency, trade.buy.p2sh) self.check_fund_status(trade.buy.currency, trade.buy.p2sh)
def check_p2sh(currency, address): def check_p2sh(self, currency, address):
if currency == 'bitcoin': if currency == 'bitcoin':
print("Checking funds in Bitcoin p2sh") print("Checking funds in Bitcoin p2sh")
return bitcoinRPC.check_funds(address) return self.bitcoinRPC.check_funds(address)
else: else:
print("Checking funds in Zcash p2sh") print("Checking funds in Zcash p2sh")
return zcashRPC.check_funds(address) return self.zcashRPC.check_funds(address)
def check_fund_status(currency, address): def check_fund_status(self, currency, address):
if currency == 'bitcoin': if currency == 'bitcoin':
print("Checking funds in Bitcoin p2sh") print("Checking funds in Bitcoin p2sh")
return bitcoinRPC.get_fund_status(address) return self.bitcoinRPC.get_fund_status(address)
else: else:
print("Checking funds in Zcash p2sh") print("Checking funds in Zcash p2sh")
return zcashRPC.get_fund_status(address) return self.zcashRPC.get_fund_status(address)
# TODO: function to calculate appropriate locktimes between chains # TODO: function to calculate appropriate locktimes between chains
# def verify_p2sh(trade): # def verify_p2sh(trade):
# htlc = create_htlc(trade.buy.currency, trade.buy.fulfiller, trade.buy.initiator, trade.commitment, trade.buy.locktime) # htlc = self.create_htlc(
# trade.buy.currency, trade.buy.fulfiller,
# trade.buy.initiator, trade.commitment,
# trade.buy.locktime)
# buyer_p2sh = htlc['p2sh'] # buyer_p2sh = htlc['p2sh']
# print("Buyer p2sh:", buyer_p2sh) # print("Buyer p2sh:", buyer_p2sh)
# If the two p2sh match... # If the two p2sh match...
@ -58,123 +62,140 @@ def check_fund_status(currency, address):
# else: # else:
# print("Compiled p2sh for htlc does not match what seller sent.") # print("Compiled p2sh for htlc does not match what seller sent.")
def create_htlc(currency, funder, redeemer, commitment, locktime): def create_htlc(self, currency, funder, redeemer, commitment, locktime):
if currency == 'bitcoin': if currency == 'bitcoin':
sell_p2sh = bitcoinRPC.hashtimelockcontract(funder, redeemer, commitment, locktime) sell_p2sh = self.bitcoinRPC.hashtimelockcontract(
funder, redeemer, commitment, locktime)
else: else:
sell_p2sh = zcashRPC.hashtimelockcontract(funder, redeemer, commitment, locktime) sell_p2sh = self.zcashRPC.hashtimelockcontract(
funder, redeemer, commitment, locktime)
return sell_p2sh return sell_p2sh
def fund_htlc(currency, p2sh, amount): def fund_htlc(self, currency, p2sh, amount):
if currency == 'bitcoin': if currency == 'bitcoin':
txid = bitcoinRPC.fund_htlc(p2sh, amount) txid = self.bitcoinRPC.fund_htlc(p2sh, amount)
else: else:
txid = zcashRPC.fund_htlc(p2sh, amount) txid = self.zcashRPC.fund_htlc(p2sh, amount)
return txid return txid
def fund_contract(contract): def fund_contract(self, contract):
txid = fund_htlc(contract.currency, contract.p2sh, contract.amount) txid = self.fund_htlc(
contract.currency, contract.p2sh, contract.amount)
return txid return txid
def fund_sell_contract(trade): def fund_sell_contract(self, trade):
sell = trade.sell sell = trade.sell
txid = fund_htlc(sell.currency, sell.p2sh, sell.amount) txid = self.fund_htlc(sell.currency, sell.p2sh, sell.amount)
setattr(trade.sell, 'fund_tx', txid) setattr(trade.sell, 'fund_tx', txid)
save(trade) utils.save(trade)
return txid return txid
def create_sell_p2sh(trade, commitment, locktime): def create_sell_p2sh(self, trade, commitment, locktime):
# CREATE SELL CONTRACT # CREATE SELL CONTRACT
sell = trade.sell sell = trade.sell
contract = create_htlc(sell.currency, sell.initiator, sell.fulfiller, commitment, locktime) contract = self.create_htlc(sell.currency, sell.initiator,
sell.fulfiller, commitment, locktime)
print("sell contract", contract) print("sell contract", contract)
setattr(trade.sell, 'p2sh', contract['p2sh']) setattr(trade.sell, 'p2sh', contract['p2sh'])
setattr(trade.sell, 'redeemScript', contract['redeemScript']) setattr(trade.sell, 'redeemScript', contract['redeemScript'])
setattr(trade.sell, 'redeemblocknum', contract['redeemblocknum']) setattr(trade.sell, 'redeemblocknum', contract['redeemblocknum'])
setattr(trade.buy, 'locktime', contract['locktime']) setattr(trade.buy, 'locktime', contract['locktime'])
save(trade) utils.save(trade)
def create_buy_p2sh(trade, commitment, locktime): def create_buy_p2sh(self, trade, commitment, locktime):
## CREATE BUY CONTRACT # CREATE BUY CONTRACT
buy = trade.buy 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)) print("\nNow creating buy contract on the {0} blockchain where you "
buy_contract = create_htlc(buy.currency, buy.fulfiller, buy.initiator, commitment, locktime) "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) print("Buy contract", buy_contract)
setattr(trade.buy, 'p2sh', buy_contract['p2sh']) setattr(trade.buy, 'p2sh', buy_contract['p2sh'])
setattr(trade.buy, 'redeemScript', buy_contract['redeemScript']) setattr(trade.buy, 'redeemScript', buy_contract['redeemScript'])
setattr(trade.buy, 'redeemblocknum', buy_contract['redeemblocknum']) setattr(trade.buy, 'redeemblocknum', buy_contract['redeemblocknum'])
setattr(trade.buy, 'locktime', buy_contract['locktime']) 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)) print("\nNow contact the buyer and tell them to send funds to this "
"p2sh: {0}\n".format(trade.buy.p2sh))
save(trade) utils.save(trade)
def redeem_p2sh(contract, secret): def redeem_p2sh(self, contract, secret):
currency = contract.currency currency = contract.currency
if currency == 'bitcoin': if currency == 'bitcoin':
res = bitcoinRPC.redeem_contract(contract, secret) res = self.bitcoinRPC.redeem_contract(contract, secret)
else: else:
res = zcashRPC.redeem_contract(contract, secret) res = self.zcashRPC.redeem_contract(contract, secret)
return res return res
def parse_secret(chain, txid): def parse_secret(self, chain, txid):
if chain == 'bitcoin': if chain == 'bitcoin':
secret = bitcoinRPC.parse_secret(txid) secret = self.bitcoinRPC.parse_secret(txid)
else: else:
secret = zcashRPC.parse_secret(txid) secret = self.zcashRPC.parse_secret(txid)
return secret return secret
#### Main functions determining user flow from command line # Main functions determining user flow from command line
def buyer_redeem(trade): def buyer_redeem(self, trade):
userInput.authorize_buyer_redeem(trade) userInput.authorize_buyer_redeem(trade)
if trade.sell.get_status() == 'redeemed': if trade.sell.get_status() == 'redeemed':
print("You already redeemed the funds and acquired {0} {1}".format(trade.sell.amount, trade.sell.currency)) print("You already redeemed the funds and acquired "
"{0} {1}".format(trade.sell.amount, trade.sell.currency))
exit() exit()
else: else:
# Buyer redeems seller's funded tx # Buyer redeems seller's funded tx
p2sh = trade.sell.p2sh # p2sh = trade.sell.p2sh
currency = trade.sell.currency # currency = trade.sell.currency
# Buy contract is where seller disclosed secret in redeeming # Buy contract is where seller disclosed secret in redeeming
if trade.buy.currency == 'bitcoin': if trade.buy.currency == 'bitcoin':
secret = bitcoinRPC.parse_secret(trade.buy.redeem_tx) secret = self.bitcoinRPC.parse_secret(trade.buy.redeem_tx)
else: else:
secret = zcashRPC.parse_secret(trade.buy.redeem_tx) secret = self.zcashRPC.parse_secret(trade.buy.redeem_tx)
print("Found secret in seller's redeem tx", secret) print("Found secret in seller's redeem tx", secret)
redeem_tx = redeem_p2sh(trade.sell, secret) redeem_tx = self.redeem_p2sh(trade.sell, secret)
setattr(trade.sell, 'redeem_tx', redeem_tx) setattr(trade.sell, 'redeem_tx', redeem_tx)
save(trade) utils.save(trade)
exit() exit()
def seller_redeem_p2sh(trade, secret): def seller_redeem_p2sh(self, trade, secret):
buy = trade.buy buy = trade.buy
userInput.authorize_seller_redeem(buy) userInput.authorize_seller_redeem(buy)
if trade.sell.get_status() == 'redeemed': if trade.sell.get_status() == 'redeemed':
print("You already redeemed the funds and acquired {0} {1}".format(buy.amount, buy.currency)) print("You already redeemed the funds and acquired "
"{0} {1}".format(buy.amount, buy.currency))
exit() exit()
else: else:
# Seller redeems buyer's funded tx (contract in p2sh) # Seller redeems buyer's funded tx (contract in p2sh)
txs = redeem_p2sh(trade.buy, secret) txs = self.redeem_p2sh(trade.buy, secret)
print("You have redeemed {0} {1}!".format(buy.amount, buy.currency)) print("You have redeemed "
"{0} {1}!".format(buy.amount, buy.currency))
return txs return txs
def buyer_fulfill(trade): def buyer_fulfill(self, trade):
buy = trade.buy buy = trade.buy
sell = trade.sell sell = trade.sell
buy_p2sh_balance = check_p2sh(buy.currency, buy.p2sh) buy_p2sh_balance = self.check_p2sh(buy.currency, buy.p2sh)
sell_p2sh_balance = check_p2sh(sell.currency, sell.p2sh) sell_p2sh_balance = self.check_p2sh(sell.currency, sell.p2sh)
if buy_p2sh_balance == 0: if buy_p2sh_balance == 0:
userInput.authorize_buyer_fulfill(sell_p2sh_balance, sell.currency, buy_p2sh_balance, buy.currency) userInput.authorize_buyer_fulfill(
sell_p2sh_balance,
sell.currency,
buy_p2sh_balance,
buy.currency)
print("Buy amt:", buy.amount) print("Buy amt:", buy.amount)
txid = fund_buy_contract(trade) txid = fund_buy_contract(trade)
print("Fund tx txid:", txid) print("Fund tx txid:", txid)
else: 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("It looks like you've already funded the contract to buy "
print("Please wait for the seller to remove your funds from escrow to complete the trade.") "{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') print_trade('buyer')
def initialize_trade(tradeid, **kwargs): def initialize_trade(self, tradeid, **kwargs):
trade = Trade() trade = Trade()
conf = kwargs['conf'] conf = kwargs['conf']
if conf == 'cli': if conf == 'cli':
@ -203,22 +224,22 @@ def initialize_trade(tradeid, **kwargs):
print(trade.buy.__dict__) print(trade.buy.__dict__)
return tradeid, trade return tradeid, trade
def seller_init(self, tradeid, trade):
def seller_init(tradeid, trade): secret = utils.generate_password()
secret = generate_password()
db.save_secret(tradeid, secret) db.save_secret(tradeid, secret)
print("\nGenerated a secret preimage to lock funds. This will only be stored locally: ", secret) print("\nGenerated a secret preimage to lock funds. This will only "
"be stored locally: ", secret)
hash_of_secret = sha256(secret) hash_of_secret = utils.sha256(secret)
# TODO: Implement locktimes and mock block passage of time # TODO: Implement locktimes and mock block passage of time
sell_locktime = 20 sell_locktime = 20
buy_locktime = 10 # Must be more than first tx buy_locktime = 10 # Must be more than first tx
print("Creating pay-to-script-hash for sell contract...") print("Creating pay-to-script-hash for sell contract...")
# create the p2sh addrs # create the p2sh addrs
create_sell_p2sh(trade, hash_of_secret, sell_locktime) self.create_sell_p2sh(trade, hash_of_secret, sell_locktime)
create_buy_p2sh(trade, hash_of_secret, buy_locktime) self.create_buy_p2sh(trade, hash_of_secret, buy_locktime)
trade.commitment = b2x(hash_of_secret) trade.commitment = utils.b2x(hash_of_secret)
print("TRADE after seller init", trade.toJSON()) print("TRADE after seller init", trade.toJSON())
return trade return trade

View File

@ -1,53 +1,62 @@
import unittest import unittest
import unittest.mock as mock
import xcat.cli as cli import xcat.cli as cli
import xcat.db as db from xcat.tests.utils import test_trade
from xcat.tests.utils import mktrade from xcat.trades import Trade
from xcat.trades import Trade, Contract
class SimpleTestCase(unittest.TestCase): class TestCLI(unittest.TestCase):
def setUp(self):
self.trade = mktrade()
def test_exporttrade(self): def test_save_state(self):
self.__class__.hexstr = cli.exporttrade('test') pass
self.assertTrue(int(self.hexstr, 16))
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): 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): def test_findtrade(self):
trade = cli.findtrade('test') pass
def test_find_role(self):
pass
def test_checktrade(self):
pass
def test_newtrade(self): def test_newtrade(self):
trade = cli.newtrade('new', conf='regtest') pass
self.assertTrue(isinstance(trade, Trade))
def test_listtrades(self):
pass
def test_fundsell(self): def test_fundsell(self):
trade = db.get('new') pass
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)
# def test_fundbuy(self): def test_fundbuy(self):
# trade = db.get('new') pass
# status = cli.buyer_check_status(trade)
# self.assertEqual(status, 'sellerFunded') def test_seller_redeem(self):
# fund_tx = cli.fund_contract(trade.buy) pass
#
# def test_seller_redeem(self): def test_buyer_redeem(self):
# trade = db.get('new') pass
# 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')
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,8 +1,20 @@
import xcat.db as db test_trade = {
"sell": {
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"} "amount": 3.5,
"redeemScript": "63a82003d58daab37238604b3e57d4a8bdcffa401dc497a9c1aa4f08ffac81616c22b68876a9147788b4511a25fba1092e67b307a6dcdb6da125d967022a04b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac",
def mktrade(): "redeemblocknum": 1066,
db.create(test_trade, 'test') "currency": "bitcoin",
trade = db.get('test') "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp",
return trade "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"}