From ee8dac6ee46108fd2890f7be24dad0025d1f52f4 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 2 Aug 2017 19:36:07 -0700 Subject: [PATCH 1/6] Get default addresses from xcatconf.py in top level dir --- xcat/cli.py | 30 +++++++++++++----------------- xcat/protocol.py | 20 ++++++++++++++------ xcat/utils.py | 8 ++++++++ xcatconf.py | 5 +++++ 4 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 xcatconf.py diff --git a/xcat/cli.py b/xcat/cli.py index 205cc73..d6e5e6c 100644 --- a/xcat/cli.py +++ b/xcat/cli.py @@ -156,12 +156,11 @@ def checktrade(tradeid): role = 'buyer' checkBuyStatus(tradeid) -def newtrade(tradeid): - erase_trade() - role = 'seller' +def newtrade(tradeid, **kwargs): print("Creating new XCAT trade...") - trade = seller_init(tradeid) - print("Use 'xcat exporttrade to export the trade and sent to the buyer.'") + erase_trade() + trade = seller_init(tradeid, **kwargs) + print("Use 'xcat exporttrade [tradeid] to export the trade and sent to the buyer.'") save_state(trade, tradeid) def main(): @@ -178,20 +177,20 @@ def main(): parser.add_argument("command", action="store", help="list commands") parser.add_argument("arguments", action="store", nargs="*", help="add arguments") parser.add_argument("-w", "--wormhole", action="store_true", help="Transfer trade data through magic-wormhole") + parser.add_argument("-n", "--network", action="store", help="Set network to regtest or mainnet. Defaults to testnet while in beta.") + parser.add_argument("-c", "--conf", action="store", help="Use default trade data in conf file.") # parser.add_argument("--daemon", "-d", action="store_true", help="Run as daemon process") # TODO: function to view available trades # TODO: function to tell if tradeid already exists for newtrade args = parser.parse_args() - - # how to hold state of role + print(args) command = args.command if command == 'importtrade': if args.wormhole: wormhole_importtrade() else: if len(args.arguments) != 2: - print("Usage: importtrade [tradeid] [hexstring]") - exit() + throw("Usage: importtrade [tradeid] [hexstring]") tradeid = args.arguments[0] hexstr = args.arguments[1] importtrade(tradeid, hexstr) @@ -206,13 +205,11 @@ def main(): tradeid = args.arguments[0] checktrade(tradeid) elif command == 'newtrade': - print("in new trade") - try: - tradeid = args.arguments[0] - newtrade(tradeid) - except: - tradeid = userInput.enter_trade_id() - newtrade(tradeid) + if len(args.arguments) < 1: + throw("Usage: newtrade [tradeid]") + tradeid = args.arguments[0] + print("network, conf", args.network, args.conf) + newtrade(tradeid, network=args.network, conf=args.conf) elif command == "daemon": #TODO: implement print("Run as daemon process") @@ -227,7 +224,6 @@ def main(): elif command == "step3": tradeid = args.arguments[0] checkSellStatus(tradeid) - # TODO: When trade finishes, delete wormhole file in tmp dir. elif command == "step4": tradeid = args.arguments[0] checkBuyStatus(tradeid) diff --git a/xcat/protocol.py b/xcat/protocol.py index f674936..69b9fbf 100644 --- a/xcat/protocol.py +++ b/xcat/protocol.py @@ -167,22 +167,30 @@ def buyer_fulfill(trade): print("Please wait for the seller to remove your funds from escrow to complete the trade.") print_trade('buyer') -def seller_init(tradeid): +def seller_init(tradeid, **kwargs): + print(*kwargs) + if kwargs['network'] == 'regtest': + init_addrs = REGTEST_INIT_ADDRS + fulfill_addrs = REGTEST_FULFILL_ADDRS + elif kwargs['network'] == 'testnet': + init_addrs = TESTNET_INIT_ADDRS + fulfill_addrs = TESTNET_FULFILL_ADDRS + else: + init_addrs = userInput.get_initiator_addresses() + fulfill_addrs = userInput.get_fulfiller_addresses() + trade = Trade() - # TODO: pass in amounts, or get from cli. {"amounts": {"buy": {}, "sell": {}}} amounts = userInput.get_trade_amounts() + sell = amounts['sell'] buy = amounts['buy'] sell_currency = sell['currency'] buy_currency = buy['currency'] - # Get addresses - init_addrs = userInput.get_initiator_addresses() sell['initiator'] = init_addrs[sell_currency] buy['initiator'] = init_addrs[buy_currency] - - fulfill_addrs = userInput.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) diff --git a/xcat/utils.py b/xcat/utils.py index 4b4e4da..c2a5793 100644 --- a/xcat/utils.py +++ b/xcat/utils.py @@ -77,6 +77,14 @@ def sha256(secret): h = hashlib.sha256(preimage).digest() return h +############################################ +######## Error handling for CLI ############ +############################################ + +def throw(err): + print(err) + exit() + ############################################# ######### xcat.json temp file ############# ############################################# diff --git a/xcatconf.py b/xcatconf.py new file mode 100644 index 0000000..91b2817 --- /dev/null +++ b/xcatconf.py @@ -0,0 +1,5 @@ + + +# Replace with your own addresses +REGTEST_INIT_ADDRS = {"bitcoin": "mvc56qCEVj6p57xZ5URNC3v7qbatudHQ9b", "zcash": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc"} +REGTEST_FULFILL_ADDRS = {"bitcoin": "moRt56gJQGDNK46Y6fYy2HbooKnQXrTGDN", "zcash": "tmK3rGzHDqa78MCwEicx9VcY9ZWX9gCF2nd"} From 398e2096213deac04dbca5e7a4d5ca7d14710140 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 2 Aug 2017 19:36:14 -0700 Subject: [PATCH 2/6] Modify description --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8404c0e..1dfe29a 100644 --- a/setup.py +++ b/setup.py @@ -8,9 +8,9 @@ setup( entry_points = { "console_scripts": ['xcat = xcat.cli:main'] }, - description="Xcat is a package to facilitate cross-chain atomic transactions.", + description="Xcat is a package that creates cross-chain atomic transactions.", author="arcalinea and arielgabizon", - author_email="xcat@z.cash", + author_email="arcalinea@z.cash", license="MIT", url="http://github.com/zcash/xcat", packages=find_packages() From 73f7d02dd776b5bfb1fb486a69d4c0035dd14ee2 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 2 Aug 2017 19:36:24 -0700 Subject: [PATCH 3/6] Gitignore .tmp dir --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a06fbbd..b4b5438 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.pyc -xcatdb/ xcat.egg-info/ +.tmp/ From 21b240ff69897c9b22b940eedb7c1619defb0aaa Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 2 Aug 2017 20:56:56 -0700 Subject: [PATCH 4/6] Pass in through -conf --- xcat/cli.py | 9 +++------ xcat/protocol.py | 14 +++++++------- xcatconf.py | 25 +++++++++++++++++++++---- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/xcat/cli.py b/xcat/cli.py index d6e5e6c..2544c86 100644 --- a/xcat/cli.py +++ b/xcat/cli.py @@ -177,8 +177,8 @@ def main(): parser.add_argument("command", action="store", help="list commands") parser.add_argument("arguments", action="store", nargs="*", help="add arguments") parser.add_argument("-w", "--wormhole", action="store_true", help="Transfer trade data through magic-wormhole") - parser.add_argument("-n", "--network", action="store", help="Set network to regtest or mainnet. Defaults to testnet while in beta.") 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 beta.") # parser.add_argument("--daemon", "-d", action="store_true", help="Run as daemon process") # TODO: function to view available trades # TODO: function to tell if tradeid already exists for newtrade @@ -189,8 +189,7 @@ def main(): if args.wormhole: wormhole_importtrade() else: - if len(args.arguments) != 2: - throw("Usage: importtrade [tradeid] [hexstring]") + if len(args.arguments) != 2: throw("Usage: importtrade [tradeid] [hexstring]") tradeid = args.arguments[0] hexstr = args.arguments[1] importtrade(tradeid, hexstr) @@ -205,8 +204,7 @@ def main(): tradeid = args.arguments[0] checktrade(tradeid) elif command == 'newtrade': - if len(args.arguments) < 1: - throw("Usage: newtrade [tradeid]") + if len(args.arguments) < 1: throw("Usage: newtrade [tradeid]") tradeid = args.arguments[0] print("network, conf", args.network, args.conf) newtrade(tradeid, network=args.network, conf=args.conf) @@ -218,7 +216,6 @@ def main(): tradeid = args.arguments[0] checkSellStatus(tradeid) elif command == "step2": - # trade = get_trade() tradeid = args.arguments[0] checkBuyStatus(tradeid) elif command == "step3": diff --git a/xcat/protocol.py b/xcat/protocol.py index 69b9fbf..c9b946a 100644 --- a/xcat/protocol.py +++ b/xcat/protocol.py @@ -168,13 +168,13 @@ def buyer_fulfill(trade): print_trade('buyer') def seller_init(tradeid, **kwargs): - print(*kwargs) - if kwargs['network'] == 'regtest': - init_addrs = REGTEST_INIT_ADDRS - fulfill_addrs = REGTEST_FULFILL_ADDRS - elif kwargs['network'] == 'testnet': - init_addrs = TESTNET_INIT_ADDRS - fulfill_addrs = TESTNET_FULFILL_ADDRS + conf = kwargs['conf'] + if conf.upper() == 'REGTEST': + init_addrs = REGTEST['initiator'] + fulfill_addrs = REGTEST['fulfiller'] + elif conf.upper() == 'TESTNET': + init_addrs = TESTNET['initiator'] + fulfill_addrs = TESTNET['fulfiller'] else: init_addrs = userInput.get_initiator_addresses() fulfill_addrs = userInput.get_fulfiller_addresses() diff --git a/xcatconf.py b/xcatconf.py index 91b2817..4035d54 100644 --- a/xcatconf.py +++ b/xcatconf.py @@ -1,5 +1,22 @@ - - # Replace with your own addresses -REGTEST_INIT_ADDRS = {"bitcoin": "mvc56qCEVj6p57xZ5URNC3v7qbatudHQ9b", "zcash": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc"} -REGTEST_FULFILL_ADDRS = {"bitcoin": "moRt56gJQGDNK46Y6fYy2HbooKnQXrTGDN", "zcash": "tmK3rGzHDqa78MCwEicx9VcY9ZWX9gCF2nd"} +REGTEST = { + "initiator": { + "bitcoin": "mvc56qCEVj6p57xZ5URNC3v7qbatudHQ9b", + "zcash": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc" + }, + "fulfiller": { + "bitcoin": "moRt56gJQGDNK46Y6fYy2HbooKnQXrTGDN", + "zcash": "tmK3rGzHDqa78MCwEicx9VcY9ZWX9gCF2nd" + } +} + +TESTNET = { + "initiator": { + "bitcoin": "mvc56qCEVj6p57xZ5URNC3v7qbatudHQ9b", + "zcash": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc" + }, + "fulfiller": { + "bitcoin": "mgRG44X4PQC1ZCA4V654UZjJGJ3pxbApj2", + "zcash": "tmLZu7MdjNdA6vbPTNTwdsZo91LnnrVTYB5" + } +} From 99a3ac71fcc0d36f1f83cf28cb9152a671210523 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 2 Aug 2017 21:41:55 -0700 Subject: [PATCH 5/6] Clean up printing to console --- xcat/bitcoinRPC.py | 40 +++++++++++++++------------------------- xcat/cli.py | 22 ++++++++-------------- xcat/protocol.py | 24 ++++++++++-------------- xcat/utils.py | 1 - xcat/zcashRPC.py | 38 +++++++++----------------------------- 5 files changed, 42 insertions(+), 83 deletions(-) diff --git a/xcat/bitcoinRPC.py b/xcat/bitcoinRPC.py index 8c97b35..0b6f7d6 100644 --- a/xcat/bitcoinRPC.py +++ b/xcat/bitcoinRPC.py @@ -27,9 +27,7 @@ def validateaddress(addr): return bitcoind.validateaddress(addr) def find_secret(p2sh, fundtx_input): - print("fundtx_input:", fundtx_input) txs = bitcoind.call('listtransactions', "*", 20, 0, True) - print('Length of txs from listtransactions():', len(txs)) for tx in txs: raw = bitcoind.gettransaction(lx(tx['txid']))['hex'] decoded = bitcoind.decoderawtransaction(raw) @@ -43,12 +41,13 @@ def find_secret(p2sh, fundtx_input): return def parse_secret(txid): - decoded = bitcoind.getrawtransaction(lx(txid), 1) - print("Decoded", decoded) - # decoded = bitcoind.decoderawtransaction(raw) - asm = decoded['vin'][0]['scriptSig']['asm'].split(" ") - secret = asm[2] - print("Found secret: ", secret) + raw = zcashd.gettransaction(txid, True)['hex'] + decoded = zcashd.call('decoderawtransaction', raw) + scriptSig = decoded['vin'][0]['scriptSig'] + asm = scriptSig['asm'].split(" ") + pubkey = asm[1] + secret = x2s(asm[2]) + redeemPubkey = P2PKHBitcoinAddress.from_pubkey(x(pubkey)) return secret def get_keys(funder_address, redeemer_address): @@ -68,14 +67,13 @@ def hashtimelockcontract(funder, redeemer, commitment, locktime): commitment = x(commitment) # h = sha256(secret) blocknum = bitcoind.getblockcount() - print("Current blocknum", blocknum) + print("Current blocknum on Bitcoin: ", blocknum) redeemblocknum = blocknum + locktime - print("REDEEMBLOCKNUM BITCOIN", redeemblocknum) - print("COMMITMENT", commitment) + print("Redeemblocknum on Bitcoin: ", redeemblocknum) redeemScript = CScript([OP_IF, OP_SHA256, commitment, OP_EQUALVERIFY,OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG]) - print("Redeem script for p2sh contract on Bitcoin blockchain:", b2x(redeemScript)) + # print("Redeem script for p2sh contract on Bitcoin blockchain: {0}".format(b2x(redeemScript))) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) @@ -105,7 +103,7 @@ def get_fund_status(p2sh): bitcoind.importaddress(p2sh, "", False) amount = bitcoind.getreceivedbyaddress(p2sh, 0) amount = amount/COIN - print("Amount in bitcoin get_fund_status", amount, p2sh) + print("Amount in bitcoin p2sh: ", amount, p2sh) if amount > 0: return 'funded' else: @@ -152,7 +150,7 @@ def redeem_contract(contract, secret): quit() fundtx = find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN - print("Found fundtx:", fundtx) + # print("Found fund_tx: ", fundtx) p2sh = P2SHBitcoinAddress(p2sh) if fundtx['address'] == p2sh: print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) @@ -170,21 +168,17 @@ def redeem_contract(contract, secret): # TODO: protect privkey better, separate signing from rawtx creation privkey = bitcoind.dumpprivkey(redeemPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) - print("SECRET", secret) preimage = secret.encode('utf-8') txin.scriptSig = CScript([sig, privkey.pub, preimage, OP_TRUE, zec_redeemScript]) - print("txin.scriptSig", b2x(txin.scriptSig)) + # print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() - print('Redeem txhex', b2x(tx.serialize())) + print('Raw redeem transaction hex: ', b2x(tx.serialize())) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) - print("script verified, sending raw tx") + print("Script verified, sending raw transaction...") txid = bitcoind.sendrawtransaction(tx) fund_tx = str(fundtx['outpoint']) redeem_tx = b2x(lx(b2x(txid))) - print("Returning fund_tx", fund_tx) - print("Txid of submitted redeem tx: ", redeem_tx) - print("TXID SUCCESSFULLY REDEEMED") return {"redeem_tx": redeem_tx, "fund_tx": fund_tx} else: print("nLocktime exceeded, refunding") @@ -192,9 +186,6 @@ def redeem_contract(contract, secret): txid = bitcoind.sendtoaddress(refundPubKey, fundtx['amount'] - FEE) fund_tx = str(fundtx['outpoint']) refund_tx = b2x(lx(b2x(txid))) - print("Returning fund_tx", fund_tx) - print("Txid of submitted refund tx: ", refund_tx) - print("TXID SUCCESSFULLY REDEEMED") return {"refund_tx": refund_tx, "fund_tx": fund_tx} else: print("No contract for this p2sh found in database", p2sh) @@ -222,7 +213,6 @@ def find_transaction_to_address(p2sh): for tx in txs: if tx['address'] == CBitcoinAddress(p2sh): print("Found tx to p2sh", p2sh) - print(tx) return tx def new_bitcoin_addr(): diff --git a/xcat/cli.py b/xcat/cli.py index 2544c86..8555f10 100644 --- a/xcat/cli.py +++ b/xcat/cli.py @@ -13,7 +13,7 @@ def save_state(trade, tradeid): def checkSellStatus(tradeid): trade = db.get(tradeid) status = seller_check_status(trade) - print("In checkSellStatus", status) + print("Trade status: {0}\n".format(status)) if status == 'init': userInput.authorize_fund_sell(trade) fund_tx = fund_sell_contract(trade) @@ -22,11 +22,9 @@ def checkSellStatus(tradeid): save_state(trade, tradeid) elif status == 'buyerFunded': secret = db.get_secret(tradeid) - print("SECRET found in checksellactions", secret) + print("Retrieved secret to redeem funds for {0}: {1}".format(tradeid, secret)) txs = seller_redeem_p2sh(trade, secret) - print("TXS IN SELLER REDEEM BUYER TX", txs) trade.buy.redeem_tx = txs['redeem_tx'] - print("TRADE SUCCESSFULLY REDEEMED", trade) save_state(trade, tradeid) # Remove from db? Or just from temporary file storage cleanup(tradeid) @@ -71,7 +69,7 @@ def seller_check_status(trade): def checkBuyStatus(tradeid): trade = db.get(tradeid) status = buyer_check_status(trade) - print("In checkBuyStatus", status) + 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': @@ -81,19 +79,16 @@ def checkBuyStatus(tradeid): print("Trade commitment", trade.commitment) # if verify_p2sh(trade): fund_tx = fund_contract(trade.buy) - print("\nBuyer's funding tx: ", fund_tx) + print("\nYou sent this funding tx: ", fund_tx) trade.buy.fund_tx = fund_tx save_state(trade, tradeid) elif status == 'sellerRedeemed': - print("FUND TX CLI", trade.buy.fund_tx) secret = find_secret_from_fundtx(trade.buy.currency, trade.buy.p2sh, trade.buy.fund_tx) - print("Secret in cli", secret) if secret != None: - print("Found secret", secret) + print("Found secret on blockchain in seller's redeem tx: ", secret) txs = redeem_p2sh(trade.sell, secret) - print("TXS IN SELLER REDEEMED", txs) trade.sell.redeem_tx = txs['redeem_tx'] - print("TXID after buyer redeem", trade.sell.redeem_tx) + print("Redeem txid: ", trade.sell.redeem_tx) save_state(trade, tradeid) print("XCAT trade complete!") else: @@ -160,7 +155,7 @@ def newtrade(tradeid, **kwargs): print("Creating new XCAT trade...") erase_trade() trade = seller_init(tradeid, **kwargs) - print("Use 'xcat exporttrade [tradeid] to export the trade and sent to the buyer.'") + print("\nUse 'xcat exporttrade [tradeid]' to export the trade and sent to the buyer.\n") save_state(trade, tradeid) def main(): @@ -183,7 +178,7 @@ def main(): # TODO: function to view available trades # TODO: function to tell if tradeid already exists for newtrade args = parser.parse_args() - print(args) + command = args.command if command == 'importtrade': if args.wormhole: @@ -206,7 +201,6 @@ def main(): elif command == 'newtrade': if len(args.arguments) < 1: throw("Usage: newtrade [tradeid]") tradeid = args.arguments[0] - print("network, conf", args.network, args.conf) newtrade(tradeid, network=args.network, conf=args.conf) elif command == "daemon": #TODO: implement diff --git a/xcat/protocol.py b/xcat/protocol.py index c9b946a..76446eb 100644 --- a/xcat/protocol.py +++ b/xcat/protocol.py @@ -10,7 +10,6 @@ import xcat.db as db from xcatconf import * def find_secret_from_fundtx(currency, p2sh, fundtx): - print("Fund tx in protocol.py", fundtx) if currency == 'bitcoin': secret = bitcoinRPC.find_secret(p2sh, fundtx) else: @@ -48,7 +47,6 @@ def check_fund_status(currency, address): # print("Compiled p2sh for htlc does not match what seller sent.") def create_htlc(currency, funder, redeemer, commitment, locktime): - print("Commitment in create_htlc", commitment) if currency == 'bitcoin': sell_p2sh = bitcoinRPC.hashtimelockcontract(funder, redeemer, commitment, locktime) else: @@ -60,12 +58,10 @@ def fund_htlc(currency, p2sh, amount): txid = bitcoinRPC.fund_htlc(p2sh, amount) else: txid = zcashRPC.fund_htlc(p2sh, amount) - print("Fund_htlc txid", txid ) return txid def fund_contract(contract): txid = fund_htlc(contract.currency, contract.p2sh, contract.amount) - print("TXID coming back from fund_contract", txid) return txid def fund_sell_contract(trade): @@ -89,8 +85,7 @@ def create_sell_p2sh(trade, commitment, locktime): def create_buy_p2sh(trade, commitment, locktime): ## CREATE BUY CONTRACT buy = trade.buy - print("Now creating buy contract on the {0} blockchain where you will wait for the buyer to send funds...".format(buy.currency)) - print("HTLC DETAILS", buy.currency, buy.fulfiller, buy.initiator, commitment, locktime) + 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) @@ -98,7 +93,7 @@ def create_buy_p2sh(trade, commitment, locktime): setattr(trade.buy, 'redeemScript', buy_contract['redeemScript']) setattr(trade.buy, 'redeemblocknum', buy_contract['redeemblocknum']) setattr(trade.buy, 'locktime', buy_contract['locktime']) - print("Now contact the buyer and tell them to send funds to this p2sh: ", 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) @@ -168,13 +163,14 @@ def buyer_fulfill(trade): print_trade('buyer') def seller_init(tradeid, **kwargs): - conf = kwargs['conf'] - if conf.upper() == 'REGTEST': - init_addrs = REGTEST['initiator'] - fulfill_addrs = REGTEST['fulfiller'] - elif conf.upper() == 'TESTNET': - init_addrs = TESTNET['initiator'] - fulfill_addrs = TESTNET['fulfiller'] + if kwargs['conf']: + conf = kwargs['conf'].upper() + if conf.upper() == 'REGTEST': + init_addrs = REGTEST['initiator'] + fulfill_addrs = REGTEST['fulfiller'] + elif conf.upper() == 'TESTNET': + init_addrs = TESTNET['initiator'] + fulfill_addrs = TESTNET['fulfiller'] else: init_addrs = userInput.get_initiator_addresses() fulfill_addrs = userInput.get_fulfiller_addresses() diff --git a/xcat/utils.py b/xcat/utils.py index c2a5793..3bb0230 100644 --- a/xcat/utils.py +++ b/xcat/utils.py @@ -92,7 +92,6 @@ def throw(err): xcatjson = os.path.join(ROOT_DIR, '.tmp/xcat.json') def save_trade(trade): - print("Trade in save_trade", trade) with open(xcatjson, 'w+') as outfile: json.dump(trade, outfile) diff --git a/xcat/zcashRPC.py b/xcat/zcashRPC.py index 4fff6c5..162ae92 100644 --- a/xcat/zcashRPC.py +++ b/xcat/zcashRPC.py @@ -48,20 +48,19 @@ def hashtimelockcontract(funder, redeemer, commitment, locktime): commitment = x(commitment) # h = sha256(secret) blocknum = zcashd.getblockcount() - print("Current blocknum", blocknum) + print("Current blocknum on Zcash: ", blocknum) redeemblocknum = blocknum + locktime - print("REDEEMBLOCKNUM ZCASH", redeemblocknum) - print("COMMITMENT on zxcat", commitment) + print("Redeemblocknum on Zcash: ", redeemblocknum) # can rm op_dup and op_hash160 if you replace addrs with pubkeys (as raw hex/bin data?), and can rm last op_equalverify (for direct pubkey comparison) zec_redeemScript = CScript([OP_IF, OP_SHA256, commitment, OP_EQUALVERIFY,OP_DUP, OP_HASH160, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160, funderAddr, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG]) - print("Redeem script for p2sh contract on Zcash blockchain:", b2x(zec_redeemScript)) + # print("Redeem script for p2sh contract on Zcash blockchain: ", b2x(zec_redeemScript)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) - print("p2sh computed", p2sh) + print("p2sh computed: ", p2sh) # Import address as soon as you create it zcashd.importaddress(p2sh, "", False) # Returning all this to be saved locally in p2sh.json @@ -73,17 +72,13 @@ def fund_htlc(p2sh, amount): zcashd.importaddress(p2sh, "", False) fund_txid = zcashd.sendtoaddress(p2sh, send_amount) txid = b2x(lx(b2x(fund_txid))) - print("txid at end of fund_htlc in zcashRPC", txid) - # print("Dif version of txid", b2x(lx(fund_txid))) return txid # Following two functions are about the same def check_funds(p2sh): zcashd.importaddress(p2sh, "", False) - print("Imported address", p2sh) # Get amount in address amount = zcashd.getreceivedbyaddress(p2sh, 0) - print("Amount in address", amount) amount = amount/COIN return amount @@ -91,7 +86,7 @@ def get_fund_status(p2sh): zcashd.importaddress(p2sh, "", False) amount = zcashd.getreceivedbyaddress(p2sh, 0) amount = amount/COIN - print("Amount in zcash get_fund_status", amount, p2sh) + print("Amount in zcash p2sh: ", amount, p2sh) if amount > 0: return 'funded' else: @@ -107,17 +102,13 @@ def find_transaction_to_address(p2sh): for tx in txs: if tx['address'] == CBitcoinAddress(p2sh): print("Found tx to p2sh", p2sh) - print(tx) return tx def find_secret(p2sh, fundtx_input): - print("fundtx_input:", fundtx_input) txs = zcashd.call('listtransactions', "*", 20, 0, True) - print('Length of txs from listtransactions():', len(txs)) for tx in txs: raw = zcashd.gettransaction(lx(tx['txid']))['hex'] decoded = zcashd.decoderawtransaction(raw) - print("TXINFO", decoded['vin'][0]) if('txid' in decoded['vin'][0]): sendid = decoded['vin'][0]['txid'] if (sendid == fundtx_input ): @@ -134,22 +125,19 @@ def parse_secret(txid): pubkey = asm[1] secret = x2s(asm[2]) redeemPubkey = P2PKHBitcoinAddress.from_pubkey(x(pubkey)) - print('Veryify redeemPubkey: ', redeemPubkey) - print("Found secret in parse_secret:", secret) return secret def redeem_contract(contract, secret): # How to find redeemScript and redeemblocknum from blockchain? - print("Contract in redeem contract", contract.__dict__) p2sh = contract.p2sh #checking there are funds in the address amount = check_funds(p2sh) if(amount == 0): - print("address ", p2sh, " not funded") + print("Address ", p2sh, " not funded") quit() fundtx = find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN - print("Found fundtx:", fundtx) + # print("Found fund_tx: ", fundtx) p2sh = P2SHBitcoinAddress(p2sh) if fundtx['address'] == p2sh: print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) @@ -176,18 +164,13 @@ def redeem_contract(contract, secret): print("SECRET", secret) preimage = secret.encode('utf-8') txin.scriptSig = CScript([sig, privkey.pub, preimage, OP_TRUE, zec_redeemScript]) - - print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() - print('Redeem txhex', b2x(tx.serialize())) + print('Raw redeem transaction hex: ', b2x(tx.serialize())) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) - print("script verified, sending raw tx") + print("Script verified, sending raw redeem transaction...") txid = zcashd.sendrawtransaction(tx) redeem_tx = b2x(lx(b2x(txid))) fund_tx = str(fundtx['outpoint']) - print("Returning fund_tx", fund_tx) - print("Txid of submitted redeem tx: ", redeem_tx) - print("TXID SUCCESSFULLY REDEEMED") return {"redeem_tx": redeem_tx, "fund_tx": fund_tx} else: print("nLocktime exceeded, refunding") @@ -196,9 +179,6 @@ def redeem_contract(contract, secret): txid = zcashd.sendtoaddress(refundPubKey, fundtx['amount'] - FEE) refund_tx = b2x(lx(b2x(txid))) fund_tx = str(fundtx['outpoint']) - print("Returning fund_tx", fund_tx) - print("Txid of submitted refund tx: ", refund_tx) - print("TXID SUCCESSFULLY REDEEMED") return {"refund_tx": refund_tx, "fund_tx": fund_tx} else: print("No contract for this p2sh found in database", p2sh) From a8540b8cbe778d627098c5e03a4782fa4f566b81 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Wed, 2 Aug 2017 21:42:02 -0700 Subject: [PATCH 6/6] Update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 018ce43..867f7ab 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,15 @@ Since this is beta software that is still under active development, we recommend We use the term "seller" for whoever initiates the trade, and "buyer" for whoever fulfills the other end. +### Seller Setup: + +To start a trade using default addresses, edit the buyer and seller addresses for the chosen network in `xcatconf.py`. You will initiate the trade using these default addresses by passing in the variable through a `-conf` flag. + ### Seller: -To initiate a new trade, the seller enters all the necessary trade data and saves it under a tradeid. We will use the tradeid "testtrade" for this example. The amounts being traded will have to be agreed upon in advance, and the seller will need the buyer's destination addresses on both chains. +To initiate a new trade, the seller enters all the necessary trade data and saves it under a tradeid. We will use the tradeid "testtrade" for this example. The amounts being traded will have to be agreed upon in advance, and the seller will need the buyer's destination addresses on both chains. The `-c` field will pass in the name of the network addresses set in `xcatconf.py`. (If addresses are not set, initiator addresses are generated on your computer, and you can enter the buyer's addresses on the command line.) -`xcat newtrade testtrade` +`xcat -c=regtest newtrade testtrade` After creating, the seller exports the trade data encoded as a hex string to transfer the terms of the trade to the buyer. They can send this hex string to the buyer through email or any other channel, but there is also built-in support to transfer the data directly between two computers through [magic-wormhole](https://github.com/warner/magic-wormhole).