Add automated test, refund tx functionality
This commit is contained in:
parent
3ee8606dcf
commit
84df93782b
23
bXcat.py
23
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
|
||||
|
|
|
@ -1 +1 @@
|
|||
1nXlLORk
|
||||
Hm0Mla5n
|
24
test.py
24
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)
|
||||
|
||||
|
|
|
@ -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"}}
|
||||
{"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}}
|
11
xcat.py
11
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__':
|
||||
|
|
71
zXcat.py
71
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
|
||||
|
|
Loading…
Reference in New Issue