Get working again

This commit is contained in:
Jay Graber 2017-07-28 13:57:44 -07:00
parent 941ef40390
commit 043958b840
6 changed files with 39 additions and 68 deletions

View File

@ -20,12 +20,13 @@ import zcash
import zcash.rpc import zcash.rpc
import pprint, json import pprint, json
from zXcat import parse_script
# SelectParams('testnet') # SelectParams('testnet')
SelectParams('regtest') SelectParams('regtest')
bitcoind = bitcoin.rpc.Proxy() bitcoind = bitcoin.rpc.Proxy()
FEE = 0.001*COIN FEE = 0.001*COIN
zcashd = zcash.rpc.Proxy()
def validateaddress(addr): def validateaddress(addr):
return bitcoind.validateaddress(addr) return bitcoind.validateaddress(addr)
@ -50,12 +51,15 @@ def privkey(address):
def hashtimelockcontract(funder, redeemer, commitment, locktime): def hashtimelockcontract(funder, redeemer, commitment, locktime):
funderAddr = CBitcoinAddress(funder) funderAddr = CBitcoinAddress(funder)
redeemerAddr = CBitcoinAddress(redeemer) redeemerAddr = CBitcoinAddress(redeemer)
if type(commitment) == str:
commitment = x(commitment)
# h = sha256(secret) # h = sha256(secret)
blocknum = bitcoind.getblockcount() blocknum = bitcoind.getblockcount()
print("Current blocknum", blocknum) print("Current blocknum", blocknum)
redeemblocknum = blocknum + locktime redeemblocknum = blocknum + locktime
print("REDEEMBLOCKNUM BITCOIN", redeemblocknum) 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, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160,
funderAddr, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG]) 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:", b2x(redeemScript))
@ -63,7 +67,8 @@ def hashtimelockcontract(funder, redeemer, commitment, locktime):
# Convert the P2SH scriptPubKey to a base58 Bitcoin address # Convert the P2SH scriptPubKey to a base58 Bitcoin address
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
p2sh = str(txin_p2sh_address) 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): def fund_htlc(p2sh, amount):
send_amount = float(amount) * COIN send_amount = float(amount) * COIN
@ -111,8 +116,8 @@ def auto_redeem(contract, secret):
print("Parsing script for auto_redeem...") print("Parsing script for auto_redeem...")
scriptarray = parse_script(contract.redeemScript) scriptarray = parse_script(contract.redeemScript)
redeemblocknum = scriptarray[8] redeemblocknum = scriptarray[8]
redeemPubkey = scriptarray[6] redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6]))
refundPubkey = scriptarray[13] refundPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[13]))
# How to find redeemScript and redeemblocknum from blockchain? # How to find redeemScript and redeemblocknum from blockchain?
print("Contract in auto redeem", contract.__dict__) print("Contract in auto redeem", contract.__dict__)
p2sh = contract.p2sh p2sh = contract.p2sh
@ -132,12 +137,13 @@ def auto_redeem(contract, secret):
# redeemblocknum = find_redeemblocknum(contract) # redeemblocknum = find_redeemblocknum(contract)
blockcount = bitcoind.getblockcount() blockcount = bitcoind.getblockcount()
print("\nCurrent blocknum at time of redeem on Bitcoin:", blockcount) print("\nCurrent blocknum at time of redeem on Bitcoin:", blockcount)
if blockcount < redeemblocknum: if blockcount < int(redeemblocknum):
# redeemPubKey = find_redeemAddr(contract) # redeemPubKey = find_redeemAddr(contract)
print('redeemPubKey', redeemPubKey) print('redeemPubKey', redeemPubKey)
else: else:
print("nLocktime exceeded, refunding") print("nLocktime exceeded, refunding")
redeemPubKey = find_refundAddr(contract) # refundPubKey = find_refundAddr(contract)
redeemPubKey = refundPubkey
print('refundPubKey', redeemPubKey) print('refundPubKey', redeemPubKey)
# redeemPubKey = CBitcoinAddress.from_scriptPubKey(redeemPubKey) # redeemPubKey = CBitcoinAddress.from_scriptPubKey(redeemPubKey)
# exit() # 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 # 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... # TODO: these things like redeemblocknum should really be properties of a tx class...
# Need: redeemblocknum, zec_redeemScript, secret (for creator...), txid, redeemer... # Need: redeemblocknum, zec_redeemScript, secret (for creator...), txid, redeemer...
if blockcount >= redeemblocknum: if blockcount >= int(redeemblocknum):
print("\nLocktime exceeded") print("\nLocktime exceeded")
tx.nLockTime = redeemblocknum # Ariel: This is only needed when redeeming with the timelock tx.nLockTime = redeemblocknum # Ariel: This is only needed when redeeming with the timelock
sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL) sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL)
@ -234,13 +240,6 @@ def redeem_contract(contract, secret):
else: else:
print("No contract for this p2sh found in database", p2sh) 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): def find_redeemblocknum(contract):
scriptarray = parse_script(contract.redeemScript) scriptarray = parse_script(contract.redeemScript)
redeemblocknum = scriptarray[8] redeemblocknum = scriptarray[8]

13
cli.py
View File

@ -22,15 +22,18 @@ def checkSellStatus(trade):
elif trade.buy.get_status() == 'redeemed': elif trade.buy.get_status() == 'redeemed':
print("You have already redeemed the p2sh on the second chain of this trade.") 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): def checkBuyStatus(trade):
if trade.sell.get_status() == 'funded' and trade.buy.get_status() != 'redeemed': if trade.sell.get_status() == 'funded' and trade.buy.get_status() != 'redeemed':
print("One active trade available, fulfilling buyer contract...") print("One active trade available, fulfilling buyer contract...")
# they should calculate redeemScript for themselves # 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) 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 the two p2sh match...
if buyer_p2sh == contract.buy.p2sh: if buyer_p2sh == trade.buy.p2sh:
fund_tx = fund_contract(trade.buy) fund_tx = fund_contract(trade.buy)
trade.buy.fund_tx = fund_tx trade.buy.fund_tx = fund_tx
print("trade buy with redeemscript?", trade.buy.__dict__) print("trade buy with redeemscript?", trade.buy.__dict__)
@ -91,7 +94,7 @@ if __name__ == '__main__':
erase_trade() erase_trade()
role = 'seller' role = 'seller'
print("Creating new XCAT trade...") print("Creating new XCAT trade...")
trade = seller_initiate(Trade()) trade = seller_init(Trade())
# Save it to leveldb # Save it to leveldb
db.create(trade) db.create(trade)
elif command == "daemon": elif command == "daemon":
@ -106,7 +109,7 @@ if __name__ == '__main__':
elif command == "step1": elif command == "step1":
erase_trade() erase_trade()
print("Creating new XCAT trade...") print("Creating new XCAT trade...")
trade = seller_initiate(Trade()) trade = seller_init(Trade())
# Save it to leveldb # Save it to leveldb
save_state(trade) save_state(trade)
elif command == "step2": elif command == "step2":

View File

@ -14,7 +14,7 @@ class Trade(object):
class Contract(object): class Contract(object):
def __init__(self, data): def __init__(self, data):
# Keep track of funding and redeem tx? # 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: for key in data:
if key in allowed: if key in allowed:
setattr(self, key, data[key]) setattr(self, key, data[key])
@ -30,5 +30,3 @@ class Contract(object):
return 'funded' return 'funded'
else: else:
return 'empty' return 'empty'
# other classes; transactions? users?

View File

@ -95,7 +95,7 @@ def get_trade():
xcatdb = json.load(data_file) xcatdb = json.load(data_file)
sell = trades.Contract(xcatdb['sell']) sell = trades.Contract(xcatdb['sell'])
buy = trades.Contract(xcatdb['buy']) buy = trades.Contract(xcatdb['buy'])
trade = trades.Trade(sell, buy) trade = trades.Trade(sell, buy, commitment=xcatdb['commitment'])
return trade return trade
except: except:
return None return None
@ -108,44 +108,7 @@ 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
} }
save_trade(trade) 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

View File

@ -18,6 +18,7 @@ def check_p2sh(currency, address):
return zXcat.check_funds(address) return zXcat.check_funds(address)
def create_htlc(currency, funder, redeemer, commitment, locktime): def create_htlc(currency, funder, redeemer, commitment, locktime):
print("Commitment in create_htlc", commitment)
if currency == 'bitcoin': if currency == 'bitcoin':
sell_p2sh = bXcat.hashtimelockcontract(funder, redeemer, commitment, locktime) sell_p2sh = bXcat.hashtimelockcontract(funder, redeemer, commitment, locktime)
else: else:
@ -57,6 +58,7 @@ def create_sell_p2sh(trade, commitment, locktime):
setattr(trade.sell, 'p2sh', contract['p2sh']) setattr(trade.sell, 'p2sh', contract['p2sh'])
setattr(trade.sell, 'redeemScript', contract['redeemScript']) setattr(trade.sell, 'redeemScript', contract['redeemScript'])
setattr(trade.sell, 'redeemblocknum', contract['redeemblocknum']) setattr(trade.sell, 'redeemblocknum', contract['redeemblocknum'])
setattr(trade.buy, 'locktime', contract['locktime'])
save(trade) save(trade)
def create_buy_p2sh(trade, commitment, locktime): 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, 'p2sh', buy_contract['p2sh'])
setattr(trade.buy, 'redeemScript', buy_contract['redeemScript']) setattr(trade.buy, 'redeemScript', buy_contract['redeemScript'])
setattr(trade.buy, 'redeemblocknum', buy_contract['redeemblocknum']) 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("Now contact the buyer and tell them to send funds to this p2sh: ", trade.buy.p2sh)
save(trade) 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("Please wait for the seller to remove your funds from escrow to complete the trade.")
print_trade('buyer') print_trade('buyer')
def seller_initiate(trade): def seller_init(trade):
# Get amounts # Get amounts
amounts = userInput.get_trade_amounts() amounts = userInput.get_trade_amounts()
sell = amounts['sell'] sell = amounts['sell']
@ -183,7 +186,8 @@ def seller_initiate(trade):
txid = fund_sell_contract(trade) txid = fund_sell_contract(trade)
print("Sent") print("Sent")
create_buy_p2sh(trade, secret, buy_locktime) create_buy_p2sh(trade, hash_of_secret, buy_locktime)
trade.commitment = b2x(hash_of_secret) trade.commitment = b2x(hash_of_secret)
print("TRADE after seller init", trade.toJSON())
return trade return trade

View File

@ -39,13 +39,16 @@ def privkey(address):
def hashtimelockcontract(funder, redeemer, commitment, locktime): def hashtimelockcontract(funder, redeemer, commitment, locktime):
funderAddr = CBitcoinAddress(funder) funderAddr = CBitcoinAddress(funder)
redeemerAddr = CBitcoinAddress(redeemer) redeemerAddr = CBitcoinAddress(redeemer)
if type(commitment) == str:
commitment = x(commitment)
# h = sha256(secret) # h = sha256(secret)
blocknum = zcashd.getblockcount() blocknum = zcashd.getblockcount()
print("Current blocknum", blocknum) print("Current blocknum", blocknum)
redeemblocknum = blocknum + locktime redeemblocknum = blocknum + locktime
print("REDEEMBLOCKNUM ZCASH", redeemblocknum) 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) # 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, redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160,
funderAddr, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG]) 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))
@ -53,8 +56,9 @@ def hashtimelockcontract(funder, redeemer, commitment, locktime):
# Convert the P2SH scriptPubKey to a base58 Bitcoin address # Convert the P2SH scriptPubKey to a base58 Bitcoin address
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
p2sh = str(txin_p2sh_address) p2sh = str(txin_p2sh_address)
print("p2sh computed", p2sh)
# Returning all this to be saved locally in p2sh.json # 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): def fund_htlc(p2sh, amount):
send_amount = float(amount)*COIN send_amount = float(amount)*COIN
@ -206,7 +210,7 @@ def redeem_contract(contract, secret):
# redeemblocknum = find_redeemblocknum(contract) # redeemblocknum = find_redeemblocknum(contract)
blockcount = zcashd.getblockcount() blockcount = zcashd.getblockcount()
print("\nCurrent blocknum at time of redeem on Zcash:", blockcount) 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. # TODO: parse the script once, up front.
redeemPubKey = find_redeemAddr(contract) redeemPubKey = find_redeemAddr(contract)