def refund(proxy, refundGuy, contract): redeemScript = CScript(x(contract['redeemScript'])) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, refundGuy['addr'].to_scriptPubKey()) tx = CMutableTransaction([txin], [txout]) txin.nSequence = 0 tx.nLockTime = contract['redeemblocknum'] sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) sig = refundGuy['key'].sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([sig, refundGuy['key'].pub, OP_FALSE, redeemScript]) 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 = proxy.sendrawtransaction(tx) refund_tx = b2x(lx(b2x(txid))) fund_tx = str(fundtx['outpoint']) return {"refund_tx": refund_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]) # Set nSequence and nLockTime txin.nSequence = 0 tx.nLockTime = contract.redeemblocknum 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 redeem_after_timelock(contract): p2sh = contract.p2sh fundtx = find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN if (fundtx['address'].__str__() != p2sh): print("no fund transaction found to the contract p2sh address ", p2sh) quit() print("Found fundtx:", fundtx) # Parsing redeemblocknum from the redeemscript of the p2sh redeemblocknum = find_redeemblocknum(contract) blockcount = bitcoind.getblockcount() print("Current block:", blockcount, "Can redeem from block:", redeemblocknum) if (still_locked(contract)): print("too early for redeeming with timelock try again at block", redeemblocknum, "or later") return 0 print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) redeemPubKey = find_refundAddr(contract) print('refundPubKey', redeemPubKey) redeemScript = CScript(x(contract.redeemScript)) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. txin.nSequence = 0 tx = CMutableTransaction([txin], [txout]) tx.nLockTime = redeemblocknum sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) # TODO: figure out how to better protect privkey privkey = bitcoind.dumpprivkey(redeemPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([sig, privkey.pub, OP_FALSE, 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)))
# Same as the txid:vout the createrawtransaction RPC call requires # # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin # transaction hashes are shown little-endian rather than the usual big-endian. # There's also a corresponding x() convenience function that takes big-endian # hex and converts it to bytes. txid = lx('6d500966f9e494b38a04545f0cea35fc7b3944e341a64b804fed71cdee11d434') vout = 1 amount = 0.00009999 * COIN amount_less_fees = amount - 200 # Create the txin structure, which includes the outpoint. The scriptSig # defaults to being empty. txin = CMutableTxIn(COutPoint(txid, vout)) binzero = 2**32 txin.nSequence = binzero - 3 # Create the txout. This time we create the scriptPubKey from a Bitcoin # address. txout = CMutableTxOut( amount_less_fees, CBitcoinAddress( 'tb1qv9hg20f0g08d460l67ph6p4ukwt7m0ttqzj7mk').to_scriptPubKey()) # Create the unsigned transaction. tx = CMutableTransaction([txin], [txout]) tx.nLockTime = nLockTime # Calculate the signature hash for that transaction. Note how the script we use # is the redeemScript, not the scriptPubKey. That's because when the CHECKSIG # operation happens EvalScript() will be evaluating the redeemScript, so the
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, senderpubkey.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)
]) # Generate a P2SH address from the locking script txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) # Load the htlc amount = 1.0*COIN fund_tx = proxy.sendtoaddress(txin_p2sh_address, amount) # Construct the transaction which will redeem the htlc via the second payment route txinfo = proxy.gettransaction(fund_tx) txin = CMutableTxIn(COutPoint(fund_tx, txinfo['details'][0]['vout'])) # By default, python-bitcoinlib disables locktime via nSequence, so we must enable txin.nSequence = 0xfffffffe default_fee = 0.001*COIN txout = CMutableTxOut(amount - default_fee, senderpubkey.to_scriptPubKey()) tx = CMutableTransaction([txin], [txout]) tx.nLockTime = redeemblocknum # Sign the redeem script with Alice's private key ( for whose address the first payment path # is set up exclusively for ) sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) sig = sender_seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Load the script sig of Bob's redemption transaction with the appropriate values txin.scriptSig = CScript([sig, sender_seckey.pub, 0, txin_redeemScript]) from ptpdb import set_trace set_trace()