|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +# Copyright (C) 2020 The python-bitcoinlib developers |
| 4 | +# |
| 5 | +# This file is part of python-bitcoinlib. |
| 6 | +# |
| 7 | +# It is subject to the license terms in the LICENSE file found in the top-level |
| 8 | +# directory of this distribution. |
| 9 | +# |
| 10 | +# No part of python-bitcoinlib, including this file, may be copied, modified, |
| 11 | +# propagated, or distributed except according to the terms contained in the |
| 12 | +# LICENSE file. |
| 13 | + |
| 14 | +"""Low-level example of how to spend a P2WPKH output.""" |
| 15 | + |
| 16 | +import sys |
| 17 | +if sys.version_info.major < 3: |
| 18 | + sys.stderr.write("Sorry, Python 3.x required by this example.\n") |
| 19 | + sys.exit(1) |
| 20 | + |
| 21 | +import hashlib |
| 22 | + |
| 23 | +from bitcoin import SelectParams |
| 24 | +from bitcoin.core import b2x, b2lx, lx, COIN, COutPoint, CTxOut, CTxIn, CTxInWitness, CTxWitness, CScriptWitness, CMutableTransaction, Hash160 |
| 25 | +from bitcoin.core.script import CScript, OP_0, SignatureHash, SIGHASH_ALL, SIGVERSION_WITNESS_V0 |
| 26 | +from bitcoin.wallet import CBitcoinSecret, P2WPKHBitcoinAddress |
| 27 | +from bitcoin.rpc import Proxy |
| 28 | + |
| 29 | +SelectParams("regtest") |
| 30 | +connection = Proxy() |
| 31 | + |
| 32 | +if connection._call("getblockchaininfo")["chain"] != "regtest": |
| 33 | + sys.stderr.write("This example is intended for regtest only.\n") |
| 34 | + sys.exit(1) |
| 35 | + |
| 36 | + |
| 37 | +# Create the (in)famous correct brainwallet secret key. |
| 38 | +h = hashlib.sha256(b'correct horse battery staple').digest() |
| 39 | +seckey = CBitcoinSecret.from_secret_bytes(h) |
| 40 | + |
| 41 | +# Create an address from that private key. |
| 42 | +public_key = seckey.pub |
| 43 | +scriptPubKey = CScript([OP_0, Hash160(public_key)]) |
| 44 | +address = P2WPKHBitcoinAddress.from_scriptPubKey(scriptPubKey) |
| 45 | + |
| 46 | +# Give the private key to bitcoind (for ismine, listunspent, etc). |
| 47 | +connection._call("importprivkey", str(seckey)) |
| 48 | + |
| 49 | +# Check if there's any funds available. |
| 50 | +unspentness = lambda: connection._call("listunspent", 6, 9999, [str(address)], True, {"minimumAmount": 1.0}) |
| 51 | +unspents = unspentness() |
| 52 | +while len(unspents) == 0: |
| 53 | + # mine some funds into the address |
| 54 | + connection._call("generatetoaddress", 110, str(address)) |
| 55 | + unspents = unspentness() |
| 56 | + |
| 57 | +# Choose the first UTXO, let's spend it! |
| 58 | +unspent_utxo_details = unspents[0] |
| 59 | +txid = unspent_utxo_details["txid"] |
| 60 | +vout = unspent_utxo_details["vout"] |
| 61 | +amount = int(float(unspent_utxo_details["amount"]) * COIN) |
| 62 | + |
| 63 | +# Calculate an amount for the upcoming new UTXO. Set a high fee to bypass |
| 64 | +# bitcoind minfee setting. |
| 65 | +amount_less_fee = int(amount - (0.01 * COIN)) |
| 66 | + |
| 67 | +# Create a destination to send the coins. |
| 68 | +destination_address = connection._call("getnewaddress", "python-bitcoinlib-example", "bech32") |
| 69 | +destination_address = P2WPKHBitcoinAddress(destination_address) |
| 70 | +target_scriptPubKey = destination_address.to_scriptPubKey() |
| 71 | + |
| 72 | +# Create the unsigned transaction. |
| 73 | +txin = CTxIn(COutPoint(lx(txid), vout)) |
| 74 | +txout = CTxOut(amount_less_fee, target_scriptPubKey) |
| 75 | +tx = CMutableTransaction([txin], [txout]) |
| 76 | + |
| 77 | +# Specify which transaction input is going to be signed for. |
| 78 | +txin_index = 0 |
| 79 | + |
| 80 | +# When signing a P2WPKH transaction, use an "implicit" script that isn't |
| 81 | +# specified in the scriptPubKey or the witness. |
| 82 | +redeem_script = address.to_redeemScript() |
| 83 | + |
| 84 | +# Calculate the signature hash for the transaction. This is then signed by the |
| 85 | +# private key that controls the UTXO being spent here at this txin_index. |
| 86 | +sighash = SignatureHash(redeem_script, tx, txin_index, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) |
| 87 | +signature = seckey.sign(sighash) + bytes([SIGHASH_ALL]) |
| 88 | + |
| 89 | +# Construct a witness for this transaction input. The public key is given in |
| 90 | +# the witness so that the appropriate redeem_script can be calculated by |
| 91 | +# anyone. The original scriptPubKey had only the Hash160 hash of the public |
| 92 | +# key, not the public key itself, and the redeem script can be entirely |
| 93 | +# re-constructed (from implicit template) if given just the public key. So the |
| 94 | +# public key is added to the witness. This is P2WPKH in bip141. |
| 95 | +witness = [signature, public_key] |
| 96 | + |
| 97 | +# Aggregate all of the witnesses together, and then assign them to the |
| 98 | +# transaction object. |
| 99 | +ctxinwitnesses = [CTxInWitness(CScriptWitness(witness))] |
| 100 | +tx.wit = CTxWitness(ctxinwitnesses) |
| 101 | + |
| 102 | +# Broadcast the transaction to the regtest network. |
| 103 | +spend_txid = connection.sendrawtransaction(tx) |
| 104 | + |
| 105 | +# Done! Print the transaction to standard output. Show the transaction |
| 106 | +# serialization in hex (instead of bytes), and render the txid. |
| 107 | +print("serialized transaction: {}".format(b2x(tx.serialize()))) |
| 108 | +print("txid: {}".format(b2lx(spend_txid))) |
0 commit comments