wip
This commit is contained in:
parent
4e100c46c3
commit
15ff860746
30
api.py
30
api.py
|
@ -103,22 +103,32 @@ def buyer_fund():
|
|||
|
||||
|
||||
|
||||
def seller_redeem_before_signature():
|
||||
def seller_redeem():
|
||||
trade = get_seller_trade()
|
||||
print(trade)
|
||||
print("SELLER REDEEMING BUY CONTRACT")
|
||||
print("=============================")
|
||||
buy = trade.buyContract
|
||||
print(buy)
|
||||
# if trade.sellContract.get_status() == 'redeemed':
|
||||
# raise RuntimeError("Sell contract status was already redeemed before seller could redeem buyer's tx")
|
||||
#else:
|
||||
secret = get_secret() # Just the seller getting his local copy of the secret
|
||||
print("SELLER SECRET IN TEST:", secret)
|
||||
txid = redeem_p2sh(trade.buyContract, secret, trade.sellContract)
|
||||
setattr(trade.buyContract, 'redeem_tx', txid)
|
||||
save(trade)
|
||||
(buy,sell) = init_redeem_p2sh(trade.buyContract, trade.sellContract)
|
||||
|
||||
# in case we're still in the time lock on buy side, try to redeem with secret
|
||||
if(buy.redeemtype != ""):
|
||||
privkey = get_redeemer_priv_key(buy)
|
||||
buy = get_raw_redeem(buy)
|
||||
|
||||
if(sell.redeemtype != ""):
|
||||
privkey = get_redeemer_priv_key(sell)
|
||||
|
||||
contract = check trade(trade.buyContract, secret, trade.sellContract)
|
||||
setattr(trade.buyContract, 'redeem_tx', txid)
|
||||
save_seller(trade)
|
||||
|
||||
def seller_sign_edeem():
|
||||
|
||||
def seller_redeem_after_signature():
|
||||
trade
|
||||
|
||||
|
||||
def buyer_redeem():
|
||||
print("BUYER REDEEMING SELL CONTRACT")
|
||||
|
@ -148,7 +158,7 @@ def buyer_redeem():
|
|||
print("Found secret in seller's redeem tx on zcash chain:", secret)
|
||||
redeem_tx = redeem_p2sh(sellContract, secret, buyContract)
|
||||
setattr(trade.sellContract, 'redeem_tx', redeem_tx)
|
||||
save(trade)
|
||||
save_buyer(trade)
|
||||
|
||||
|
||||
def generate_blocks(num):
|
||||
|
|
76
bXcat.py
76
bXcat.py
|
@ -26,6 +26,11 @@ bitcoind = bitcoin.rpc.Proxy()
|
|||
FEE = 0.001*COIN
|
||||
zcashd = zcash.rpc.Proxy()
|
||||
|
||||
def send_raw_tx(rawtx):
|
||||
txid = bitcoind.sendrawtransaction(rawtx)
|
||||
return txid
|
||||
|
||||
|
||||
def import_address(address):
|
||||
bitcoind.importaddress(address, "", False)
|
||||
|
||||
|
@ -92,24 +97,42 @@ def get_tx_details(txid):
|
|||
fund_txinfo = bitcoind.gettransaction(lx(txid))
|
||||
return fund_txinfo['details'][0]
|
||||
|
||||
# redeems funded tx automatically, by scanning for transaction to the p2sh
|
||||
# i.e., doesn't require buyer telling us fund txid
|
||||
# returns false if fund tx doesn't exist or is too small
|
||||
def check_redeem_with_secret(contract):
|
||||
def get_redeemer_priv_key(contract):
|
||||
if (contract.redeemtype == 'secret'):
|
||||
redeemPubKey = find_redeemAddr(contract)
|
||||
elif (contract.redeemtype = 'timelock'):
|
||||
redeemPubKey = find_refundAddr(contract)
|
||||
else:
|
||||
raise ValueError("Invalid redeemtype:", contract.redeemtype)
|
||||
|
||||
return bitcoind.dumpprivkey(redeemPubKey)
|
||||
|
||||
|
||||
|
||||
def check_and_return_fundtx(contract):
|
||||
# How to find redeemscript and redeemblocknum from blockchain?
|
||||
print("Redeeming contract using secret", contract.__dict__)
|
||||
p2sh = contract.p2sh
|
||||
minamount = float(contract.amount)
|
||||
# checking there are funds in the address
|
||||
amount = check_funds(p2sh)
|
||||
if(amount < minamount):
|
||||
print("address ", p2sh, " not sufficiently funded")
|
||||
return false
|
||||
# may have problems in case funder funded address in more than one tx
|
||||
# the funder may have accidentily funded the p2sh with sufficient amount in several transactions. The current code
|
||||
# will abort in this case. This is a conservative approach to prevent the following attack, for example: the funder splits
|
||||
# the amount into many tiny outputs, hoping the redeemer will not have time to redeem them all by the timelock.
|
||||
fundtx = find_transaction_to_address(p2sh)
|
||||
if(fundtx=""):
|
||||
raise ValueError("fund tx to ", p2sh, " not found")
|
||||
|
||||
amount = fundtx['amount'] / COIN
|
||||
if(amount < minamount):
|
||||
print("funder funded ", p2sh, " in more than one tx will need to run redeem again to get whole amount")
|
||||
|
||||
|
||||
contract.fund_tx = fund_tx
|
||||
return contract
|
||||
|
||||
# assuming we have the correct fund tx in the contract prepares the signed redeem raw tx
|
||||
def get_raw_redeem(contract, privkey)
|
||||
|
||||
p2sh = contract.p2sh
|
||||
p2sh = P2SHBitcoinAddress(p2sh)
|
||||
if fundtx['address'] == p2sh:
|
||||
print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh))
|
||||
|
@ -126,29 +149,23 @@ def check_redeem_with_secret(contract):
|
|||
print("No contract for this p2sh found in database", p2sh)
|
||||
|
||||
|
||||
def finish_redeem_with_secret():
|
||||
sighash = SignatureHash(redeemscript, tx, 0, SIGHASH_ALL)
|
||||
# TODO: figure out how to better protect privkey
|
||||
print("herebeforedump")
|
||||
privkey = bitcoind.dumpprivkey(redeemPubKey)
|
||||
print("hereafterdump")
|
||||
|
||||
sig = privkey.sign(sighash) + bytes([SIGHASH_ALL])
|
||||
sighash = SignatureHash(redeemscript, tx, 0, SIGHASH_ALL)
|
||||
secret = get_secret() # assumes secret is present in secret.json
|
||||
sig = privkey.sign(sighash) + bytes([SIGHASH_ALL])
|
||||
if(contract.redeemtype = "secret"):
|
||||
print("SECRET", secret)
|
||||
preimage = secret.encode('utf-8')
|
||||
txin.scriptSig = CScript([sig, privkey.pub, preimage, OP_TRUE, redeemscript])
|
||||
|
||||
# exit()
|
||||
|
||||
# print("txin.scriptSig", b2x(txin.scriptSig))
|
||||
txin_scriptPubKey = 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 = bitcoind.sendrawtransaction(tx)
|
||||
print("Txid of submitted redeem tx: ", b2x(lx(b2x(txid))))
|
||||
return b2x(lx(b2x(txid)))
|
||||
elif(contract.redeemtype = "timelock"):
|
||||
txin.scriptSig = CScript([sig, privkey.pub, OP_FALSE, redeemscript])
|
||||
else:
|
||||
raise ValueError("invalid redeemtype:", contract.redeemtype)
|
||||
|
||||
txin_scriptPubKey = redeemscript.to_p2sh_scriptPubKey()
|
||||
VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
|
||||
print("script verified, writing raw redeem tx in contract")
|
||||
contract.rawredeemtx = tx
|
||||
return contract
|
||||
|
||||
|
||||
|
||||
|
@ -265,6 +282,7 @@ def find_transaction_to_address(p2sh):
|
|||
if tx['address'] == CBitcoinAddress(p2sh):
|
||||
print("Found tx to p2sh", p2sh, "tx is", tx)
|
||||
return tx
|
||||
return ""
|
||||
|
||||
def new_bitcoin_addr():
|
||||
addr = bitcoind.getnewaddress()
|
||||
|
|
|
@ -7,7 +7,7 @@ class Trade(object):
|
|||
class Contract(object):
|
||||
def __init__(self, data):
|
||||
# Keep track of funding and redeem tx?
|
||||
allowed = ('funder', 'redeemer', 'currency', 'p2sh', 'amount', 'fund_tx', 'redeem_tx', 'secret', 'redeemscript', 'redeemblocknum','hash_of_secret')
|
||||
allowed = ('funder', 'redeemer', 'currency', 'p2sh', 'amount', 'fund_tx', 'redeem_tx', 'secret', 'redeemscript', 'redeemblocknum','hash_of_secret','redeemtype')
|
||||
for key in data:
|
||||
if key in allowed:
|
||||
setattr(self, key, data[key])
|
||||
|
|
8
utils.py
8
utils.py
|
@ -17,12 +17,12 @@ def generate_password():
|
|||
passlen = 8
|
||||
p = "".join(random.sample(s,passlen))
|
||||
return p
|
||||
|
||||
'''
|
||||
# TODO: Port these over to leveldb or some other database
|
||||
def save_trade(trade):
|
||||
with open('xcat.json', 'w') as outfile:
|
||||
json.dump(trade, outfile)
|
||||
|
||||
'''
|
||||
def save_seller_trade(trade):
|
||||
with open('sellertrade.json', 'w') as outfile:
|
||||
json.dump(jsonformat(trade), outfile)
|
||||
|
@ -43,7 +43,7 @@ def get_init():
|
|||
trade = trades.Trade(sellContract,buyContract)
|
||||
return trade
|
||||
|
||||
|
||||
'''
|
||||
def get_trade():
|
||||
with open('xcat.json') as data_file:
|
||||
# try:
|
||||
|
@ -52,7 +52,7 @@ def get_trade():
|
|||
buyContract = trades.Contract(xcatdb['buy'])
|
||||
trade = trades.Trade(sellContract,buyContract)
|
||||
|
||||
return trade
|
||||
return trade'''
|
||||
|
||||
def get_seller_trade():
|
||||
with open('init.json') as data_file:
|
||||
|
|
50
xcat.py
50
xcat.py
|
@ -97,7 +97,7 @@ def create_buy_2sh(trade, secret, locktime):
|
|||
# we try to redeem contract with secret
|
||||
# we try to redeem revertcontract with time lock
|
||||
# returns True if at least one redeem succeeded
|
||||
def prepare_redeem_p2sh(contract, secret, revertcontract):
|
||||
def redeem_p2sh(contract, secret, revertcontract):
|
||||
|
||||
currency = contract.currency
|
||||
res = False
|
||||
|
@ -129,6 +129,7 @@ def prepare_redeem_p2sh(contract, secret, revertcontract):
|
|||
except Exception:
|
||||
print("Failed - the other party might have redeemed the fund tx on the btc chain with the secret by now")
|
||||
if(res): print("You have redeemed {0} {1}!".format(revertcontract.amount, revertcontract.currency))
|
||||
print("HHERE")
|
||||
if (revert_currency == 'zcash'):
|
||||
if(zXcat.still_locked(revertcontract)):
|
||||
print('too early for redeeminng with time lock on zcash chain')
|
||||
|
@ -142,53 +143,6 @@ def prepare_redeem_p2sh(contract, secret, revertcontract):
|
|||
|
||||
return res
|
||||
|
||||
def finish_redeem_p2sh(contract, secret, revertcontract):
|
||||
|
||||
currency = contract.currency
|
||||
res = False
|
||||
revert_currency = revertcontract.currency
|
||||
|
||||
# should the code still try to redeem when time has passed? currently it doesn't
|
||||
if (currency == 'bitcoin' and bXcat.still_locked(contract)):
|
||||
print("trying to redeem btc with secret:")
|
||||
try:
|
||||
res = bXcat.redeem_with_secret(contract, secret)
|
||||
except Exception:
|
||||
print("Failed - you might not have the correct secret - perhaps because the seller has not redeemed the buy contract correctly")
|
||||
if(res): print("You have redeemed {0} {1}!".format(contract.amount, contract.currency))
|
||||
|
||||
if (currency == 'zcash' and zXcat.still_locked(contract)):
|
||||
print("trying to redeeming zec with secret:")
|
||||
try:
|
||||
res = zXcat.redeem_with_secret(contract, secret)
|
||||
except Exception:
|
||||
print("Failed - you might not have the correct secret - perhaps because the seller has not redeemed the buy contract correctly")
|
||||
if(res): print("You have redeemed {0} {1}!".format(contract.amount, contract.currency))
|
||||
if (revert_currency == 'bitcoin'):
|
||||
if(bXcat.still_locked(revertcontract)):
|
||||
print('too early for redeeminng with time lock on btc chain')
|
||||
else:
|
||||
print("trying to redeeming btc with timelock:")
|
||||
try:
|
||||
res = bXcat.redeem_after_timelock(revertcontract)
|
||||
except Exception:
|
||||
print("Failed - the other party might have redeemed the fund tx on the btc chain with the secret by now")
|
||||
if(res): print("You have redeemed {0} {1}!".format(revertcontract.amount, revertcontract.currency))
|
||||
if (revert_currency == 'zcash'):
|
||||
if(zXcat.still_locked(revertcontract)):
|
||||
print('too early for redeeminng with time lock on zcash chain')
|
||||
else:
|
||||
print("trying to redeeming zec with timelock:")
|
||||
try:
|
||||
res = zXcat.redeem_after_timelock(revertcontract)
|
||||
except Exception:
|
||||
print("Failed - the other party might have redeemed the fund tx on the zcash chain with the secret by now")
|
||||
if(res): print("You have redeemed {0} {1}!".format(revertcontract.amount, revertcontract.currency))
|
||||
|
||||
return res
|
||||
|
||||
|
||||
|
||||
def print_trade(role):
|
||||
print("\nTrade status for {0}:".format(role))
|
||||
trade = get_trade()
|
||||
|
|
36
zXcat.py
36
zXcat.py
|
@ -23,6 +23,10 @@ SelectParams('regtest')
|
|||
zcashd = zcash.rpc.Proxy()
|
||||
FEE = 0.0001*COIN
|
||||
|
||||
def send_raw_tx(rawtx):
|
||||
txid = zcashd.sendrawtransaction(rawtx)
|
||||
return txid
|
||||
|
||||
|
||||
def import_address(address):
|
||||
zcashd.importaddress(address, "", False)
|
||||
|
@ -361,3 +365,35 @@ def redeem_after_timelock(contract):
|
|||
txid = zcashd.sendrawtransaction(tx)
|
||||
print("Txid of submitted redeem tx: ", b2x(lx(b2x(txid))))
|
||||
return b2x(lx(b2x(txid)))
|
||||
|
||||
|
||||
def get_redeemer_priv_key(contract):
|
||||
if (contract.redeemtype == 'secret'):
|
||||
redeemPubKey = find_redeemAddr(contract)
|
||||
elif (contract.redeemtype = 'timelock'):
|
||||
redeemPubKey = find_refundAddr(contract)
|
||||
else:
|
||||
raise ValueError("Invalid redeemtype:", contract.redeemtype)
|
||||
|
||||
return zcashd.dumpprivkey(redeemPubKey)
|
||||
|
||||
|
||||
def check_and_return_fundtx(contract):
|
||||
# How to find redeemscript and redeemblocknum from blockchain?
|
||||
print("Redeeming contract using secret", contract.__dict__)
|
||||
p2sh = contract.p2sh
|
||||
minamount = float(contract.amount)
|
||||
# the funder may have accidentily funded the p2sh with sufficient amount in several transactions. The current code
|
||||
# will abort in this case. This is a conservative approach to prevent the following attack, for example: the funder splits
|
||||
# the amount into many tiny outputs, hoping the redeemer will not have time to redeem them all by the timelock.
|
||||
fundtx = find_transaction_to_address(p2sh)
|
||||
if(fundtx=""):
|
||||
raise ValueError("fund tx to ", p2sh, " not found")
|
||||
|
||||
amount = fundtx['amount'] / COIN
|
||||
if(amount < minamount):
|
||||
print("funder funded ", p2sh, " in more than one tx will need to run redeem again to get whole amount")
|
||||
|
||||
|
||||
contract.fund_tx = fund_tx
|
||||
return contract
|
||||
|
|
Loading…
Reference in New Issue