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 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]

13
cli.py
View File

@ -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":

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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)