diff --git a/bXcat.py b/bXcat.py index 7445fa5..ebec5b2 100644 --- a/bXcat.py +++ b/bXcat.py @@ -51,7 +51,7 @@ def hashtimelockcontract(funder, redeemer, secret, locktime): blocknum = bitcoind.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + locktime - print("REDEEMBLOCKNUM", redeemblocknum) + print("REDEEMBLOCKNUM BITCOIN", redeemblocknum) redeemScript = CScript([OP_IF, OP_SHA256, h, 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]) @@ -123,28 +123,28 @@ def auto_redeem(contract, secret): # Parsing redeemblocknum from the redeemscript of the p2sh redeemblocknum = find_redeemblocknum(contract) blockcount = bitcoind.getblockcount() + print("\nCurrent blocknum at time of redeem on Bitcoin:", blockcount) if blockcount < redeemblocknum: redeemPubKey = find_redeemAddr(contract) + print('redeemPubKey', redeemPubKey) else: + print("nLocktime exceeded, refunding") redeemPubKey = find_refundAddr(contract) - tx.nLockTime = redeemblocknum - print('redeemPubKey', redeemPubKey) + print('refundPubKey', redeemPubKey) # redeemPubKey = CBitcoinAddress.from_scriptPubKey(redeemPubKey) # exit() zec_redeemScript = CScript(x(contract.redeemScript)) - - # details = get_tx_details(txid) - # txin = CMutableTxIn(COutPoint(lx(txid), details['vout'])) txin = CMutableTxIn(fundtx['outpoint']) - txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. tx = CMutableTransaction([txin], [txout]) # 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... - tx.nLockTime = redeemblocknum # Ariel: This is only needed when redeeming with the timelock + if blockcount >= 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) # TODO: figure out how to better protect privkey privkey = bitcoind.dumpprivkey(redeemPubKey) @@ -185,7 +185,7 @@ def find_redeemAddr(contract): def find_refundAddr(contract): scriptarray = parse_script(contract.redeemScript) - funder = scriptarray[6] + funder = scriptarray[13] refundAddr = P2PKHBitcoinAddress.from_bytes(x(funder)) return refundAddr @@ -209,7 +209,6 @@ def find_refundAddr(contract): # redeemPubkey = P2PKHBitcoinAddress.from_pubkey(x(pubkey)) # print('redeemPubkey', redeemPubkey) - def find_transaction_to_address(p2sh): bitcoind.importaddress(p2sh, "", False) txs = bitcoind.listunspent() @@ -226,3 +225,7 @@ def new_bitcoin_addr(): addr = bitcoind.getnewaddress() print('new btc addr', addr.to_scriptPubKey) return addr.to_scriptPubKey() + +def generate(num): + blocks = bitcoind.generate(num) + return blocks diff --git a/secret.json b/secret.json index 82dea70..160c7de 100644 --- a/secret.json +++ b/secret.json @@ -1 +1 @@ -1nXlLORk \ No newline at end of file +Hm0Mla5n \ No newline at end of file diff --git a/test.py b/test.py index 0b33e7a..28bfbf0 100644 --- a/test.py +++ b/test.py @@ -1,3 +1,5 @@ +import zXcat +import bXcat from xcat import * htlcTrade = Trade() @@ -33,12 +35,13 @@ def initiate(trade): print("Generating secret to lock funds:", secret) save_secret(secret) # TODO: Implement locktimes and mock block passage of time - locktime = 20 # Must be more than first tx + sell_locktime = 2 + buy_locktime = 4 # Must be more than first tx - create_sell_p2sh(trade, secret, locktime) + create_sell_p2sh(trade, secret, sell_locktime) txid = fund_sell_contract(trade) print("Sent") - create_buy_p2sh(trade, secret, locktime) + create_buy_p2sh(trade, secret, buy_locktime) def fulfill(trade): buy = trade.buyContract @@ -60,15 +63,17 @@ def redeem_one(trade): else: secret = get_secret() print("GETTING SECRET IN TEST:", secret) - txid = redeem_p2sh(trade.buyContract, secret) - print("TX SUCCESSFULLY REDEEMED") - setattr(trade.buyContract, 'redeem_tx', txid) + tx_type, txid = redeem_p2sh(trade.buyContract, secret) + print("\nTX Type", tx_type) + setattr(trade.buyContract, tx_type, txid) save(trade) print("You have redeemed {0} {1}!".format(buy.amount, buy.currency)) def redeem_two(trade): if trade.sellContract.get_status() == 'redeemed': raise RuntimeError("Sell contract was redeemed before buyer could retrieve funds") + elif trade.buyContract.get_status() == 'refunded': + print("buyContract was refunded to buyer") else: # Buy contract is where seller disclosed secret in redeeming if trade.buyContract.currency == 'bitcoin': @@ -80,8 +85,15 @@ def redeem_two(trade): setattr(trade.sellContract, '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) diff --git a/xcat.json b/xcat.json index 418f6d4..1891b41 100644 --- a/xcat.json +++ b/xcat.json @@ -1 +1 @@ -{"sell": {"redeemScript": "63a8208002f14ffc3869269ba5b233d3c934f37115c8821c590da9a28e4df6b44e773d8876a9147788b4511a25fba1092e67b307a6dcdb6da125d967029200b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", "redeem_tx": "ce654c459da4dae859aaf0e88ff8c427ad06874b56f0b332ae158914c67011f0", "p2sh": "2NDymuzi7wFP2SEcwicq3qBXqz2qVAyp9jJ", "currency": "bitcoin", "fund_tx": "ef4cb435c7d7e5fcf128538ae652d5f9920384f63aa39b5f29f6bc2f0fb1b0ea", "redeemblocknum": 146, "amount": "0.5", "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp"}, "buy": {"redeemScript": "63a8208002f14ffc3869269ba5b233d3c934f37115c8821c590da9a28e4df6b44e773d8876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b16702b600b17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", "redeem_tx": "71fb28287ac315ad890f342b0b154f13895c836c6c7bff511c8d58bb6da0a752", "p2sh": "t26pfk2JKC4XzNLdcmXwrpPMTyb13SDWDjV", "currency": "zcash", "fund_tx": "828afa314f8ba0f75e1f3a808fbf39d57b0b2c71a445b90f6ac3b24bd8eddc3e", "redeemblocknum": 182, "amount": "1.12", "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY", "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ"}} \ No newline at end of file +{"sell": {"currency": "bitcoin", "fulfiller": "mrQzUGU1dwsWRx5gsKKSDPNtrsP65vCA3Z", "initiator": "myfFr5twPYNwgeXyjCmGcrzXtCmfmWXKYp", "amount": "0.5", "redeemScript": "63a82033fb8f68c7e079a2a35cfcd8827279f8a55fa1be04c99debd8ed3e54954e08228876a9147788b4511a25fba1092e67b307a6dcdb6da125d96702bd01b17576a914c7043e62a7391596116f54f6a64c8548e97d3fd96888ac", "fund_tx": "6cca31678d7fe6461277cea7e0614844e62ccc3ae4e247ca77d62bdd741fabef", "p2sh": "2N3rA4r6VSx65FeBTcgWWcR9HaW69DYDbrp", "redeemblocknum": 445}, "buy": {"currency": "zcash", "fulfiller": "tmTjZSg4pX2Us6V5HttiwFZwj464fD2ZgpY", "initiator": "tmFRXyju7ANM7A9mg75ZjyhFW1UJEhUPwfQ", "amount": "1.12", "refund_tx": "5e34f0c634fb6207e9c85ed52528629404d25db29b68931b4e0278377ee776d6", "redeemScript": "63a82033fb8f68c7e079a2a35cfcd8827279f8a55fa1be04c99debd8ed3e54954e08228876a9143ea29256c9d2888ca23de42a8b8e69ca2ec235b16702e301b17576a914c5acca6ef39c843c7a9c3ad01b2da95fe2edf5ba6888ac", "fund_tx": "8c9f9581a8cab00836b54237b30a6d68125067e3ffe6ae04413da2bdc9146daa", "p2sh": "t2UkYvcnigZt7FFp86UvTZ78qdGeLXw7tet", "redeemblocknum": 483}} \ No newline at end of file diff --git a/xcat.py b/xcat.py index 1ac9485..e6cff8e 100644 --- a/xcat.py +++ b/xcat.py @@ -114,8 +114,8 @@ def seller_redeem(trade): else: # Seller redeems buyer's funded tx (contract in p2sh) secret = userInput.retrieve_password() - txid = redeem_p2sh(trade.buyContract, secret) - setattr(trade.buyContract, 'redeem_tx', txid) + tx_type, txid = redeem_p2sh(trade.buyContract, secret) + setattr(trade.buyContract, tx_type, txid) save(trade) print("You have redeemed {0} {1}!".format(buy.amount, buy.currency)) print_trade('seller') @@ -158,16 +158,17 @@ def seller_initiate(trade): secret = userInput.create_password() # TODO: Implement locktimes and mock block passage of time - locktime = 20 # Must be more than first tx + sell_locktime = 5 + buy_locktime = 10 # Must be more than first tx - create_sell_p2sh(trade, secret, locktime) + create_sell_p2sh(trade, secret, sell_locktime) userInput.authorize_fund_sell(trade) txid = fund_sell_contract(trade) print("Sent") - create_buy_p2sh(trade, secret, locktime) + create_buy_p2sh(trade, secret, buy_locktime) print_trade('seller') if __name__ == '__main__': diff --git a/zXcat.py b/zXcat.py index 86760fa..76e7be8 100644 --- a/zXcat.py +++ b/zXcat.py @@ -41,7 +41,7 @@ def hashtimelockcontract(funder, redeemer, secret, locktime): blocknum = zcashd.getblockcount() print("Current blocknum", blocknum) redeemblocknum = blocknum + locktime - print("REDEEMBLOCKNUM", redeemblocknum) + print("REDEEMBLOCKNUM ZCASH", redeemblocknum) zec_redeemScript = CScript([OP_IF, OP_SHA256, h, 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]) @@ -145,39 +145,42 @@ def auto_redeem(contract, secret): # Where can you find redeemblocknum in the transaction? redeemblocknum = find_redeemblocknum(contract) blockcount = zcashd.getblockcount() + print("\nCurrent blocknum at time of redeem on Zcash:", blockcount) if blockcount < redeemblocknum: redeemPubKey = find_redeemAddr(contract) + print('redeemPubKey', redeemPubKey) + zec_redeemScript = CScript(x(contract.redeemScript)) + txin = CMutableTxIn(fundtx['outpoint']) + txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) + # Create the unsigned raw transaction. + tx = CMutableTransaction([txin], [txout]) + sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL) + # TODO: figure out how to better protect privkey + privkey = zcashd.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)) + txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() + print('Redeem txhex', b2x(tx.serialize())) + VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) + print("script verified, sending raw tx") + txid = zcashd.sendrawtransaction(tx) + print("Txid of submitted redeem tx: ", b2x(lx(b2x(txid)))) + print("TXID SUCCESSFULLY REDEEMED") + return 'redeem_tx', b2x(lx(b2x(txid))) else: - redeemPubKey = find_refundAddr(contract) - tx.nLockTime = redeemblocknum - print('redeemPubKey', redeemPubKey) - - zec_redeemScript = CScript(x(contract.redeemScript)) - - # details = get_tx_details(txid) - # txin = CMutableTxIn(COutPoint(lx(txid), details['vout'])) - txin = CMutableTxIn(fundtx['outpoint']) - - txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) - # Create the unsigned raw transaction. - tx = CMutableTransaction([txin], [txout]) - - sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL) - # TODO: figure out how to better protect privkey - privkey = zcashd.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)) - txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() - print('Redeem txhex', b2x(tx.serialize())) - VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) - print("script verified, sending raw tx") - txid = zcashd.sendrawtransaction(tx) - print("Txid of submitted redeem tx: ", b2x(lx(b2x(txid)))) - return b2x(lx(b2x(txid))) + # if blockcount >= redeemblocknum: + # tx.nLockTime = redeemblocknum + print("nLocktime exceeded, refunding") + refundPubKey = find_refundAddr(contract) + print('refundPubKey', refundPubKey) + txid = zcashd.sendtoaddress(refundPubKey, fundtx['amount'] - FEE) + print("Txid of refund tx:", b2x(lx(b2x(txid)))) + print("TXID SUCCESSFULLY REFUNDED") + return 'refund_tx', b2x(lx(b2x(txid))) else: print("No contract for this p2sh found in database", p2sh) @@ -199,7 +202,7 @@ def find_redeemAddr(contract): def find_refundAddr(contract): scriptarray = parse_script(contract.redeemScript) - funder = scriptarray[6] + funder = scriptarray[13] refundAddr = P2PKHBitcoinAddress.from_bytes(x(funder)) return refundAddr @@ -230,3 +233,7 @@ def new_zcash_addr(): addr = zcashd.getnewaddress() print('new ZEC addr', addr.to_p2sh_scriptPubKey) return addr.to_scriptPubKey() + +def generate(num): + blocks = zcashd.generate(num) + return blocks