This commit is contained in:
James Prestwich 2017-09-14 14:40:07 -06:00
commit 772f1b857b
No known key found for this signature in database
GPG Key ID: 519E010A79028CCC
6 changed files with 233 additions and 102 deletions

View File

@ -10,16 +10,20 @@ import bitcoin.rpc
from bitcoin import SelectParams
from bitcoin.core import b2x, lx, b2lx, x, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, Hash160, CTransaction
from bitcoin.base58 import decode
from bitcoin.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_ENDIF, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL, OP_FALSE, OP_DROP, OP_CHECKLOCKTIMEVERIFY, OP_SHA256, OP_TRUE
from bitcoin.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_ENDIF, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL, OP_FALSE, OP_DROP, OP_CHECKLOCKTIMEVERIFY, OP_SHA256, OP_TRUE, OP_FALSE
from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH
from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret, P2SHBitcoinAddress, P2PKHBitcoinAddress
from xcat.utils import *
import logging
FEE = 0.001*COIN
class bitcoinProxy():
def __init__(self, network='regtest', timeout=900):
if network is not 'testnet' and network is not 'mainnet':
network='regtest'
logging.debug("NETWORK in proxy: {0}".format(network))
self.network = network
self.timeout = timeout
@ -143,7 +147,7 @@ class bitcoinProxy():
print("Parsing script for redeem_contract...")
scriptarray = self.parse_script(contract.redeemScript)
redeemblocknum = scriptarray[8]
redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6]))
self.redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6]))
refundPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[13]))
p2sh = contract.p2sh
#checking there are funds in the address
@ -161,38 +165,64 @@ class bitcoinProxy():
blockcount = self.bitcoind.getblockcount()
print("\nCurrent blocknum at time of redeem on Zcash:", blockcount)
if blockcount < int(redeemblocknum):
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: protect privkey better, separate signing from rawtx creation
privkey = self.bitcoind.dumpprivkey(redeemPubKey)
sig = privkey.sign(sighash) + bytes([SIGHASH_ALL])
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('Raw redeem transaction hex: ', b2x(tx.serialize()))
VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
print("Script verified, sending raw transaction...")
txid = self.bitcoind.sendrawtransaction(tx)
fund_tx = str(fundtx['outpoint'])
redeem_tx = b2x(lx(b2x(txid)))
return {"redeem_tx": redeem_tx, "fund_tx": fund_tx}
return self.redeem(contract, fundtx, secret)
else:
print("nLocktime exceeded, refunding")
print('refundPubKey', refundPubKey)
txid = self.bitcoind.sendtoaddress(refundPubKey, fundtx['amount'] - FEE)
fund_tx = str(fundtx['outpoint'])
refund_tx = b2x(lx(b2x(txid)))
return {"refund_tx": refund_tx, "fund_tx": fund_tx}
return self.refund(contract)
else:
print("No contract for this p2sh found in database", p2sh)
def redeem(self, contract, fundtx, secret):
print('redeemPubKey', self.redeemPubKey)
# TODO: Compare with script on blockchain?
redeemScript = CScript(x(contract.redeemScript))
txin = CMutableTxIn(fundtx['outpoint'])
txout = CMutableTxOut(fundtx['amount'] - FEE, self.redeemPubKey.to_scriptPubKey())
# Create the unsigned raw transaction.
tx = CMutableTransaction([txin], [txout])
sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL)
# TODO: protect privkey better, separate signing from rawtx creation
privkey = self.bitcoind.dumpprivkey(self.redeemPubKey)
sig = privkey.sign(sighash) + bytes([SIGHASH_ALL])
preimage = secret.encode('utf-8')
txin.scriptSig = CScript([sig, privkey.pub, preimage, OP_TRUE, redeemScript])
# print("txin.scriptSig", b2x(txin.scriptSig))
txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey()
print('Raw redeem transaction hex: ', b2x(tx.serialize()))
VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
print("Script verified, sending raw transaction...")
txid = self.bitcoind.sendrawtransaction(tx)
fund_tx = str(fundtx['outpoint'])
redeem_tx = b2x(lx(b2x(txid)))
return {"redeem_tx": redeem_tx, "fund_tx": fund_tx}
def refund(self, contract):
fundtx = self.find_transaction_to_address(contract.p2sh)
print("Fund tx found in refund: ", fundtx)
refundPubKey = self.find_refundAddr(contract)
print('refundPubKey: {0}'.format(refundPubKey))
redeemScript = CScript(x(contract.redeemScript))
txin = CMutableTxIn(fundtx['outpoint'])
txout = CMutableTxOut(fundtx['amount'] - FEE, refundPubKey.to_scriptPubKey())
# Create the unsigned raw transaction.
tx = CMutableTransaction([txin], [txout])
sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL)
privkey = self.bitcoind.dumpprivkey(refundPubKey)
sig = privkey.sign(sighash) + bytes([SIGHASH_ALL])
# Sign without secret
txin.scriptSig = CScript([sig, privkey.pub, OP_FALSE, redeemScript])
# txin.nSequence = 2185
txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey()
print('Raw redeem transaction hex: {0}'.format(b2x(tx.serialize())))
res = VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
print("Script verified, sending raw transaction... (NOT)", res)
txid = self.bitcoind.sendrawtransaction(tx)
refund_tx = b2x(lx(b2x(txid)))
fund_tx = str(fundtx['outpoint'])
return {"refund_tx": refund_tx, "fund_tx": fund_tx}
def parse_script(self, script_hex):
redeemScript = self.bitcoind.call('decodescript', script_hex)
scriptarray = redeemScript['asm'].split(' ')
@ -210,7 +240,7 @@ class bitcoinProxy():
return redeemAddr
def find_refundAddr(self, contract):
scriptarray = parse_script(contract.redeemScript)
scriptarray = self.parse_script(contract.redeemScript)
funder = scriptarray[13]
refundAddr = P2PKHBitcoinAddress.from_bytes(x(funder))
return refundAddr
@ -220,7 +250,7 @@ class bitcoinProxy():
txs = self.bitcoind.listunspent()
for tx in txs:
if tx['address'] == CBitcoinAddress(p2sh):
print("Found tx to p2sh", p2sh)
logging.debug("Found tx to p2sh: {0}".format(p2sh))
return tx
def new_bitcoin_addr(self):

View File

@ -27,11 +27,12 @@ def checkSellStatus(tradeid):
if 'redeem_tx' in txs:
trade.buy.redeem_tx = txs['redeem_tx']
print("Redeem tx: ", txs['redeem_tx'])
elif 'refund_tx' in txs:
if 'refund_tx' in txs:
trade.buy.redeem_tx = txs['refund_tx']
print("Refund tx: ", txs['refund_tx'])
print("Buyer refund tx: ", txs['refund_tx'])
txs = refund_contract(trade.sell) # Refund to seller
print("Your refund txid: ", txs['refund_tx'])
save_state(trade, tradeid)
# Remove from db? Or just from temporary file storage
cleanup(tradeid)
elif status == 'sellerFunded':
print("Buyer has not yet funded the contract where you offered to buy {0}, please wait for them to complete their part.".format(trade.buy.currency))
@ -101,6 +102,7 @@ def checkBuyStatus(tradeid):
save_state(trade, tradeid)
print("XCAT trade complete!")
else:
# Search if tx has been refunded from p2sh
print("Secret not found in redeemtx")
# Import a trade in hex, and save to db
@ -173,9 +175,9 @@ def checktrade(tradeid):
def newtrade(tradeid, **kwargs):
print("Creating new XCAT trade...")
erase_trade()
tradeid, trade= initialize_trade(tradeid, conf=kwargs['conf'])
print("Trade", trade)
trade = seller_init(tradeid, trade)
tradeid, trade= initialize_trade(tradeid, conf=kwargs['conf'], network=kwargs['network'])
print("New trade created: {0}".format(trade))
trade = seller_init(tradeid, trade, network=kwargs['network'])
print("\nUse 'xcat exporttrade [tradeid]' to export the trade and sent to the buyer.\n")
save_state(trade, tradeid)
return trade
@ -199,12 +201,24 @@ def main():
'''))
parser.add_argument("command", action="store", help="list commands")
parser.add_argument("arguments", action="store", nargs="*", help="add arguments")
parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode. Defaults to false")
parser.add_argument("-w", "--wormhole", action="store_true", help="Transfer trade data through magic-wormhole")
parser.add_argument("-c", "--conf", action="store", help="Use default trade data in conf file.")
parser.add_argument("-n", "--network", action="store", help="Set network to regtest or mainnet. Defaults to testnet while in alpha.")
# parser.add_argument("--daemon", "-d", action="store_true", help="Run as daemon process")
args = parser.parse_args()
if args.debug:
numeric_level = getattr(logging, 'DEBUG', None)
logging.basicConfig(format='%(levelname)s: %(message)s', level=numeric_level)
else:
logging.basicConfig(format='%(levelname)s: %(message)s', level='INFO')
if args.network:
NETWORK = args.network
else:
NETWORK = 'testnet'
command = args.command
if command == 'importtrade':
if args.wormhole:
@ -234,9 +248,9 @@ def main():
if len(args.arguments) < 1: throw("Usage: newtrade [tradeid]")
tradeid = args.arguments[0]
if args.conf == None:
newtrade(tradeid, network=args.network, conf='cli')
newtrade(tradeid, network=NETWORK, conf='cli')
else:
newtrade(tradeid, network=args.network, conf=args.conf)
newtrade(tradeid, network=NETWORK, conf=args.conf)
elif command == "daemon":
#TODO: not implemented
print("Run as daemon process")
@ -248,8 +262,10 @@ def main():
tradeid = args.arguments[0]
checkBuyStatus(tradeid)
elif command == "step3":
generate(31)
tradeid = args.arguments[0]
checkSellStatus(tradeid)
elif command == "step4":
# generate(1)
tradeid = args.arguments[0]
checkBuyStatus(tradeid)

View File

@ -8,24 +8,35 @@ import xcat.db as db
from xcat.xcatconf import *
from xcat.bitcoinRPC import bitcoinProxy
from xcat.zcashRPC import zcashProxy
import logging
bitcoinRPC = bitcoinProxy()
zcashRPC = zcashProxy()
def generate(num):
bitcoinRPC.generate(num)
zcashRPC.generate(num)
def is_myaddr(address):
# Handle different network prefixes
if address[:1] == 'm':
status = bitcoinRPC.validateaddress(address)
else:
status = zcashRPC.validateaddress(address)
status = status['ismine']
# print("Address {0} is mine: {1}".format(address, status))
logging.debug("Address status: ", status)
if status['isvalid'] is False:
raise ValueError("Invalid address: %s" % address)
elif 'ismine' in status:
status = status['ismine']
return status
def find_secret_from_fundtx(currency, p2sh, fundtx):
if currency == 'bitcoin':
secret = bitcoinRPC.find_secret(p2sh, fundtx)
else:
elif currency == 'zcash':
secret = zcashRPC.find_secret(p2sh, fundtx)
else:
raise ValueError("Currency not recognized: ", currency)
return secret
def import_addrs(trade):
@ -36,17 +47,21 @@ def check_p2sh(currency, address):
if currency == 'bitcoin':
print("Checking funds in Bitcoin p2sh")
return bitcoinRPC.check_funds(address)
else:
elif currency == 'zcash':
print("Checking funds in Zcash p2sh")
return zcashRPC.check_funds(address)
else:
raise ValueError("Currency not recognized: ", currency)
def check_fund_status(currency, address):
if currency == 'bitcoin':
print("Checking funds in Bitcoin p2sh")
return bitcoinRPC.get_fund_status(address)
else:
elif currency == 'zcash':
print("Checking funds in Zcash p2sh")
return zcashRPC.get_fund_status(address)
else:
raise ValueError("Currency not recognized: ", currency)
# TODO: function to calculate appropriate locktimes between chains
# def verify_p2sh(trade):
@ -61,17 +76,50 @@ def check_fund_status(currency, address):
def create_htlc(currency, funder, redeemer, commitment, locktime):
if currency == 'bitcoin':
sell_p2sh = bitcoinRPC.hashtimelockcontract(funder, redeemer, commitment, locktime)
else:
elif currency == 'zcash':
sell_p2sh = zcashRPC.hashtimelockcontract(funder, redeemer, commitment, locktime)
else:
raise ValueError("Currency not recognized: ", currency)
return sell_p2sh
def fund_htlc(currency, p2sh, amount):
if currency == 'bitcoin':
txid = bitcoinRPC.fund_htlc(p2sh, amount)
else:
elif currency == 'zcash':
txid = zcashRPC.fund_htlc(p2sh, amount)
else:
raise ValueError("Currency not recognized: ", currency)
return txid
def redeem_p2sh(contract, secret):
currency = contract.currency
if currency == 'bitcoin':
res = bitcoinRPC.redeem_contract(contract, secret)
elif currency == 'zcash':
res = zcashRPC.redeem_contract(contract, secret)
else:
raise ValueError("Currency not recognized: ", currency)
return res
def refund_contract(contract):
currency = contract.currency
if currency == 'bitcoin':
res = bitcoinRPC.refund(contract)
elif currency == 'zcash':
res = zcashRPC.refund(contract)
else:
raise ValueError("Currency not recognized: ", currency)
return res
def parse_secret(currency, txid):
if currency == 'bitcoin':
secret = bitcoinRPC.parse_secret(txid)
elif currency == 'zcash':
secret = zcashRPC.parse_secret(txid)
else:
raise ValueError("Currency not recognized: ", currency)
return secret
def fund_contract(contract):
txid = fund_htlc(contract.currency, contract.p2sh, contract.amount)
return txid
@ -109,21 +157,6 @@ def create_buy_p2sh(trade, commitment, locktime):
save(trade)
def redeem_p2sh(contract, secret):
currency = contract.currency
if currency == 'bitcoin':
res = bitcoinRPC.redeem_contract(contract, secret)
else:
res = zcashRPC.redeem_contract(contract, secret)
return res
def parse_secret(chain, txid):
if chain == 'bitcoin':
secret = bitcoinRPC.parse_secret(txid)
else:
secret = zcashRPC.parse_secret(txid)
return secret
#### Main functions determining user flow from command line
def buyer_redeem(trade):
userInput.authorize_buyer_redeem(trade)
@ -148,7 +181,6 @@ def buyer_redeem(trade):
def seller_redeem_p2sh(trade, secret):
buy = trade.buy
userInput.authorize_seller_redeem(buy)
if trade.sell.get_status() == 'redeemed':
print("You already redeemed the funds and acquired {0} {1}".format(buy.amount, buy.currency))
exit()
@ -203,11 +235,10 @@ def initialize_trade(tradeid, **kwargs):
print(trade.buy.__dict__)
return tradeid, trade
def seller_init(tradeid, trade):
def seller_init(tradeid, trade, network):
secret = generate_password()
db.save_secret(tradeid, secret)
print("\nGenerated a secret preimage to lock funds. This will only be stored locally: ", secret)
print("Generated a secret preimage to lock funds. This will only be stored locally: {0}".format(secret))
hash_of_secret = sha256(secret)
# TODO: Implement locktimes and mock block passage of time
@ -220,5 +251,5 @@ def seller_init(tradeid, trade):
create_buy_p2sh(trade, hash_of_secret, buy_locktime)
trade.commitment = b2x(hash_of_secret)
print("TRADE after seller init", trade.toJSON())
print("TRADE after seller init: {0}".format(trade.toJSON()))
return trade

View File

@ -2,6 +2,7 @@ from xcat.utils import *
from xcat.db import *
from xcat.bitcoinRPC import bitcoinProxy
from xcat.zcashRPC import zcashProxy
from xcat.xcatconf import *
def enter_trade_id():
tradeid = input("Enter a unique identifier for this trade: ")

View File

@ -17,9 +17,11 @@ ADDRS = {
"zcash": "tmTF7LMLjvEsGdcepWPUsh4vgJNrKMWwEyc"
},
"fulfiller": {
"bitcoin": "mm2smEJjRN4xoijEfpb5XvYd8e3EYWezom",
"zcash": "tmPwPdceaJAHQn7UiRCVnJ5tXBXHVqWMkis"
"bitcoin": "mn2boR7rYq9DaAWWrVN5MazHKFyf7UhdyU",
"zcash": "tmErB22A1G74aq32aAh5AoqgQSJsAAAdT2p"
},
"amounts": {'buy': {'currency': 'zcash', 'amount': 0.02}, 'sell': {'currency': 'bitcoin', 'amount': 0.01}}
}
}
NETWORK = 'testnet'

View File

@ -12,6 +12,7 @@ from zcash.core import b2x, lx, x, b2lx, COIN, COutPoint, CMutableTxOut, CMutabl
from zcash.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_ENDIF, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL, OP_FALSE, OP_DROP, OP_CHECKLOCKTIMEVERIFY, OP_SHA256, OP_TRUE
from zcash.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH
from zcash.wallet import CBitcoinAddress, CBitcoinSecret, P2SHBitcoinAddress, P2PKHBitcoinAddress
import logging
from xcat.utils import x2s
@ -104,6 +105,7 @@ class zcashProxy():
for tx in txs:
raw = self.zcashd.gettransaction(lx(tx['txid']))['hex']
decoded = self.zcashd.decoderawtransaction(raw)
# print("TXINFO", decoded['vin'][0])
if('txid' in decoded['vin'][0]):
sendid = decoded['vin'][0]['txid']
if (sendid == fundtx_input ):
@ -112,14 +114,42 @@ class zcashProxy():
print("Redeem transaction with secret not found")
return
# def find_secret(self, p2sh, fundtx_input):
# print("In find secret zcashrpc")
# txs = self.zcashd.call('listtransactions', "*", 200, 0, True)
# for tx in txs:
# if tx['address'] == p2sh: # Only check txs involving imported p2sh
# raw = self.zcashd.gettransaction(lx(tx['txid']))['hex']
# decoded = self.zcashd.decoderawtransaction(raw)
# print('decoded', decoded)
# if('txid' in decoded['vin'][0]):
# sendid = decoded['vin'][0]['txid']
# print("sendid", sendid)
# if (sendid == fundtx_input ):
# print("Found funding zcash tx: ", sendid)
# res = self.parse_secret(lx(tx['txid']))
# secret = res[0]
# redeemPubkey = res[1]
# if secret is None:
# print("Secret not found")
# res = self.validateaddress(redeemPubkey)
# if res['ismine']:
# print("Funding tx already refunded. Sent to your address {0}".format(redeemPubkey))
# logging.debug("Redeem transaction with secret not found")
# return
def parse_secret(self, txid):
raw = self.zcashd.gettransaction(txid, True)['hex']
decoded = self.zcashd.decoderawtransaction(raw)
scriptSig = decoded['vin'][0]['scriptSig']
asm = scriptSig['asm'].split(" ")
pubkey = asm[1]
secret = x2s(asm[2])
redeemPubkey = P2PKHBitcoinAddress.from_pubkey(x(pubkey))
try:
secret = x2s(asm[2])
except:
secret = None
self.redeemPubkey = P2PKHBitcoinAddress.from_pubkey(x(pubkey))
print("redeemPubkey: ", self.redeemPubkey)
return secret
def redeem_contract(self, contract, secret):
@ -136,48 +166,69 @@ class zcashProxy():
p2sh = P2SHBitcoinAddress(p2sh)
if fundtx['address'] == p2sh:
print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh))
# Where can you find redeemblocknum in the transaction?
# redeemblocknum = find_redeemblocknum(contract)
blockcount = self.zcashd.getblockcount()
print("\nCurrent blocknum at time of redeem on Zcash:", blockcount)
if blockcount < contract.redeemblocknum:
# TODO: parse the script once, up front.
redeemPubKey = self.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 = self.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])
txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey()
print('Raw redeem transaction hex: ', b2x(tx.serialize()))
VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
print("Script verified, sending raw redeem transaction...")
txid = self.zcashd.sendrawtransaction(tx)
redeem_tx = b2x(lx(b2x(txid)))
fund_tx = str(fundtx['outpoint'])
return {"redeem_tx": redeem_tx, "fund_tx": fund_tx}
return self.redeem(contract, fundtx, secret)
else:
print("nLocktime exceeded, refunding")
refundPubKey = self.find_refundAddr(contract)
print('refundPubKey', refundPubKey)
txid = self.zcashd.sendtoaddress(refundPubKey, fundtx['amount'] - FEE)
refund_tx = b2x(lx(b2x(txid)))
fund_tx = str(fundtx['outpoint'])
return {"refund_tx": refund_tx, "fund_tx": fund_tx}
return self.refund(contract)
else:
print("No contract for this p2sh found in database", p2sh)
def redeem(self, contract, fundtx, secret):
# TODO: parse the script once, up front.
redeemPubKey = self.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 = self.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])
txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey()
print('Raw redeem transaction hex: ', b2x(tx.serialize()))
VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
print("Script verified, sending raw redeem transaction...")
txid = self.zcashd.sendrawtransaction(tx)
redeem_tx = b2x(lx(b2x(txid)))
fund_tx = str(fundtx['outpoint'])
return {"redeem_tx": redeem_tx, "fund_tx": fund_tx}
def refund(self, contract):
fundtx = self.find_transaction_to_address(contract.p2sh)
print("Fund tx found in refund: ", fundtx)
refundPubKey = self.find_refundAddr(contract)
print('refundPubKey: {0}'.format(refundPubKey))
redeemScript = CScript(x(contract.redeemScript))
txin = CMutableTxIn(fundtx['outpoint'])
txout = CMutableTxOut(fundtx['amount'] - FEE, refundPubKey.to_scriptPubKey())
# Create the unsigned raw transaction.
tx = CMutableTransaction([txin], [txout])
sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL)
privkey = self.zcashd.dumpprivkey(refundPubKey)
sig = privkey.sign(sighash) + bytes([SIGHASH_ALL])
# Sign without secret
txin.scriptSig = CScript([sig, privkey.pub, OP_FALSE, redeemScript])
# txin.nSequence = 2185
txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey()
print('Raw redeem transaction hex: {0}'.format(b2x(tx.serialize())))
res = VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
print("Script verified, sending raw transaction... (NOT)", res)
txid = self.zcashd.sendrawtransaction(tx)
refund_tx = b2x(lx(b2x(txid)))
fund_tx = str(fundtx['outpoint'])
return {"refund_tx": refund_tx, "fund_tx": fund_tx}
def parse_script(self, script_hex):
redeemScript = self.zcashd.decodescript(script_hex)
scriptarray = redeemScript['asm'].split(' ')