From 043958b840d0592709d315006bc023f45791c952 Mon Sep 17 00:00:00 2001 From: Jay Graber Date: Fri, 28 Jul 2017 13:57:44 -0700 Subject: [PATCH] Get working again --- bXcat.py | 29 ++++++++++++++--------------- cli.py | 13 ++++++++----- trades.py | 4 +--- utils.py | 43 +++---------------------------------------- xcat.py | 8 ++++++-- zXcat.py | 10 +++++++--- 6 files changed, 39 insertions(+), 68 deletions(-) diff --git a/bXcat.py b/bXcat.py index 379eeb0..7005c78 100644 --- a/bXcat.py +++ b/bXcat.py @@ -20,12 +20,13 @@ import zcash import zcash.rpc import pprint, json +from zXcat import parse_script + # SelectParams('testnet') SelectParams('regtest') bitcoind = bitcoin.rpc.Proxy() FEE = 0.001*COIN -zcashd = zcash.rpc.Proxy() def validateaddress(addr): return bitcoind.validateaddress(addr) @@ -50,12 +51,15 @@ def privkey(address): def hashtimelockcontract(funder, redeemer, commitment, locktime): funderAddr = CBitcoinAddress(funder) redeemerAddr = CBitcoinAddress(redeemer) + if type(commitment) == str: + commitment = x(commitment) # h = sha256(secret) blocknum = bitcoind.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + locktime print("REDEEMBLOCKNUM BITCOIN", redeemblocknum) - redeemScript = CScript([OP_IF, OP_SHA256, x(commitment), OP_EQUALVERIFY,OP_DUP, OP_HASH160, + print("COMMITMENT", commitment) + 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)) @@ -63,7 +67,8 @@ def hashtimelockcontract(funder, redeemer, commitment, locktime): # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) - return {'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(redeemScript), 'redeemer': redeemer, 'funder': funder} + print("p2sh computed", p2sh) + return {'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(redeemScript), 'redeemer': redeemer, 'funder': funder, 'locktime': locktime} def fund_htlc(p2sh, amount): send_amount = float(amount) * COIN @@ -111,8 +116,8 @@ def auto_redeem(contract, secret): print("Parsing script for auto_redeem...") scriptarray = parse_script(contract.redeemScript) redeemblocknum = scriptarray[8] - redeemPubkey = scriptarray[6] - refundPubkey = scriptarray[13] + redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6])) + refundPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[13])) # How to find redeemScript and redeemblocknum from blockchain? print("Contract in auto redeem", contract.__dict__) p2sh = contract.p2sh @@ -132,12 +137,13 @@ def auto_redeem(contract, secret): # redeemblocknum = find_redeemblocknum(contract) blockcount = bitcoind.getblockcount() print("\nCurrent blocknum at time of redeem on Bitcoin:", blockcount) - if blockcount < redeemblocknum: + if blockcount < int(redeemblocknum): # redeemPubKey = find_redeemAddr(contract) print('redeemPubKey', redeemPubKey) else: print("nLocktime exceeded, refunding") - redeemPubKey = find_refundAddr(contract) + # refundPubKey = find_refundAddr(contract) + redeemPubKey = refundPubkey print('refundPubKey', redeemPubKey) # redeemPubKey = CBitcoinAddress.from_scriptPubKey(redeemPubKey) # exit() @@ -150,7 +156,7 @@ def auto_redeem(contract, secret): # nLockTime needs to be at least as large as parameter of CHECKLOCKTIMEVERIFY for script to verify # TODO: these things like redeemblocknum should really be properties of a tx class... # Need: redeemblocknum, zec_redeemScript, secret (for creator...), txid, redeemer... - if blockcount >= redeemblocknum: + if blockcount >= int(redeemblocknum): print("\nLocktime exceeded") tx.nLockTime = redeemblocknum # Ariel: This is only needed when redeeming with the timelock sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL) @@ -234,13 +240,6 @@ def redeem_contract(contract, secret): else: print("No contract for this p2sh found in database", p2sh) -# takes hex and returns array of decoded script op codes -# This seems to be a costly operation, minimize frequency of calls. -def parse_script(script_hex): - redeemScript = zcashd.decodescript(script_hex) - scriptarray = redeemScript['asm'].split(' ') - return scriptarray - def find_redeemblocknum(contract): scriptarray = parse_script(contract.redeemScript) redeemblocknum = scriptarray[8] diff --git a/cli.py b/cli.py index cf287b1..0abcd3a 100644 --- a/cli.py +++ b/cli.py @@ -22,15 +22,18 @@ def checkSellStatus(trade): elif trade.buy.get_status() == 'redeemed': print("You have already redeemed the p2sh on the second chain of this trade.") - +# TODO: function to calculate appropriate locktimes between chains def checkBuyStatus(trade): if trade.sell.get_status() == 'funded' and trade.buy.get_status() != 'redeemed': print("One active trade available, fulfilling buyer contract...") # they should calculate redeemScript for themselves + print("Trade commitment", trade.commitment) + # TODO: which block to start computation from? htlc = create_htlc(trade.buy.currency, trade.buy.fulfiller, trade.buy.initiator, trade.commitment, trade.buy.locktime) - print("Buyer p2sh:", htlc['p2sh']) + buyer_p2sh = htlc['p2sh'] + print("Buyer p2sh:", buyer_p2sh) # If the two p2sh match... - if buyer_p2sh == contract.buy.p2sh: + if buyer_p2sh == trade.buy.p2sh: fund_tx = fund_contract(trade.buy) trade.buy.fund_tx = fund_tx print("trade buy with redeemscript?", trade.buy.__dict__) @@ -91,7 +94,7 @@ if __name__ == '__main__': erase_trade() role = 'seller' print("Creating new XCAT trade...") - trade = seller_initiate(Trade()) + trade = seller_init(Trade()) # Save it to leveldb db.create(trade) elif command == "daemon": @@ -106,7 +109,7 @@ if __name__ == '__main__': elif command == "step1": erase_trade() print("Creating new XCAT trade...") - trade = seller_initiate(Trade()) + trade = seller_init(Trade()) # Save it to leveldb save_state(trade) elif command == "step2": diff --git a/trades.py b/trades.py index 6330baf..b1e2077 100644 --- a/trades.py +++ b/trades.py @@ -14,7 +14,7 @@ class Trade(object): class Contract(object): def __init__(self, data): # Keep track of funding and redeem tx? - allowed = ('fulfiller', 'initiator', 'currency', 'p2sh', 'amount', 'fund_tx', 'redeem_tx', 'secret', 'redeemScript', 'redeemblocknum') + allowed = ('fulfiller', 'initiator', 'currency', 'p2sh', 'amount', 'fund_tx', 'redeem_tx', 'secret', 'redeemScript', 'redeemblocknum', 'locktime') for key in data: if key in allowed: setattr(self, key, data[key]) @@ -30,5 +30,3 @@ class Contract(object): return 'funded' else: return 'empty' - -# other classes; transactions? users? diff --git a/utils.py b/utils.py index 349c13b..9ba24af 100644 --- a/utils.py +++ b/utils.py @@ -95,7 +95,7 @@ def get_trade(): xcatdb = json.load(data_file) sell = trades.Contract(xcatdb['sell']) buy = trades.Contract(xcatdb['buy']) - trade = trades.Trade(sell, buy) + trade = trades.Trade(sell, buy, commitment=xcatdb['commitment']) return trade except: return None @@ -108,44 +108,7 @@ def save(trade): print("Saving trade") trade = { 'sell': trade.sell.__dict__, - 'buy': trade.buy.__dict__ + 'buy': trade.buy.__dict__, + 'commitment': trade.commitment } save_trade(trade) - - -############################################# -######### Ariel's changes ############### -############################################# - - -def save_seller_trade(trade): - with open('sellertrade.json', 'w') as outfile: - json.dump(jsonformat(trade), outfile) - -def save_buyer_trade(trade): - with open('buyertrade.json', 'w') as outfile: - json.dump(jsonformat(trade), outfile) - -def save_init(trade): - with open('init.json', 'w') as outfile: - json.dump(jsonformat(trade), outfile) - -def get_seller_trade(): - data_file = open('init.json', 'w+') - # try: - xcatdb = json.load(data_file) - sell = trades.Contract(xcatdb['sell']) - buyContract = trades.Contract(xcatdb['buy']) - trade = trades.Trade(sell,buyContract) - - return trade - -def get_buyer_trade(): - with open('buyertrade.json') as data_file: - # try: - xcatdb = json.load(data_file) - sell = trades.Contract(xcatdb['sell']) - buyContract = trades.Contract(xcatdb['buy']) - trade = trades.Trade(sell,buyContract) - - return trade diff --git a/xcat.py b/xcat.py index e2db91b..7abf4f2 100644 --- a/xcat.py +++ b/xcat.py @@ -18,6 +18,7 @@ def check_p2sh(currency, address): return zXcat.check_funds(address) def create_htlc(currency, funder, redeemer, commitment, locktime): + print("Commitment in create_htlc", commitment) if currency == 'bitcoin': sell_p2sh = bXcat.hashtimelockcontract(funder, redeemer, commitment, locktime) else: @@ -57,6 +58,7 @@ def create_sell_p2sh(trade, commitment, locktime): 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): @@ -70,6 +72,7 @@ def create_buy_p2sh(trade, commitment, locktime): 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("Now contact the buyer and tell them to send funds to this p2sh: ", trade.buy.p2sh) save(trade) @@ -149,7 +152,7 @@ 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_initiate(trade): +def seller_init(trade): # Get amounts amounts = userInput.get_trade_amounts() sell = amounts['sell'] @@ -183,7 +186,8 @@ def seller_initiate(trade): txid = fund_sell_contract(trade) print("Sent") - create_buy_p2sh(trade, secret, buy_locktime) + create_buy_p2sh(trade, hash_of_secret, buy_locktime) trade.commitment = b2x(hash_of_secret) + print("TRADE after seller init", trade.toJSON()) return trade diff --git a/zXcat.py b/zXcat.py index 0f844c8..16c5bfd 100644 --- a/zXcat.py +++ b/zXcat.py @@ -39,13 +39,16 @@ def privkey(address): def hashtimelockcontract(funder, redeemer, commitment, locktime): funderAddr = CBitcoinAddress(funder) redeemerAddr = CBitcoinAddress(redeemer) + if type(commitment) == str: + commitment = x(commitment) # h = sha256(secret) blocknum = zcashd.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + locktime print("REDEEMBLOCKNUM ZCASH", redeemblocknum) + print("COMMITMENT on zxcat", commitment) # 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, x(commitment), OP_EQUALVERIFY,OP_DUP, OP_HASH160, + 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)) @@ -53,8 +56,9 @@ def hashtimelockcontract(funder, redeemer, commitment, locktime): # 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) # Returning all this to be saved locally in p2sh.json - return {'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(zec_redeemScript), 'redeemer': redeemer, 'funder': funder} + return {'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(zec_redeemScript), 'redeemer': redeemer, 'funder': funder, 'locktime': locktime} def fund_htlc(p2sh, amount): send_amount = float(amount)*COIN @@ -206,7 +210,7 @@ def redeem_contract(contract, secret): # redeemblocknum = find_redeemblocknum(contract) blockcount = zcashd.getblockcount() print("\nCurrent blocknum at time of redeem on Zcash:", blockcount) - if blockcount < contract.d: + if blockcount < contract.redeemblocknum: # TODO: parse the script once, up front. redeemPubKey = find_redeemAddr(contract)