Merge branch 'master' of github.com:zcash-hackworks/ZBXCAT

This commit is contained in:
Jay Graber 2017-10-19 11:10:12 -07:00
commit 9f01f7fc30
7 changed files with 271 additions and 409 deletions

View File

@ -67,8 +67,6 @@ class bitcoinProxy():
def get_keys(self, funder_address, redeemer_address): def get_keys(self, funder_address, redeemer_address):
fundpubkey = CBitcoinAddress(funder_address) fundpubkey = CBitcoinAddress(funder_address)
redeempubkey = CBitcoinAddress(redeemer_address) redeempubkey = CBitcoinAddress(redeemer_address)
# fundpubkey = self.bitcoind.getnewaddress()
# redeempubkey = self.bitcoind.getnewaddress()
return fundpubkey, redeempubkey return fundpubkey, redeempubkey
def privkey(self, address): def privkey(self, address):
@ -79,7 +77,8 @@ class bitcoinProxy():
redeemerAddr = CBitcoinAddress(redeemer) redeemerAddr = CBitcoinAddress(redeemer)
if type(commitment) == str: if type(commitment) == str:
commitment = x(commitment) commitment = x(commitment)
# h = sha256(secret) else:
raise ValueError("Commitment was not a string: {0}".format(commitment))
blocknum = self.bitcoind.getblockcount() blocknum = self.bitcoind.getblockcount()
print("Current blocknum on Bitcoin: ", blocknum) print("Current blocknum on Bitcoin: ", blocknum)
redeemblocknum = blocknum + locktime redeemblocknum = blocknum + locktime

View File

@ -9,252 +9,229 @@ import xcat.utils as utils
from xcat.protocol import Protocol from xcat.protocol import Protocol
from xcat.trades import Trade from xcat.trades import Trade
class CLI():
def __init__(self):
self.db = DB()
self.protocol = Protocol()
def save_state(trade, tradeid): def checkSellStatus(self, tradeid):
db = DB() trade = self.db.get(tradeid)
utils.save(trade) status = self.seller_check_status(trade)
db.create(trade, tradeid) print("Trade status: {0}\n".format(status))
if status == 'init':
userInput.authorize_fund_sell(trade)
fund_tx = self.protocol.fund_sell_contract(trade)
def checkSellStatus(tradeid): print("Sent fund_tx", fund_tx)
db = DB() trade.sell.fund_tx = fund_tx
protocol = Protocol() self.db.create(trade, tradeid)
trade = db.get(tradeid) elif status == 'buyerFunded':
status = seller_check_status(trade) secret = self.db.get_secret(tradeid)
print("Trade status: {0}\n".format(status)) print("Retrieved secret to redeem funds for "
"{0}: {1}".format(tradeid, secret))
if status == 'init': txs = self.protocol.seller_redeem_p2sh(trade, secret)
userInput.authorize_fund_sell(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 = protocol.seller_redeem_p2sh(trade, secret)
if 'redeem_tx' in txs:
trade.buy.redeem_tx = txs['redeem_tx']
print("Redeem tx: ", txs['redeem_tx'])
if 'refund_tx' in txs:
trade.buy.redeem_tx = txs['refund_tx']
print("Buyer refund tx: ", txs['refund_tx'])
txs = protocol.refund_contract(trade.sell) # Refund to seller
print("Your refund txid: ", txs['refund_tx'])
save_state(trade, tradeid)
# Remove from db? Or just from temporary file storage
utils.cleanup(tradeid)
elif status == 'sellerFunded':
print("Buyer has not yet funded the contract where you offered to "
"buy {0}, please wait for them to complete "
"their part.".format(trade.buy.currency))
elif status == 'sellerRedeemed':
print("You have already redeemed the p2sh on the second chain of "
"this trade.")
def buyer_check_status(trade):
protocol = Protocol()
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?
elif sellState == 'funded' and hasattr(trade.buy, 'fund_tx'):
return 'sellerRedeemed' # step3
elif sellState == 'funded' and buyState == 'funded':
return 'buyerFunded' # step2
elif sellState == 'empty' and buyState == 'empty':
if hasattr(trade.sell, 'redeem_tx'):
return 'buyerRedeemed' # step4
else:
return 'init'
def seller_check_status(trade):
protocol = Protocol()
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'):
return 'sellerRedeemed' # step3
# TODO: How does seller get buyer funded tx?
elif sellState == 'funded' and buyState == 'funded':
return 'buyerFunded' # step2
elif sellState == 'empty' and buyState == 'empty':
if hasattr(trade.buy, 'redeem_tx'):
return 'buyerRedeemed' # step4
else:
return 'init' # step0
def checkBuyStatus(tradeid):
db = DB()
protocol = Protocol()
trade = db.get(tradeid)
status = buyer_check_status(trade)
print("Trade status: {0}\n".format(status))
if status == 'init':
print("Trade has not yet started, waiting for seller to fund the "
"sell p2sh.")
elif status == 'buyerRedeemed':
print("This trade is complete, both sides redeemed.")
elif status == 'sellerFunded':
print("One active trade available, fulfilling buyer contract...")
input("Type 'enter' to allow this program to send funds on your "
"behalf.")
print("Trade commitment", trade.commitment)
# if verify_p2sh(trade):
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 = protocol.find_secret_from_fundtx(trade.buy.currency,
trade.buy.p2sh,
trade.buy.fund_tx)
if secret is not None:
print("Found secret on blockchain in seller's redeem tx: ", 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.buy.redeem_tx = txs['redeem_tx']
print("Redeem txid: ", trade.sell.redeem_tx) print("Redeem tx: ", txs['redeem_tx'])
elif 'refund_tx' in txs: if 'refund_tx' in txs:
trade.sell.redeem_tx = txs['refund_tx'] trade.buy.redeem_tx = txs['refund_tx']
print("Refund tx: ", txs['refund_tx']) print("Buyer refund tx: ", txs['refund_tx'])
save_state(trade, tradeid) txs = self.protocol.refund_contract(trade.sell) # Refund to seller
print("XCAT trade complete!") print("Your refund txid: ", txs['refund_tx'])
self.db.create(trade, tradeid)
# Remove from db? Or just from temporary file storage
utils.cleanup(tradeid)
elif status == 'sellerFunded':
print("Buyer has not yet funded the contract where you offered to "
"buy {0}, please wait for them to complete "
"their part.".format(trade.buy.currency))
elif status == 'sellerRedeemed':
print("You have already redeemed the p2sh on the second chain of "
"this trade.")
def buyer_check_status(self, trade):
sellState = self.protocol.check_fund_status(
trade.sell.currency, trade.sell.p2sh)
buyState = self.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?
elif sellState == 'funded' and hasattr(trade.buy, 'fund_tx'):
return 'sellerRedeemed' # step3
elif sellState == 'funded' and buyState == 'funded':
return 'buyerFunded' # step2
elif sellState == 'empty' and buyState == 'empty':
if hasattr(trade.sell, 'redeem_tx'):
return 'buyerRedeemed' # step4
else:
return 'init'
def seller_check_status(self, trade):
sellState = self.protocol.check_fund_status(
trade.sell.currency, trade.sell.p2sh)
buyState = self.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'):
return 'sellerRedeemed' # step3
# TODO: How does seller get buyer funded tx?
elif sellState == 'funded' and buyState == 'funded':
return 'buyerFunded' # step2
elif sellState == 'empty' and buyState == 'empty':
if hasattr(trade.buy, 'redeem_tx'):
return 'buyerRedeemed' # step4
else:
return 'init' # step0
def checkBuyStatus(self, tradeid):
trade = self.db.get(tradeid)
status = self.buyer_check_status(trade)
print("Trade status: {0}\n".format(status))
if status == 'init':
print("Trade has not yet started, waiting for seller to fund the "
"sell p2sh.")
elif status == 'buyerRedeemed':
print("This trade is complete, both sides redeemed.")
elif status == 'sellerFunded':
print("One active trade available, fulfilling buyer contract...")
input("Type 'enter' to allow this program to send funds on your "
"behalf.")
print("Trade commitment", trade.commitment)
# if verify_p2sh(trade):
fund_tx = self.protocol.fund_contract(trade.buy)
print("\nYou sent this funding tx: ", fund_tx)
trade.buy.fund_tx = fund_tx
self.db.create(trade, tradeid)
elif status == 'sellerRedeemed':
secret = self.protocol.find_secret_from_fundtx(trade.buy.currency,
trade.buy.p2sh,
trade.buy.fund_tx)
if secret is not None:
print("Found secret on blockchain in seller's redeem tx: ", secret)
txs = self.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)
elif 'refund_tx' in txs:
trade.sell.redeem_tx = txs['refund_tx']
print("Refund tx: ", txs['refund_tx'])
self.db.create(trade, tradeid)
print("XCAT trade complete!")
else:
# Search if tx has been refunded from p2sh
print("Secret not found in redeemtx")
# Import a trade in hex, and save to db
def importtrade(self, tradeid, hexstr=''):
trade = utils.x2s(hexstr)
trade = Trade(trade)
self.protocol.import_addrs(trade)
print(trade.toJSON())
self.db.create(trade, tradeid)
def wormhole_importtrade(self):
res = subprocess.call('wormhole receive', shell=True)
if res == 0:
tradeid = input("Enter filename of received trade data to import "
"(printed on line above): ")
with open(tradeid) as infile:
hexstr = infile.readline().strip()
self.importtrade(tradeid, hexstr)
print("Successfully imported trade using magic-wormhole")
os.remove(tradeid)
else: else:
# Search if tx has been refunded from p2sh print("Importing trade using magic-wormhole failed.")
print("Secret not found in redeemtx")
# Import a trade in hex, and save to db # Export a trade by its tradeid
def importtrade(tradeid, hexstr=''): def exporttrade(self, tradeid, wormhole=False):
protocol = Protocol() trade = self.db.get(tradeid)
trade = utils.x2s(hexstr) hexstr = utils.s2x(trade.toJSON())
trade = Trade(trade) if wormhole:
protocol.import_addrs(trade) tradefile = os.path.join(utils.ROOT_DIR, '.tmp/{0}'.format(tradeid))
print(trade.toJSON()) print(tradefile)
save_state(trade, tradeid) with open(tradefile, '+w') as outfile:
outfile.write(hexstr)
print("Exporting trade to buyer using magic wormhole.")
def wormhole_importtrade(): subprocess.call('wormhole send {0}'.format(tradefile), shell=True)
res = subprocess.call('wormhole receive', shell=True)
if res == 0:
tradeid = input("Enter filename of received trade data to import "
"(printed on line above): ")
with open(tradeid) as infile:
hexstr = infile.readline().strip()
importtrade(tradeid, hexstr)
print("Successfully imported trade using magic-wormhole")
os.remove(tradeid)
else:
print("Importing trade using magic-wormhole failed.")
# Export a trade by its tradeid
def exporttrade(tradeid, wormhole=False):
db = DB()
trade = db.get(tradeid)
hexstr = utils.s2x(trade.toJSON())
if wormhole:
tradefile = os.path.join(utils.ROOT_DIR, '.tmp/{0}'.format(tradeid))
print(tradefile)
with open(tradefile, '+w') as outfile:
outfile.write(hexstr)
print("Exporting trade to buyer using magic wormhole.")
subprocess.call('wormhole send {0}'.format(tradefile), shell=True)
else:
print(hexstr)
return hexstr
def findtrade(tradeid):
db = DB()
trade = db.get(tradeid)
print(trade.toJSON())
return trade
def find_role(contract):
protocol = Protocol()
# When regtest created both addrs on same machine, role is both.
if protocol.is_myaddr(contract.initiator):
if protocol.is_myaddr(contract.fulfiller):
return 'test'
else: else:
return 'initiator' print(hexstr)
else: return hexstr
if protocol.is_myaddr(contract.fulfiller):
return 'fulfiller' def findtrade(self, tradeid):
trade = self.db.get(tradeid)
print(trade.toJSON())
return trade
def find_role(self, contract):
# When regtest created both addrs on same machine, role is both.
if self.protocol.is_myaddr(contract.initiator):
if self.protocol.is_myaddr(contract.fulfiller):
return 'test'
else:
return 'initiator'
else: else:
raise ValueError('You are not a participant in this contract.') if self.protocol.is_myaddr(contract.fulfiller):
return 'fulfiller'
else:
raise ValueError('You are not a participant in this contract.')
def checktrade(tradeid): def checktrade(self, tradeid):
db = DB() print("In checktrade")
print("In checktrade") trade = self.db.get(tradeid)
trade = db.get(tradeid) if find_role(trade.sell) == 'test':
if find_role(trade.sell) == 'test': input("Is this a test? Both buyer and seller addresses are yours, "
input("Is this a test? Both buyer and seller addresses are yours, " "press 'enter' to test.")
"press 'enter' to test.") self.checkSellStatus(tradeid)
checkSellStatus(tradeid) self.checkBuyStatus(tradeid)
checkBuyStatus(tradeid) self.checkSellStatus(tradeid)
checkSellStatus(tradeid) self.checkBuyStatus(tradeid)
checkBuyStatus(tradeid) elif find_role(trade.sell) == 'initiator':
elif find_role(trade.sell) == 'initiator': print("You are the seller in this trade.")
print("You are the seller in this trade.") # role = 'seller'
# role = 'seller' self.checkSellStatus(tradeid)
checkSellStatus(tradeid) else:
else: print("You are the buyer in this trade.")
print("You are the buyer in this trade.") # role = 'buyer'
# role = 'buyer' self.checkBuyStatus(tradeid)
checkBuyStatus(tradeid)
def newtrade(self, tradeid, **kwargs):
print("Creating new XCAT trade...")
utils.erase_trade()
conf = kwargs['conf'] if 'conf' in kwargs else 'regtest'
network = kwargs['network'] if 'network' in kwargs else 'regtest'
tradeid, trade = self.protocol.initialize_trade(tradeid, conf=conf, network=network)
print("New trade created: {0}".format(trade))
def newtrade(tradeid, **kwargs): trade, secret = self.protocol.seller_init(tradeid, trade, network=network)
protocol = Protocol() self.db.save_secret(tradeid, secret)
print("Creating new XCAT trade...") print("\nGenerated a secret preimage to lock funds. This will only "
utils.erase_trade() "be stored locally: {0}".format(secret))
print("\nUse 'xcat exporttrade [tradeid]' to export the trade and send to the buyer.\n")
conf = kwargs['conf'] if 'conf' in kwargs else 'regtest' self.db.create(trade, tradeid)
network = kwargs['network'] if 'network' in kwargs else 'regtest' return trade
tradeid, trade = protocol.initialize_trade(
tradeid,
conf=conf,
network=network)
print("New trade created: {0}".format(trade))
trade = protocol.seller_init(tradeid, trade, network=network)
print("\nUse 'xcat exporttrade [tradeid]' to export the trade and sent "
"to the buyer.\n")
save_state(trade, tradeid)
return trade
def listtrades():
db = DB()
print("Trades")
trade_list = db.dump()
for trade in trade_list:
print("{0}: {1}".format(trade[0], trade[1]))
def listtrades(self):
print("Trades")
trade_list = self.db.dump()
for trade in trade_list:
print("{0}: {1}".format(trade[0], trade[1]))
def main(): def main():
cli = CLI()
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter, formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent('''\ description=textwrap.dedent('''\
@ -266,26 +243,15 @@ def main():
findtrade "tradeid" - find a trade by the tradeid findtrade "tradeid" - find a trade by the tradeid
''')) '''))
parser.add_argument("command", action="store", help="list commands")
parser.add_argument( parser.add_argument("arguments", action="store", nargs="*", help="add arguments")
"command", action="store", help="list commands") parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode. Defaults to false")
parser.add_argument( parser.add_argument("-w", "--wormhole", action="store_true", help="Transfer trade data through magic-wormhole")
"arguments", action="store", nargs="*", help="add arguments") parser.add_argument("-c", "--conf", action="store", help="Use trade data in conf file ('testnet' or 'regtest'), or pass trade data in on cli as json.")
parser.add_argument( parser.add_argument("-n", "--network", action="store", help="Set network to regtest or mainnet. Defaults to testnet while in alpha.")
"-w", "--wormhole", action="store_true", # parser.add_argument("--daemon", "-d", action="store_true", help="Run as daemon process")
help="Transfer trade data through magic-wormhole")
parser.add_argument(
"-c", "--conf", action="store",
help="Use default trade data in conf file.")
parser.add_argument(
"-n", "--network", action="store",
help=("Set network to regtest or mainnet. "
"Defaults to testnet while in alpha."))
# parser.add_argument(
# "--daemon", "-d", action="store_true",
# help="Run as daemon process")
args = parser.parse_args() args = parser.parse_args()
print(args)
if hasattr(args, 'debug'): if hasattr(args, 'debug'):
numeric_level = getattr(logging, 'DEBUG', None) numeric_level = getattr(logging, 'DEBUG', None)
@ -304,35 +270,35 @@ def main():
if command == 'importtrade': if command == 'importtrade':
if args.wormhole: if args.wormhole:
wormhole_importtrade() cli.wormhole_importtrade()
else: else:
if len(args.arguments) != 2: if len(args.arguments) != 2:
utils.throw("Usage: importtrade [tradeid] [hexstring]") utils.throw("Usage: importtrade [tradeid] [hexstring]")
tradeid = args.arguments[0] tradeid = args.arguments[0]
hexstr = args.arguments[1] hexstr = args.arguments[1]
importtrade(tradeid, hexstr) cli.importtrade(tradeid, hexstr)
elif command == 'exporttrade': elif command == 'exporttrade':
if len(args.arguments) < 1: if len(args.arguments) < 1:
utils.throw("Usage: exporttrade [tradeid]") utils.throw("Usage: exporttrade [tradeid]")
tradeid = args.arguments[0] tradeid = args.arguments[0]
exporttrade(tradeid, args.wormhole) cli.exporttrade(tradeid, args.wormhole)
elif command == "findtrade": elif command == "findtrade":
if len(args.arguments) < 1: if len(args.arguments) < 1:
utils.throw("Usage: findtrade [tradeid]") utils.throw("Usage: findtrade [tradeid]")
print("Finding trade") print("Finding trade")
key = args.arguments[0] key = args.arguments[0]
findtrade(key) cli.findtrade(key)
elif command == 'checktrade': elif command == 'checktrade':
if len(args.arguments) < 1: if len(args.arguments) < 1:
utils.throw("Usage: checktrade [tradeid]") utils.throw("Usage: checktrade [tradeid]")
tradeid = args.arguments[0] tradeid = args.arguments[0]
checktrade(tradeid) cli.checktrade(tradeid)
elif command == 'listtrades': elif command == 'listtrades':
listtrades() cli.listtrades()
# TODO: function to tell if tradeid already exists for newtrade # TODO: function to tell if tradeid already exists for newtrade
@ -341,31 +307,27 @@ def main():
utils.throw("Usage: newtrade [tradeid]") utils.throw("Usage: newtrade [tradeid]")
tradeid = args.arguments[0] tradeid = args.arguments[0]
if args.conf is None: if args.conf is None:
newtrade(tradeid, network=NETWORK, conf='cli') conf = 'cli'
else: else:
newtrade(tradeid, network=NETWORK, conf=args.conf) conf = args.conf
cli.newtrade(tradeid, network=NETWORK, conf=conf)
elif command == "daemon": elif command == "daemon":
# TODO: not implemented # TODO: not implemented
print("Run as daemon process") print("Run as daemon process")
# Ad hoc testing of workflow starts here # Ad hoc testing of workflow starts here
elif command == "step1": elif command == "step1":
tradeid = args.arguments[0] tradeid = args.arguments[0]
checkSellStatus(tradeid) cli.checkSellStatus(tradeid)
elif command == "step2": elif command == "step2":
tradeid = args.arguments[0] tradeid = args.arguments[0]
checkBuyStatus(tradeid) cli.checkBuyStatus(tradeid)
elif command == "step3": elif command == "step3":
# protocol = Protocol() # cli.protocol.generate(31)
# protocol.generate(31)
tradeid = args.arguments[0] tradeid = args.arguments[0]
checkSellStatus(tradeid) cli.checkSellStatus(tradeid)
elif command == "step4": elif command == "step4":
# generate(1) # cli.protocol.generate(1)
tradeid = args.arguments[0] tradeid = args.arguments[0]
checkBuyStatus(tradeid) cli.checkBuyStatus(tradeid)

View File

@ -5,11 +5,9 @@ from xcat.xcatconf import ADDRS
from xcat.trades import Contract, Trade 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
from xcat.db import DB import json
class Protocol(): class Protocol():
def __init__(self): def __init__(self):
self.bitcoinRPC = bitcoinProxy() self.bitcoinRPC = bitcoinProxy()
self.zcashRPC = zcashProxy() self.zcashRPC = zcashProxy()
@ -186,6 +184,22 @@ class Protocol():
"{0} {1}!".format(buy.amount, buy.currency)) "{0} {1}!".format(buy.amount, buy.currency))
return txs return txs
def seller_init(self, tradeid, trade, network):
secret = utils.generate_password()
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...")
# 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 {0}".format(trade.toJSON()))
return trade, secret
def initialize_trade(self, tradeid, **kwargs): def initialize_trade(self, tradeid, **kwargs):
trade = Trade() trade = Trade()
conf = kwargs['conf'] conf = kwargs['conf']
@ -195,9 +209,16 @@ class Protocol():
amounts = userInput.get_trade_amounts() amounts = userInput.get_trade_amounts()
print("AMOUNTS", amounts) print("AMOUNTS", amounts)
else: else:
init_addrs = ADDRS[conf]['initiator'] print("Conf in init trade", conf)
fulfill_addrs = ADDRS[conf]['fulfiller'] if conf == 'testnet' or conf == 'regtest':
amounts = ADDRS[conf]['amounts'] # If json is not passed on cli, use ADDR obj from xcatconf.py
conf = ADDRS[conf]
else:
# Allow for passing in multiple trades at a time
conf = json.loads(conf)[0]
init_addrs = conf['initiator']
fulfill_addrs = conf['fulfiller']
amounts = conf['amounts']
sell = amounts['sell'] sell = amounts['sell']
buy = amounts['buy'] buy = amounts['buy']
@ -214,24 +235,3 @@ class Protocol():
print(trade.sell.__dict__) print(trade.sell.__dict__)
print(trade.buy.__dict__) print(trade.buy.__dict__)
return tradeid, trade return tradeid, trade
def seller_init(self, tradeid, trade, network):
db = DB()
secret = utils.generate_password()
db.save_secret(tradeid, secret)
print("\nGenerated a secret preimage to lock funds. This will only "
"be stored locally: {0}".format(secret))
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...")
# 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 {0}".format(trade.toJSON()))
return trade

View File

@ -1,103 +0,0 @@
import xcat.zcash
import xcat.bitcoin
from xcat import *
htlcTrade = Trade()
print("Starting test of xcat...")
def get_initiator_addresses():
return {'bitcoin': 'myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp', 'zcash': 'tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ'}
def get_fulfiller_addresses():
return {'bitcoin': 'mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z', 'zcash': 'tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY'}
def initiate(trade):
# Get amounts
amounts = {"sell": {"currency": "bitcoin", "amount": "0.5"}, "buy": {"currency": "zcash", "amount": "1.12"}}
sell = amounts['sell']
buy = amounts['buy']
sell_currency = sell['currency']
buy_currency = buy['currency']
# Get addresses
init_addrs = get_initiator_addresses()
sell['initiator'] = init_addrs[sell_currency]
buy['initiator'] = init_addrs[buy_currency]
fulfill_addrs = get_fulfiller_addresses()
sell['fulfiller'] = fulfill_addrs[sell_currency]
buy['fulfiller'] = fulfill_addrs[buy_currency]
# initializing contract classes with addresses, currencies, and amounts
trade.sell = Contract(sell)
trade.buy = Contract(buy)
print(trade.sell.__dict__)
print(trade.buy.__dict__)
secret = generate_password()
print("Generating secret to lock funds:", secret)
save_secret(secret)
# TODO: Implement locktimes and mock block passage of time
sell_locktime = 2
buy_locktime = 4 # Must be more than first tx
create_sell_p2sh(trade, secret, sell_locktime)
txid = fund_sell_contract(trade)
print("Sent")
create_buy_p2sh(trade, secret, buy_locktime)
def 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)
if buy_p2sh_balance == 0:
print("Buy amt:", buy.amount)
txid = fund_buy_contract(trade)
print("Fund tx txid:", txid)
else:
raise ValueError("Sell p2sh not funded, buyer cannot redeem")
def redeem_one(trade):
buy = trade.buy
if trade.sell.get_status() == 'redeemed':
raise RuntimeError("Sell contract status was already redeemed before seller could redeem buyer's tx")
else:
secret = get_secret()
print("GETTING SECRET IN TEST:", secret)
tx_type, txid = redeem_p2sh(trade.buy, secret)
print("\nTX Type", tx_type)
setattr(trade.buy, tx_type, txid)
save(trade)
print("You have redeemed {0} {1}!".format(buy.amount, buy.currency))
def redeem_two(trade):
if trade.sell.get_status() == 'redeemed':
raise RuntimeError("Sell contract was redeemed before buyer could retrieve funds")
elif trade.buy.get_status() == 'refunded':
print("buy was refunded to buyer")
else:
# Buy contract is where seller disclosed secret in redeeming
if trade.buy.currency == 'bitcoin':
secret = bXcat.parse_secret(trade.buy.redeem_tx)
else:
secret = zXcat.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)
def generate_blocks(num):
bXcat.generate(num)
zXcat.generate(num)
initiate(htlcTrade)
fulfill(htlcTrade)
generate_blocks(6)
redeem_one(htlcTrade)
redeem_two(htlcTrade)
# addr = CBitcoinAddress('tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ')
# print(addr)
# # print(b2x('tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ'))
# print(b2x(addr))

View File

@ -92,11 +92,6 @@ if not os.path.exists(tmp_dir):
xcatjson = os.path.join(tmp_dir, 'xcat.json') xcatjson = os.path.join(tmp_dir, 'xcat.json')
def save_trade(trade):
with open(xcatjson, 'w+') as outfile:
json.dump(trade, outfile)
def get_trade(): def get_trade():
with open(xcatjson) as data_file: with open(xcatjson) as data_file:
xcatdb = json.load(data_file) xcatdb = json.load(data_file)
@ -113,16 +108,19 @@ def erase_trade():
except: except:
pass pass
# Dumping trade to json file for development and debugging
def save(trade): def save(trade):
# print("Saving trade") # print("Saving trade")
trade = { trade = {
'sell': trade.sell.__dict__, 'sell': trade.sell.__dict__,
'buy': trade.buy.__dict__, 'buy': trade.buy.__dict__,
'commitment': trade.commitment 'commitment': trade.commitment
} }
save_trade(trade) save_trade(trade)
def save_trade(trade):
with open(xcatjson, 'w+') as outfile:
json.dump(trade, outfile)
# Remove tmp files when trade is complete # Remove tmp files when trade is complete
def cleanup(tradeid): def cleanup(tradeid):

View File

@ -23,3 +23,8 @@ ADDRS = {
"amounts": {'buy': {'currency': 'zcash', 'amount': 0.02}, 'sell': {'currency': 'bitcoin', 'amount': 0.01}} "amounts": {'buy': {'currency': 'zcash', 'amount': 0.02}, 'sell': {'currency': 'bitcoin', 'amount': 0.01}}
} }
} }
NETWORK = 'testnet'
# Pass regtest trade data in on command line
# '[{"initiator": {"bitcoin": "mvc56qCEVj6p57xZ5URNC3v7qbatudHQ9b", "zcash": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc"}, "fulfiller": {"bitcoin": "moRt56gJQGDNK46Y6fYy2HbooKnQXrTGDN", "zcash": "tmK3rGzHDqa78MCwEicx9VcY9ZWX9gCF2nd"}, "amounts": {"buy": {"currency": "zcash", "amount": 0.02}, "sell": {"currency": "bitcoin", "amount": 0.01}}}]'

View File

@ -51,7 +51,8 @@ class zcashProxy():
redeemerAddr = CBitcoinAddress(redeemer) redeemerAddr = CBitcoinAddress(redeemer)
if type(commitment) == str: if type(commitment) == str:
commitment = x(commitment) commitment = x(commitment)
# h = sha256(secret) else:
raise ValueError("Commitment was not a string: {0}".format(commitment))
blocknum = self.zcashd.getblockcount() blocknum = self.zcashd.getblockcount()
print("Current blocknum on Zcash: ", blocknum) print("Current blocknum on Zcash: ", blocknum)
redeemblocknum = blocknum + locktime redeemblocknum = blocknum + locktime