full edit

This commit is contained in:
Shannon Appelcline 2020-09-08 09:36:54 -10:00 committed by GitHub
parent 25d20e92c0
commit 2999fe0246
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -334,161 +334,131 @@ UTXO Details:
---------------------------------------------------------------
```
## Sending Transactions
## Creating an Address
Now that we have established comfort between our python and bitcoind interface, lets create and broadcast a transaction. For the purposes of this course, we will send test bitcoins to an address generated by us in our testnet wallet. Here's how we will do it:
1. Create 2 addresses, one that will act as recipient and the other for change.
2. Select a UTXO and set transaction details.
3. Create a raw transaction.
4. Sign the raw transaction with private key of the UTXO.
5. Broadcast the transaction on the bitcoin testnet.
### 1. Create New Addresses
For the purposes of learning, we will send bitcoins to an address generated by our node. We also generate a change address to receive back change from the difference between input and recipient amounts (less the miner fees). For this we use `getrawchangeaddress`. It's largely the same as `getnewaddress` but is optimized for use as a change address in a raw transaction, so it doesn't do things like make entries in your address book.
```py
print("Creating a Transaction")
## Create New Addresses
Creating a new address with Python 3 just requires the use of an RPC like `getnewaddress` or `getrawchangeaddress`.
```
new_address = rpc_client.getnewaddress("Learning-Bitcoin-from-the-Command-Line")
new_change_address = rpc_client.getrawchangeaddress()
```
In this example, we give the `getnewaddress` command an argument: the `Learning-Bitcoin-from-the-Command-Line` label.
### 2. Select UTXO & Set Transaction Details
## Sending a Transaction
In the folowing code snippet we first select the UTXO which we want to spend. Then we get its address, transaction id, and the vector index of the output. Finally, we add the recipient address to which we want to send the bitcoins, enter the amount of bitcoins we want to send, set the miner fee, and calculate the change amount.
Creating a transaction in Python 3 requires combining some of the previous examples (of creating addresses and retrieving UTXOs) with some new RPC commands for creating, signing, and sending a transaction — much as you've done previously from the command line.
There are five steps:
0. Create 2 addresses, one that will act as recipient and the other for change.
1. Select a UTXO and set transaction details.
2. Create a raw transaction.
3. Sign the raw transaction with private key of the UTXO.
4. Broadcast the transaction on the bitcoin testnet.
### 1. Select UTXO & Set Transaction Details
In the folowing code snippet you first select the UTXO which we want to spend. Then you get its address, transaction id, and the vector index of the output.
```py
utxos = rpc_client.listunspent()
selected_utxo = utxos[0] # we select the first utxo here
utxo_address = selected_utxo['address']
utxo_txid = selected_utxo['txid']
utxo_vout = selected_utxo['vout']
utxo_amt = float(selected_utxo['amount'])
# here we are sending bitcoins to an address generated by us in our own wallet.
```
Next, you also retrieve the recipient address to which we want to send the bitcoins and the amount of bitcoins you want to send, and you calculate the miner fee and the change amount. Here, the amount is arbitrarily split in two and a miner fee is arbitrarily set.
```py
recipient_address = new_address
recipient_amt = utxo_amt / 2 # sending half coins to recipient
miner_fee = 0.00000200 # choose appropriate fee based on your tx size
miner_fee = 0.00000300 # choose appropriate fee based on your tx size
change_address = new_change_address
change_amt = float('%.8f'%((utxo_amt - recipient_amt) - miner_fee))
print("---------------------------------------------------------------")
print("Transaction Details:")
print("-------------------")
print("UTXO Address.......: ", utxo_address)
print("UTXO Txid..........: ", utxo_txid)
print("Vector ID of Output: ", utxo_vout)
print("UTXO Amount........: ", utxo_amt)
print("Tx Amount..........: ", recipient_amt)
print("Recipient Address..: ", recipient_address)
print("Change Address.....: ", change_address)
print("Miner Fee..........: ", miner_fee)
print("Change Amount......: ", change_amt)
print("---------------------------------------------------------------\n")
```
Your output will be similar to the following:
> :warning: **WARNING:** Obviously a real program would make more sophisticated choices about what UTXO to use, what to do with the funds, and what miner's fee to pay.
```sh
---------------------------------------------------------------
Transaction Details:
-------------------
UTXO Address.......: 2NHkixaDUBQ8qz7oV3obwWbYXeRzsJwYTg
UTXO Txid..........: b90sl97lfc2bfc0f16761fd1bb5f27f86e88eab440f5578fefe47143b5e4232b
Vector ID of Output: 1
UTXO Amount........: 0.01
Tx Amount..........: 0.005
Recipient Address..: 2NOLScQAYV3QH21my3kXrmn1ykTnTWXBPZ6
Change Address.....: 2NABxEDoVs85b9owihT8HGNFSnPPJTDVsFC
Miner Fee..........: 0.000002
Change Amount......: 0.004998
---------------------------------------------------------------
```
### 2. Create Raw Transacion
### 3. Create Raw Transacion
Now we have all the information to send a transaction, but before we can send one, we have to create a transaction. We do that by creating a raw transaction, like so:
Now you have all the information to send a transaction, but before you can send one, you have to create a transaction.
```py
txids_vouts = [{"txid": utxo_txid, "vout": utxo_vout}]
addresses_amts = {f"{recipient_address}": recipient_amt, f"{change_address}": change_amt}
create_raw_tx = rpc_client.createrawtransaction(txids_vouts, addresses_amts)
unsigned_tx_hex = create_raw_tx
print("---------------------------------------------------------------")
print("Unsigned Transaction Hex: ", unsigned_tx_hex)
print("---------------------------------------------------------------\n")
unsigned_tx_hex = rpc_client.createrawtransaction(txids_vouts, addresses_amts)
```
This will return the hex of the raw transaction:
```sh
---------------------------------------------------------------
Unsigned Transaction Hex: 02000000012b23e4b54371e4ef8f57f540b4ea88slk8275fbbd11f76160ffc2bfc10da18b80100000000ffffffff0220a107000000000017a914e573193a39esl9ld930127551fcef86aaa47f82f8758a007000000000017a914ls90d0497b0fef38642f64ba0c8148adf0fb1d0c8700000000
---------------------------------------------------------------
```
The format of the `createrawtransaction` command is:
Remember that the format of the `createrawtransaction` command is:
`$ bitcoin-cli createrawtransaction '[{"txid": <utxo_txid>, "vout": <vector_id>}]' '{"<address>": <amount>}'`
The `txids_vouts` is a list and `addresses_amts` is a python dictionary to match with the format of `createrawtransaction`.
The `txids_vouts` is thus a list and the `addresses_amts` is a python dictionary, to match with the format of `createrawtransaction`.
Try checking the details of the transaction, hint: use `decoderawtransaction`.
If you want to see more about the details of the transaction that you've created, you can use `decoderawtransaction`, either in Python 3 or with `bitcoin-cli`.
### 4. Sign Raw Transaction
Now that we have a raw transaction, we use its hex and the private key of the UTXOs we are spending, in order to sign the transaction like so:
### 3. Sign Raw Transaction
Signing a transaction is often the trickiest part of sending a transaction programmatically. Here you retrieve a private key from an address with `dumpprivkey` and place it in an array:
```py
address_priv_key = [] # list of priv keys of each utxo
address_priv_key.append(rpc_client.dumpprivkey(utxo_address))
```
You can then use that array (which should contain the private keys of every UTXO that is being spent) to sign your `unsigned_tx_hex`:
```py
signed_tx = rpc_client.signrawtransactionwithkey(unsigned_tx_hex, address_priv_key)
print("---------------------------------------------------------------")
print("Signed Transaction: ")
print("----------------------")
pprint(signed_tx)
print("---------------------------------------------------------------\n")
```
This returns a JSON object with the signed transaction's hex, and whether it was signed completely or not:
```sh
---------------------------------------------------------------
Signed Transaction:
----------------------
{'complete': True,
'hex': '020000000001012b23e4b5438904ef8f57f540b4ea886ef8275fbbd11f76160ffc2bfc10da18b80100000017160014c5d04b36b7b45eb9c5e4716272e3c955a6041fc2ffffffff0220a107000000000017a914e573193a39ed74dd930127551fcef86aaa47f82f8758a007000000000017a914e7d0osl97b0fef38642f64ba0c8148adf0fb1d0c8702463043021f4e2855813369bbf08288fa8bc670a48c1b27873646296c5cdabd50ee7790810220516f03c20a72f8985fd3bd5549dkfc68993909c28ffeffb5d277456f65384e60012103fa812ff869d1839e1b1d5c9532413b0ls2dcd21c334e727d9ee221c7a151591a400000000'}
---------------------------------------------------------------
```
### 4. Broadcast Transaction
### Broadcast Transaction
Finally, we are now ready to broadcast our signed transaction on the bitcoin network like so:
Finally, you are ready to broadcast the signed transaction on the bitcoin network:
```py
send_tx = rpc_client.sendrawtransaction(signed_tx['hex'])
print("---------------------------------------------------------------")
print("TXID of sent transaction: ", send_tx)
print("---------------------------------------------------------------\n")
```
Once the transaction has been broadcasted, bitcoind will return its TXID:
The [sample code](src/17_4_sendtx.py) is full of `print` statements to demonstrate all of the data available at every point:
```
$ python3 sendtx.py
Creating a Transaction
---------------------------------------------------------------
Transaction Details:
-------------------
UTXO Address.......: mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg
UTXO Txid..........: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e
Vector ID of Output: 0
UTXO Amount........: 1e-05
Tx Amount..........: 5e-06
Recipient Address..: tb1qca0elxxqzw5xc0s3yq5qhapzzj90ka0zartu6y
Change Address.....: tb1qrveukqrvqm9h6fua99xvcxgnvdx507dg8e8hrt
Miner Fee..........: 3e-06
Change Amount......: 2e-06
---------------------------------------------------------------
```sh
---------------------------------------------------------------
TXID of sent transaction: 'k9db702lsd512e2421915dc53clkj28f39a987c9a91cc0514faacfef500c6764'
Unsigned Transaction Hex: 02000000015e53fb6f63b7defa28e61c28cfc3033361138a0d33dd1fad29ae58c6fe7f20840000000000ffffffff02f401000000000000160014c75f9f98c013a86c3e1120280bf422148afb75e2c8000000000000001600141b33cb006c06cb7d279d294ccc1913634d47f9a800000000
---------------------------------------------------------------
---------------------------------------------------------------
Signed Transaction:
----------------------
{'complete': True,
'hex': '02000000015e53fb6f63b7defa28e61c28cfc3033361138a0d33dd1fad29ae58c6fe7f2084000000006a47304402205da9b2234ea057c9ef3b7794958db6c650c72dedff1a90d2915147a5f6413f2802203756552aba0dd8ebd71b0f28341becc01b28d8b28af063d7c8ce89f9c69167f8012102d0541b9211aecd25913f7fdecfc1b469215fa326d52067b1b3f7efbd12316472ffffffff02f401000000000000160014c75f9f98c013a86c3e1120280bf422148afb75e2c8000000000000001600141b33cb006c06cb7d279d294ccc1913634d47f9a800000000'}
---------------------------------------------------------------
---------------------------------------------------------------
TXID of sent transaction: 187f8baa222f9f37841d966b6bad59b8131cfacca861cbe9bfc8656bd16a44cc
```
## Summary
In this chapter we learned how to connect to a node, get some basic information about our node, and even sent a transaction over testnet.
Accessing Bitcoind with Python is very easy while using the `python-bitcoinrpc` library. The first thing to always do is to establish connection with your bitcoind instance, then you can basically call all the bitcoin API calls as described in the bitcoin-core documentation. This makes it really easy to create small or large scripts to manage your own node, check balances, or create cool applications on top as you get the full power of `bitcoin-cli`.
Accessing Bitcoind with Python is very easy while using the `python-bitcoinrpc` library. The first thing to always do is to establish connection with your bitcoind instance, then you can call all of the bitcoin API calls as described in the bitcoin-core documentation. This makes it really easy to create small or large scripts to manage your own node, check balances, or create cool applications on top as you access the full power of `bitcoin-cli`.
All the source code for this chapter is available in the [src](./src/18_4_accessing_bitcoind_with_python.py) directory of the repo.
## What's Next?
[...]
Learn more about "Talking to Bitcoin in Other Languages" in [17.5: Accessing Bitcoin with Rust](17_5_Accessing_Bitcoind_with_Rust.md).
## Synopsis: Building Python from Source