107 lines
4.1 KiB
Python
107 lines
4.1 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
# Based on spend-p2sh-txout.py from python-bitcoinlib.
|
||
|
# Copyright (C) 2017 The Zcash developers
|
||
|
|
||
|
import sys
|
||
|
if sys.version_info.major < 3:
|
||
|
sys.stderr.write('Sorry, Python 3.x required by this example.\n')
|
||
|
sys.exit(1)
|
||
|
|
||
|
import bitcoin
|
||
|
import bitcoin.rpc
|
||
|
from bitcoin import SelectParams
|
||
|
from bitcoin.core import b2x, lx, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, Hash160
|
||
|
from bitcoin.core.script import CScript, OP_DUP, OP_IF, OP_ELSE, OP_ENDIF, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL
|
||
|
from bitcoin.core.script import 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
|
||
|
|
||
|
import hashlib
|
||
|
|
||
|
# SelectParams('testnet')
|
||
|
# To get transactions not in your wallet, must set -txindex=1
|
||
|
SelectParams('regtest')
|
||
|
proxy = bitcoin.rpc.Proxy()
|
||
|
|
||
|
# The parameters needed for the htlc - hash preimage, sender/seller address, recipient/buyer address, num of blocks for timeout
|
||
|
preimage = b'preimage'
|
||
|
h = hashlib.sha256(preimage).digest()
|
||
|
|
||
|
# proxy.getnewaddress() returns CBitcoinAddress
|
||
|
recipientpubkey = proxy.getnewaddress()
|
||
|
senderpubkey = proxy.getnewaddress()
|
||
|
# privkey of the recipient, used to sign the redeemTx
|
||
|
seckey = proxy.dumpprivkey(senderpubkey)
|
||
|
|
||
|
lockduration = 10
|
||
|
blocknum = proxy.getblockcount()
|
||
|
print("current block num:", blocknum)
|
||
|
redeemblocknum = blocknum + lockduration
|
||
|
# Create a htlc redeemScript. Similar to a scriptPubKey the redeemScript must be
|
||
|
# satisfied for the funds to be spent.
|
||
|
txin_redeemScript = CScript([OP_IF, OP_SHA256, h, OP_EQUALVERIFY,OP_DUP, OP_HASH160,
|
||
|
recipientpubkey, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160,
|
||
|
senderpubkey, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG])
|
||
|
print("redeem script:", b2x(txin_redeemScript))
|
||
|
|
||
|
# Create P2SH scriptPubKey from redeemScript.
|
||
|
txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
|
||
|
print("p2sh_scriptPubKey", b2x(txin_scriptPubKey))
|
||
|
|
||
|
# Convert the P2SH scriptPubKey to a base58 Bitcoin address
|
||
|
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
|
||
|
p2sh = str(txin_p2sh_address)
|
||
|
print('Pay to:', p2sh)
|
||
|
|
||
|
# AUTOMATE Send funds to p2sh
|
||
|
amount = 1.0*COIN
|
||
|
fund_tx = proxy.sendtoaddress(txin_p2sh_address, amount)
|
||
|
|
||
|
print('Now redeeming.........')
|
||
|
|
||
|
print('Jumping forward till after timelock')
|
||
|
proxy.generate(lockduration)
|
||
|
print('block num is now:', proxy.getblockcount())
|
||
|
# AUTOMATE getting vout of funding tx
|
||
|
txinfo = proxy.gettransaction(fund_tx)
|
||
|
details = txinfo['details'][0]
|
||
|
vout = details['vout']
|
||
|
|
||
|
# Create the txin structure. scriptSig defaults to being empty.
|
||
|
# The input is the p2sh funding transaction txid, vout is its index
|
||
|
txin = CMutableTxIn(COutPoint(fund_tx, vout))
|
||
|
|
||
|
# The default nSequence of FFFFFFFF won't let you redeem when there's a CHECKTIMELOCKVERIFY
|
||
|
txin.nSequence = 0
|
||
|
|
||
|
# Create the txout. Pays out to recipient, so uses recipient's pubkey
|
||
|
# Withdraw full amount minus fee
|
||
|
default_fee = 0.001*COIN
|
||
|
txout = CMutableTxOut(amount - default_fee, recipientpubkey.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
|
||
|
tx.nLockTime=redeemblocknum
|
||
|
|
||
|
# Calculate the signature hash for that transaction. Note how the script we use
|
||
|
# is the redeemScript, not the scriptPubKey. EvalScript() will be evaluating the redeemScript
|
||
|
sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL)
|
||
|
|
||
|
# Now sign it. We have to append the type of signature we want to the end, in
|
||
|
# this case the usual SIGHASH_ALL.
|
||
|
sig = seckey.sign(sighash) + bytes([SIGHASH_ALL])
|
||
|
|
||
|
# Set the scriptSig of our transaction input appropriately.
|
||
|
txin.scriptSig = CScript([sig, seckey.pub, OP_FALSE, txin_redeemScript])
|
||
|
|
||
|
print("Redeem tx hex:", b2x(tx.serialize()))
|
||
|
|
||
|
# Verify the signature worked.
|
||
|
VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,))
|
||
|
|
||
|
print("Now sending redeem transaction.......")
|
||
|
txid = proxy.sendrawtransaction(tx)
|
||
|
print("Txid of submitted redeem tx: ", b2x(txid))
|