Goal
Develop a tool for creating a Bitcoin transaction. This tool should have a good command-line interface and a test suite.
Contents
- Goal
- Contents
- Brief Summary
- Summary
- Notes
- Downloadable Assets
- How To Use The Tools
- Future Work
- Project Log
Brief Summary
I've written a tool for creating and signing a Bitcoin transaction. It has robust input validation and optional logging.
Summary
I've written a tool for creating a Bitcoin transaction, and an accompanying test suite:
- create_transaction_4.py
- test_create_transaction_4.py
I used the existing tool create_transaction_3.py as my starting point.
The new tool has various improvements:
- Load all input data from outside the code via command-line arguments.
- More levels of input validation.
- A proper logging system, rather than print statements.
- Restructure into a tree of functions. (This is cleaner and makes it possible to write tests for the individual functions.)
- Write a test suite using onchain Bitcoin transactions.
- Remove "raw byte" option for random K value. (It's best to only use hex bytes internally so that debugging is easier and the data flow is simpler.)
- Include the random K value in the debug log output.
- Generate the txid and include it in the info log output.
- Validate the output addresses and the change address.
- Require private key and K values to be exactly 32 bytes long.
- Handle an input domain bug: Too many decimal places in a Bitcoin amount (details are in comment 2 (item 1) on Edgecase Bitcoin Storage Toolset version 2).
Tool inputs:
- Change address, Bitcoin inputs, Bitcoin outputs, private keys, random values, various control settings.
Tool outputs:
- (optional) Logging output, including the calculated txid.
- A signed transaction in hex bytes.
Notes
Important:
- Bitcoin inputs are actually unspent Bitcoin outputs from previous transactions.
- Each input in a standard Bitcoin transaction requires one ECDSA signature. A new random value must be used for every public ECDSA signature. If the transaction is signed and broadcast, and you create a new variant (e.g. if the first variant was not mined), you must supply a new random value for each input in the transaction. Two signatures made with the same private key and the same random value allows a third party to easily derive the private key.
- The input value that may be spent is limited to a default maximum percentage. All remaining value (minus the fee) will be sent to the change address. If you wish to send more than this percentage to other addresses, you must explicitly provide a new maxSpendPercentage value.
- The fee will be subtracted from the amount sent to the change address. If the fee is greater than the default maximum fee, you will need to explicitly provide a new maximum fee value.
Working definition of a standard transaction:
- It has at least one input and at least one output.
- All input and output addresses are Pay-To-Public-Key-Hash (P2PKH).
- All input scriptSigs contain uncompressed public keys.
For test data, I used Bitcoin transaction test set #2 as my source.
- The addresses that correspond to the private keys in the test transactions are available in Bitcoin address test set #2.
- Some transaction creation tests use fee rates instead of fees. These fee rates are available in comment 2 on the source article.
Logging:
- Logging at "info" level provides useful information: A bird's-eye view of the process.
- Logging at "debug" level provides a large amount of detailed information, including secret values (private keys and random values).
- At log level "info", the txid is printed just before the signed transaction.
- The txid is calculated by applying the SHA256 hash algorithm twice to the signed transaction binary data, and then converting the result to little-endian.
- Due to Transaction Malleability (transaction signatures can be slightly altered in-flight by third parties without compromising their validity), for some mined transactions the final txid may differ from the calculated version.
Downloadable Assets
Assets of this article:
List:
- create_transaction_4.py
- test_create_transaction_4.py
- test_create_transaction_4.py
Asset: A tool that creates and signs a standard Bitcoin transaction. Python 2.7.12.
create_transaction_4.py
Asset: A test suite for the transaction creation tool. Python 2.7.12, Pytest 4.6.11.
test_create_transaction_4.py
Assets of other articles:
List:
- bitcoin_functions_2.py
- bjorn_edstrom_ripemd160.py
- ecdsa-0.10.tar.gz
- pypy_sha256.py
- transaction_3.py
- bjorn_edstrom_ripemd160.py
- ecdsa-0.10.tar.gz
- pypy_sha256.py
- transaction_3.py
Asset: A library of functions for handling standard Bitcoin data types. Python 2.7.
bitcoin_functions_2.py [paywalled]
Asset: An implementation of RIPEMD-160, written by Björn Edström. Python 2.7.
bjorn_edstrom_ripemd160.py [paywalled]
Asset: A Python implementation of ECDSA cryptography, written by Peter Pearson. Python 2.7.
ecdsa-0.10.tar.gz [paywalled]
Asset: A Python implementation of SHA256. Author unknown. Python 2.7.
pypy_sha256.py [paywalled]
Asset: A library of classes for standard Bitcoin transactions. Python 2.7.
transaction_3.py [paywalled]
Dependency tree:
- create_transaction_4.py
-- bitcoin_functions_2.py
--- bjorn_edstrom_ripemd160.py
--- ecdsa-0.10.tar.gz
--- pypy_sha256.py
-- transaction_3.py
--- bitcoin_functions_2.py
--- ecdsa-0.10.tar.gz
-- bitcoin_functions_2.py
--- bjorn_edstrom_ripemd160.py
--- ecdsa-0.10.tar.gz
--- pypy_sha256.py
-- transaction_3.py
--- bitcoin_functions_2.py
--- ecdsa-0.10.tar.gz
The ecdsa-0.10.tar.gz package must be unpacked so that it can be imported and used.
Steps:
- Unpack the zipped tape archive file ecdsa-0.10.tar.gz, by opening a terminal, changing directory to the work directory, and running the following command:
tar -zxvf ecdsa-0.10.tar.gz
- This unpacking produces a new directory named "ecdsa-0.10" in the work directory. The directory "ecdsa-0.10" contains a directory named "ecdsa". Copy the "ecdsa" directory into the work directory, using the following command:
cp -r ecdsa-0.10/ecdsa .
- (optional) Delete ecdsa-0.10 and ecdsa-0.10.tar.gz.
How To Use The Tools
Notes:
- "spend" means to send bitcoin to any address that is not the change address.
- Be very careful when setting the changeAddress file path. The protection offered by the maxSpendPercentage setting only works if the changeAddress is correct.
- The maxSpendPercentage setting is a safeguard against accidentally choosing to send too much to a destination address.
- The maximum spend amount is checked prior to the subtraction of the fee from the change amount.
- The maxFee setting is a safeguard against accidentally choosing an excessive fee.
Example of creating a transaction:
python create_transaction_4.py \
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 1000 \
> --feeType fee \
> --fee 225
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 1000 \
> --feeType fee \
> --fee 225
0100000001ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284090000008a47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76dffffffff015f0c0300000000001976a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac00000000
This example uses the data for Transaction 1 in Bitcoin transaction test set #2.
Here is the data in the input files:
data/tx1_change_address.txt
12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
data/tx1_inputs.json
[
{
"txid": "8482e48391425d88fe30bd4066957000335f58e83f854f997146f41b9493b4ce",
"previous_output_index": "9",
"address": "1CTumCMjzBfccCJBTkHoPQmAwEqU9Uj2sQ",
"bitcoin_amount": "0.00200000"
}
]
data/tx1_outputs.json
[
{
"address": "12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f",
"bitcoin_amount": "0.00199775"
}
]
data/tx1_private_key_1.txt
0000000000000000000000007468655f6c6962726172795f6f665f626162656c
data/tx1_random_values.txt
0072616e646f6d5f627974655f737472696e675f61786178617861735f6d6c6f
Example of running the tests:
stjohn@judgement:work$ pytest -q test_create_transaction_4.py
........................................................................ [ 90%]
........ [100%]
80 passed in 18.81 seconds
The Project Log section includes examples of:
- running the creation tool with debug & info level logging.
- creating a transaction with multiple inputs and outputs.
- running a single test with logging.
Future Work
Here are some possible future approaches:
1) Split the creation and signing operations into separate tools.
- The creation tool should produce a JSON file containing the transaction information.
-- This approach would make it somewhat easier to (if desired) manually transfer the transaction information to an offline signing machine.
- The primary utility of the creation tool would be the design of the transaction (choice of inputs, fee, various checks, etc). It can be run online i.e. it can connect directly to a node or blockchain explorer, so it can get up-to-date information for use during creation.
- The function of the signing tool would be to create the input signatures.
-- It should validate the unsigned transaction before signing it.
-- It should produce JSON-formatted output that can be read and checked by a human, and later reformatted into hex for broadcast.
-- Optionally, the signatures could be stored in files and later displayed in an easier-to-read format, so that they could be manual transferred out of an offline signing machine.
2) A transaction validation tool that can verify a signed transaction in both hex form and in a JSON format.
3) Options for the user to supply inputs & outputs with satoshi values instead of bitcoin values. Convert these to bitcoin values, then proceed as normal.
4) Options for the user to supply a fee value in bitcoin or a fee rate value in bitcoin/byte. Convert these to satoshi or satoshi/byte values, then proceed as normal.
Project Log
I have an existing tool: create_transaction_3.py
This will be my starting point.
It's a component of Edgecase Bitcoin Storage Toolset version 2, and there is a recipe for its use: Recipe for creating and signing a standard Bitcoin transaction #2.
I would like to make various improvements:
- Load all input data from outside the code via command-line arguments.
- A proper logging system, rather than print statements.
- Remove "raw byte" option for random K value. Best to stick with hex bytes as the default.
- Write a test suite using onchain Bitcoin transactions.
- Include the random K value in the debug log output.
- Generate the txid and include it in the info log output.
- Validate the output addresses and the change address.
- Require private key and K values to be exactly 32 bytes long.
Work machine:
- Name: Judgement
- Windows 10
- Windows Subsystem for Linux (WSL): Ubuntu 16.04
- I'm working in the WSL Ubuntu terminal.
My Python version:
stjohn@judgement:work$ python --version
Python 2.7.12
My Pytest version:
stjohn@judgement:work$ pytest --version
This is pytest version 4.6.11, imported from /home/stjohn/.local/lib/python2.7/site-packages/pytest.pyc
Create a project directory, called:
"creating_a_standard_bitcoin_transaction"
Browse to Edgecase Bitcoin Storage Toolset version 2 and download the following assets:
- create_transaction_3.py
- transaction_3.py
- bitcoin_functions_2.py
- bjorn_edstrom_ripemd160.py
- ecdsa-0.10.tar.gz
- pypy_sha256.py
- transaction_3.py
- bitcoin_functions_2.py
- bjorn_edstrom_ripemd160.py
- ecdsa-0.10.tar.gz
- pypy_sha256.py
Create a new directory named "work" in the project directory. Move the downloaded assets into the work directory.
Unpack the zipped tape archive file ecdsa-0.10.tar.gz, by opening a terminal, changing directory to the work directory, and running the following command:
tar -zxvf ecdsa-0.10.tar.gz
This unpacking produced a new directory named "ecdsa-0.10" in the work directory. The directory "ecdsa-0.10" contains a directory named "ecdsa". Copy the "ecdsa" directory into the work directory, using the following command:
cp -r ecdsa-0.10/ecdsa .
Delete ecdsa-0.10 and ecdsa-0.10.tar.gz.
For test data, I'll use Bitcoin transaction test set #2 as my source.
Notes:
- The addresses that correspond to the private keys in the transactions are available in Bitcoin address test set #2.
- Some transaction creation tests use fee rates instead of fees. These fee rates are available in comment 2 on the source article.
[development occurs here.]
I've written a tool for creating a Bitcoin transaction, and an accompanying test suite:
- create_transaction_4.py
- test_create_transaction_4.py
I drew on previous work published in these articles:
- Validating a standard Bitcoin address
- Generating a standard Bitcoin address #2
- Generating entropy from dice #2
Notes:
- "spend" means to send bitcoin to any address that is not the change address.
- Be very careful when setting the changeAddress file path. The protection offered by the maxSpendPercentage setting only works if the changeAddress is correct.
- The maxSpendPercentage setting is a safeguard against accidentally choosing to send too much to a destination address.
- The maximum spend amount is checked prior to the subtraction of the fee from the change amount.
- The maxFee setting is a safeguard against accidentally choosing an excessive fee.
Tool inputs:
- change address, inputs, outputs, private keys, random values, various control settings.
(Note: inputs = as-yet-unspent outputs)
Tool outputs:
- A signed transaction in hex bytes.
Dependency tree:
- create_transaction_4.py
-- bitcoin_functions_2.py
--- bjorn_edstrom_ripemd160.py
--- ecdsa-0.10.tar.gz
--- pypy_sha256.py
-- transaction_3.py
--- bitcoin_functions_2.py
[...]
--- ecdsa-0.10.tar.gz
-- bitcoin_functions_2.py
--- bjorn_edstrom_ripemd160.py
--- ecdsa-0.10.tar.gz
--- pypy_sha256.py
-- transaction_3.py
--- bitcoin_functions_2.py
[...]
--- ecdsa-0.10.tar.gz
Working definition of a standard transaction:
- It has at least one input and at least one output.
- All input and output addresses are Pay-To-Public-Key-Hash (P2PKH).
- All input scriptSigs contain uncompressed public keys.
Important:
- Each input in a standard Bitcoin transaction requires one ECDSA signature. A new random value must be used for every public ECDSA signature. If the transaction is signed and broadcast, and you create a new variant (e.g. if the first variant was not mined), you must supply a new random value for each input in the transaction. Two signatures made with the same private key and the same random value allows a third party to easily derive the private key.
- The input value that may be spent is limited to a default maximum percentage. All remaining value (minus the fee) will be sent to the change address. If you wish to send more than this percentage to other addresses, you must explicitly provide a new maxSpendPercentage value.
- The fee will be subtracted from the amount sent to the change address. If the fee is greater than the default maximum fee, you will need to explicitly provide a new maximum fee value.
Let's record some examples of using
create_transaction_4.py
stjohn@judgement:work$ python create_transaction_4.py \
> -c data/tx1_change_address.txt \
> -i data/tx1_inputs.json \
> -o data/tx1_outputs.json \
> -p data/tx1_private_key_1.txt \
> -r data/tx1_random_values.txt \
> -m 5 \
> -x 1000 \
> -t fee \
> -e 225
> -c data/tx1_change_address.txt \
> -i data/tx1_inputs.json \
> -o data/tx1_outputs.json \
> -p data/tx1_private_key_1.txt \
> -r data/tx1_random_values.txt \
> -m 5 \
> -x 1000 \
> -t fee \
> -e 225
0100000001ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284090000008a47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76dffffffff015f0c0300000000001976a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac00000000
[same, but as a one-line command]
stjohn@judgement:work$ python create_transaction_4.py -c data/tx1_change_address.txt -i data/tx1_inputs.json -o data/tx1_outputs.json -p data/tx1_private_key_1.txt -r data/tx1_random_values.txt -m 5 -x 1000 -t fee -e 225
0100000001ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284090000008a47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76dffffffff015f0c0300000000001976a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac00000000
[same, but using long option names]
python create_transaction_4.py \
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 1000 \
> --feeType fee \
> --fee 225
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 1000 \
> --feeType fee \
> --fee 225
0100000001ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284090000008a47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76dffffffff015f0c0300000000001976a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac00000000
These examples use the data for Transaction 1 in Bitcoin transaction test set #2.
Here's the data in the input files:
stjohn@judgement:work$ tail -n +1 data/tx1_*
==> data/tx1_change_address.txt <==
12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
==> data/tx1_inputs.json <==
[
{
"txid": "8482e48391425d88fe30bd4066957000335f58e83f854f997146f41b9493b4ce",
"previous_output_index": "9",
"address": "1CTumCMjzBfccCJBTkHoPQmAwEqU9Uj2sQ",
"bitcoin_amount": "0.00200000"
}
]
==> data/tx1_outputs.json <==
[
{
"address": "12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f",
"bitcoin_amount": "0.00199775"
}
]
==> data/tx1_private_key_1.txt <==
0000000000000000000000007468655f6c6962726172795f6f665f626162656c
==> data/tx1_random_values.txt <==
0072616e646f6d5f627974655f737472696e675f61786178617861735f6d6c6f
Here's the help output.
stjohn@judgement:work$ python create_transaction_4.py -h
usage: create_transaction_4.py [-h] [-c CHANGEADDRESSFILEPATH]
[-i INPUTSFILEPATH] [-o OUTPUTSFILEPATH]
[-p [PRIVATEKEYFILEPATHS [PRIVATEKEYFILEPATHS ...]]]
[-r RANDOMVALUESFILEPATH]
[-m MAXSPENDPERCENTAGE] [-x MAXFEE]
[-t {fee,fee_rate}] [-e FEE | -f FEERATE]
[-l {debug,info,warning,error}] [-d]
Create and sign a Bitcoin transaction.
optional arguments:
-h, --help show this help message and exit
-c CHANGEADDRESSFILEPATH, --changeAddressFilePath CHANGEADDRESSFILEPATH
Path to file containing the change address (default:
'changeAddress.txt').
-i INPUTSFILEPATH, --inputsFilePath INPUTSFILEPATH
Path to file containing the transaction inputs
(default: 'inputs.json').
-o OUTPUTSFILEPATH, --outputsFilePath OUTPUTSFILEPATH
Path to file containing the transaction outputs
(default: 'outputs.json').
-p [PRIVATEKEYFILEPATHS [PRIVATEKEYFILEPATHS ...]], --privateKeyFilePaths [PRIVATEKEYFILEPATHS [PRIVATEKEYFILEPATHS ...]]
Paths to file containing the transaction outputs
(default: '['privateKey.txt']').
-r RANDOMVALUESFILEPATH, --randomValuesFilePath RANDOMVALUESFILEPATH
Path to file containing the random values (default:
'randomValues.txt').
-m MAXSPENDPERCENTAGE, --maxSpendPercentage MAXSPENDPERCENTAGE
Set maximum percentage of total input value that may
be spent (default: '1'). All remaining value (minus
the fee) will be sent to the change address.
-x MAXFEE, --maxFee MAXFEE
Choose maximum fee in satoshi that is permitted
(default: '225').
-t {fee,fee_rate}, --feeType {fee,fee_rate}
Choose format of output (default: 'fee_rate').
-e FEE, --fee FEE Set transaction fee in satoshi (default: '225').
-f FEERATE, --feeRate FEERATE
Set transaction fee rate in satoshi/byte (default:
'1').
-l {debug,info,warning,error}, --logLevel {debug,info,warning,error}
Choose logging level (default: 'error').
-d, --debug Sets logLevel to 'debug'. This overrides --logLevel.
This tool creates and signs a standard Bitcoin transaction.
Working definition of a standard transaction:
- It has at least one input and at least one output.
- All input and output addresses are Pay-To-Public-Key-Hash (P2PKH).
- All input scriptSigs contain uncompressed public keys.
Important:
- Each input in a standard Bitcoin transaction requires one ECDSA signature. A new random value must be used for every public ECDSA signature. If the transaction is signed and broadcast, and you create a new variant (e.g. if the first variant was not mined), you must supply a new random value for each input in the transaction. Two signatures made with the same private key and the same random value allows a third party to easily derive the private key.
- The input value that may be spent is limited to a default maximum percentage. All remaining value (minus the fee) will be sent to the change address. If you wish to send more than this percentage to other addresses, you must explicitly provide a new maxSpendPercentage value.
- The fee will be subtracted from the amount sent to the change address. If the fee is greater than the default maximum fee, you will need to explicitly provide a new maximum fee value.
Notes:
- There are default values for the input file paths. These can be altered within the code if desired.
- There are default values for the maxSpendPercentage, maxFee, feeType, fee, and feeRate. In order to exceed these limits, larger values will have to be explicitly supplied. These can be altered within the code if desired.
Here's an example of relying on the default values for maxFee and fee. feeType is by default "fee_rate" so we set it manually to "fee". maxSpendPercentage is not relevant for Transaction 1 because all the value will be sent to the change address.
stjohn@judgement:work$ python create_transaction_4.py \
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --feeType fee
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --feeType fee
0100000001ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284090000008a47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76dffffffff015f0c0300000000001976a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac00000000
An example of supplying a fee rate instead of a fee:
stjohn@judgement:work$ python create_transaction_4.py \
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 52 \
> --maxFee 50000 \
> --feeType fee_rate \
> --feeRate 100
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 52 \
> --maxFee 50000 \
> --feeType fee_rate \
> --feeRate 100
0100000002ea1b9db39c6fd5df377e381a896ddb47da4c3c23faf80fe2da9b13014c055f58000000008b483045022100d75efc99b640bcc09f569b1b53cb33d407720f9931a719d0ae3212182927cbb802205ea59d7e86f3bdcf7ec5b483a181704909e401cdeb3f8c60172d72aa842ec142014104e5f0aa4e9ee32cc982db529c981f18171cd9d1ccf224a94e4b3c09b51fd3752c6ebf66f0861dc435fee962f995ab9c5346d32332a409c598eb575cec74115180ffffffffea1b9db39c6fd5df377e381a896ddb47da4c3c23faf80fe2da9b13014c055f58010000008b483045022100c70dbea33b9a7d51a9f952a63d65f0572194af68774c09e03d347f65cddd38c3022072e8341e85f5cb6c49be050c862837d451f46a6f5d0f51fa80993a45983cf9d6014104cca91b1ad65fc428789b469f0e030fb2de58132c61f3240f416e3a6eb1963009a359770805e71e9b7c7982da51c2a3209ec908efe71cf5ec8b65f5b9eb05115bffffffff026c920600000000001976a91417091ffac2b6bb51d9fd1d979fac6ec6bf3a2f1e88ac20a10700000000001976a9140f3a634504545b37a97b10214b2f640fb16085e588ac00000000
Notes:
- This example uses the data for Transaction 8 in Bitcoin transaction test set #2.
- In this transaction, two private key filepaths are supplied.
Here's the data in the input files:
stjohn@judgement:work$ tail -n +1 data/tx8_*
==> data/tx8_change_address.txt <==
136oURWq1zjkdQHKcanE7TyA3o36ibARNM
==> data/tx8_inputs.json <==
[
{
"txid": "585f054c01139bdae20ff8fa233c4cda47db6d891a387e37dfd56f9cb39d1bea",
"previous_output_index": "0",
"address": "12YCFdpsRDvEHNcj5rsmvJ5G2XXkW1icJP",
"bitcoin_amount": "0.00474300"
},
{
"txid": "585f054c01139bdae20ff8fa233c4cda47db6d891a387e37dfd56f9cb39d1bea",
"previous_output_index": "1",
"address": "1H5SUR7Fv7x252WuJPqBjewwpeHuJ218Ky",
"bitcoin_amount": "0.00500000"
}
]
==> data/tx8_outputs.json <==
[
{
"address": "136oURWq1zjkdQHKcanE7TyA3o36ibARNM",
"bitcoin_amount": "0.00430700"
},
{
"address": "12PX5jPyQYejyrU79nZUDmKXvB3ttMfDqZ",
"bitcoin_amount": "0.00500000"
}
]
==> data/tx8_private_key_1.txt <==
ecfb8057d4e053dda6849f6a361ca2d6797368651bbb2b52ce4691515a7909e1
==> data/tx8_private_key_2.txt <==
fc8c7e92b44fe66f8f20d98a648f659da69461661673e22292a67dc20742ef17
==> data/tx8_random_values.txt <==
0a5a9cc087cf3337bfb0fa12f6fa036d17d6b6dc0e93dfa657c8caca47ad8155
2493ac84058e4f4b79f1bd267c45f52bc7545ef01dd66b8bf077cae86460e954
An example of the error produced when the transaction will spend more than the maximum spend percentage:
stjohn@judgement:work$ python create_transaction_4.py \
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 50000 \
> --feeType fee_rate \
> --feeRate 100
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 50000 \
> --feeType fee_rate \
> --feeRate 100
Traceback (most recent call last):
File "create_transaction_4.py", line 724, in <module>
main()
File "create_transaction_4.py", line 213, in main
signedTransaction = createAndSignTransaction(b)
File "create_transaction_4.py", line 460, in createAndSignTransaction
raise ValueError(msg)
ValueError: Spend amount (0.00500000 bitcoin) is greater than the maximum permitted spend amount (0.00048715 bitcoin). To spend this amount, you will need to increase the maxSpendPercentage from 5 to 52.
An example of the error produced when the transaction will spend more than the maximum fee:
stjohn@judgement:work$ python create_transaction_4.py \
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 555 \
> --feeType fee_rate \
> --feeRate 100
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 555 \
> --feeType fee_rate \
> --feeRate 100
Traceback (most recent call last):
File "create_transaction_4.py", line 724, in <module>
main()
File "create_transaction_4.py", line 213, in main
signedTransaction = createAndSignTransaction(b)
File "create_transaction_4.py", line 489, in createAndSignTransaction
raise ValueError(msg)
ValueError: The fee (43600 satoshi) is greater than the specified maximum fee (555 satoshi).
Let's run the tests.
stjohn@judgement:work$ pytest test_create_transaction_4.py
============================= test session starts ==============================
platform linux2 -- Python 2.7.12, pytest-4.6.11, py-1.9.0, pluggy-0.13.1
rootdir: /mnt/c/Users/User/Desktop/stuff/articles/creating_a_standard_bitcoin_transaction/work, inifile: pytest.ini
collected 80 items
test_create_transaction_4.py ........................................... [ 53%]
..................................... [100%]
========================== 80 passed in 19.32 seconds ==========================
Example: Run a specific test.
stjohn@judgement:work$ pytest test_create_transaction_4.py::test_arg_none
============================= test session starts ==============================
platform linux2 -- Python 2.7.12, pytest-4.6.11, py-1.9.0, pluggy-0.13.1
rootdir: /mnt/c/Users/User/Desktop/stuff/articles/creating_a_standard_bitcoin_transaction/work, inifile: pytest.ini
collected 1 item
test_create_transaction_4.py . [100%]
=========================== 1 passed in 0.07 seconds ===========================
Example: Run a specific test quietly.
stjohn@judgement:work$ pytest -q test_create_transaction_4.py::test_arg_none
. [100%]
1 passed in 0.05 seconds
Examples: Print log data when running a test.
stjohn@judgement:work$ pytest -o log_cli=true --log-cli-level=DEBUG --log-format="%(levelname)s [%(lineno)s: %(funcName)s] %(message)s" test_create_transaction_4.py::test_output_item_invalid_amount
============================= test session starts ==============================
platform linux2 -- Python 2.7.12, pytest-4.6.11, py-1.9.0, pluggy-0.13.1
rootdir: /mnt/c/Users/User/Desktop/stuff/articles/creating_a_standard_bitcoin_transaction/work, inifile: pytest.ini
collected 1 item
test_create_transaction_4.py::test_output_item_invalid_amount
-------------------------------- live log call ---------------------------------
DEBUG [633: validateBitcoinAddress] Address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
DEBUG [641: validateBitcoinAddress] Number of leading '1' characters: 1
DEBUG [644: validateBitcoinAddress] base10 value inside address: 383018945214016431340896370610606860961941348280797832512
DEBUG [647: validateBitcoinAddress] Address value in hex: 0f9ee78522f6cc8a88784ae02b0408e452d80259ccc52540
DEBUG [652: validateBitcoinAddress] Checksum: ccc52540
DEBUG [654: validateBitcoinAddress] Address value in hex without checksum: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [657: validateBitcoinAddress] Address value with leading zero bytes added back on: 000f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [660: validateBitcoinAddress] Recalculated checksum: ccc52540
DEBUG [667: validateBitcoinAddress] versionByte: 00
DEBUG [672: validateBitcoinAddress] publicKeyHash: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [676: validateBitcoinAddress] Address 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f validated. No problems found.
PASSED [100%]
=========================== 1 passed in 0.08 seconds ===========================
stjohn@judgement:work$ pytest -o log_cli=true --log-cli-level=INFO --log-format=
"%(levelname)s [%(lineno)s: %(funcName)s] %(message)s" test_create_transaction_4
.py::test_total_input_too_small
"%(levelname)s [%(lineno)s: %(funcName)s] %(message)s" test_create_transaction_4
.py::test_total_input_too_small
============================= test session starts ==============================
platform linux2 -- Python 2.7.12, pytest-4.6.11, py-1.9.0, pluggy-0.13.1
rootdir: /mnt/c/Users/User/Desktop/stuff/articles/creating_a_standard_bitcoin_transaction/work, inifile: pytest.ini
collected 1 item
test_create_transaction_4.py::test_total_input_too_small
-------------------------------- live log call ---------------------------------
INFO [292: createAndSignTransaction] All arguments validated. No problems found.
INFO [333: createAndSignTransaction] Number of inputs: 2
INFO [341: createAndSignTransaction] Number of outputs: 2
INFO [353: createAndSignTransaction] Input addresses, with total value to be spent from each:
-- 12YCFdpsRDvEHNcj5rsmvJ5G2XXkW1icJP: 0.00474300 (bitcoin)
-- 1H5SUR7Fv7x252WuJPqBjewwpeHuJ218Ky: 0.00100000 (bitcoin)
INFO [372: createAndSignTransaction] Output addresses, with total value to be sent to each:
-- 12PX5jPyQYejyrU79nZUDmKXvB3ttMfDqZ: 0.00500000 (bitcoin)
-- 136oURWq1zjkdQHKcanE7TyA3o36ibARNM: 0.00430700 (bitcoin)
INFO [398: createAndSignTransaction] Change address, with total value to be sent to it:
-- 136oURWq1zjkdQHKcanE7TyA3o36ibARNM: 0.00430700 (bitcoin)
INFO [405: createAndSignTransaction] Total input value: 0.00574300 (bitcoin)
INFO [406: createAndSignTransaction] Total output value: 0.00930700 (bitcoin)
PASSED [100%]
=========================== 1 passed in 0.51 seconds ===========================
This is my pytest.ini:
stjohn@judgement:work$ cat pytest.ini
[pytest]
# Commands:
# - pytest
# - pytest --help
# - pytest --quiet
# - pytest --override-ini log_cli=true
# note: -o == --override-ini
# - pytest -o log_cli=true
# - pytest -o log_cli=true -o log_level=info
# - pytest -o log_cli=true -o log_level=debug
addopts = -ra
log_cli = false
log_level = CRITICAL
log_format = [%(name)s] %(levelname)s [%(lineno)s: %(funcName)s] %(message)s
log_date_format = %Y-%m-%d %H:%M:%S
Let's look at using logging when creating a transaction.
Notes:
- Logging at "info" level provides useful information: A bird's-eye view of the process.
- Logging at "debug" level provides a large amount of detailed information, including secret values (private keys and random values).
Here's the creation of Transaction 8, with logging at "info" level.
stjohn@judgement:work$ python create_transaction_4.py \
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 52 \
> --maxFee 50000 \
> --feeType fee_rate \
> --feeRate 100 \
> --logLevel info
> --changeAddressFilePath data/tx8_change_address.txt \
> --inputsFilePath data/tx8_inputs.json \
> --outputsFilePath data/tx8_outputs.json \
> --privateKeyFilePaths data/tx8_private_key_1.txt data/tx8_private_key_2.txt \
> --randomValuesFilePath data/tx8_random_values.txt \
> --maxSpendPercentage 52 \
> --maxFee 50000 \
> --feeType fee_rate \
> --feeRate 100 \
> --logLevel info
- Data has been loaded from files.
- Addresses have been derived from private keys.
- Each input address has been matched to a private key.
- All arguments validated. No problems found.
- Number of inputs: 2
- Number of outputs: 2
- Input addresses, with total value to be spent from each:
-- 12YCFdpsRDvEHNcj5rsmvJ5G2XXkW1icJP: 0.00474300 (bitcoin)
-- 1H5SUR7Fv7x252WuJPqBjewwpeHuJ218Ky: 0.00500000 (bitcoin)
- Output addresses, with total value to be sent to each:
-- 12PX5jPyQYejyrU79nZUDmKXvB3ttMfDqZ: 0.00500000 (bitcoin)
-- 136oURWq1zjkdQHKcanE7TyA3o36ibARNM: 0.00430700 (bitcoin)
- Change address, with total value to be sent to it:
-- 136oURWq1zjkdQHKcanE7TyA3o36ibARNM: 0.00430700 (bitcoin)
- Total input value: 0.00974300 (bitcoin)
- Total output value: 0.00930700 (bitcoin)
- Total input value is greater than total output value.
-- Some input value has not been assigned to an output.
-- Extra value: 0.00043600 (bitcoin)
-- This extra value will be sent to the change address.
-- Change address: 136oURWq1zjkdQHKcanE7TyA3o36ibARNM
-- Old change amount: 0.00430700 (bitcoin)
-- New change amount: 0.00474300 (bitcoin)
- New total output value: 0.00974300 (bitcoin)
- Maximum percentage of input value (prior to fee subtraction) that can be spent: 52%
- Note: "spend" means to send bitcoin to any address that is not the change address.
- Maximum spend amount: 0.00506636 (bitcoin)
- Spend amount: 0.00500000 (bitcoin)
- The spend amount is 51.32% of the input value.
- Estimated transaction size: 436 bytes
- Fee type: fee_rate
- Fee rate: 100.0 (satoshi/byte)
- Note: Calculate final fee by multiplying {estimated transaction size} by {fee rate} and rounding up to the nearest satoshi.
- Final fee: 43600 (satoshi)
- Final fee rate (using estimated transaction size): 100.0000 (satoshi/byte)
- Maximum fee: 50000 (satoshi)
- Fee subtracted from change amount.
- New change amount: 430700 (satoshi), 0.00430700 (bitcoin)
- Transaction created.
- Note: The first random value will be used to sign the first input. The second will be used to sign the second, and so on.
- Transaction signed.
- Signed transaction size: 438 bytes
- signedTxSize - estimatedTxSize = 2 bytes
- Signed transaction fee rate: 99.5434 (satoshi/byte)
- Txid (little-endian double SHA256 hash of signed transaction):
2b0cef7b0abfefeb6c7c6b228930e6218e86e9d8c33f5525d10f34f91cc7bad4
- Signed transaction:
0100000002ea1b9db39c6fd5df377e381a896ddb47da4c3c23faf80fe2da9b13014c055f58000000008b483045022100d75efc99b640bcc09f569b1b53cb33d407720f9931a719d0ae3212182927cbb802205ea59d7e86f3bdcf7ec5b483a181704909e401cdeb3f8c60172d72aa842ec142014104e5f0aa4e9ee32cc982db529c981f18171cd9d1ccf224a94e4b3c09b51fd3752c6ebf66f0861dc435fee962f995ab9c5346d32332a409c598eb575cec74115180ffffffffea1b9db39c6fd5df377e381a896ddb47da4c3c23faf80fe2da9b13014c055f58010000008b483045022100c70dbea33b9a7d51a9f952a63d65f0572194af68774c09e03d347f65cddd38c3022072e8341e85f5cb6c49be050c862837d451f46a6f5d0f51fa80993a45983cf9d6014104cca91b1ad65fc428789b469f0e030fb2de58132c61f3240f416e3a6eb1963009a359770805e71e9b7c7982da51c2a3209ec908efe71cf5ec8b65f5b9eb05115bffffffff026c920600000000001976a91417091ffac2b6bb51d9fd1d979fac6ec6bf3a2f1e88ac20a10700000000001976a9140f3a634504545b37a97b10214b2f640fb16085e588ac00000000
Notes:
- At log level "info", the txid is printed just before the signed transaction.
- The txid is calculated by applying the SHA256 hash algorithm twice to the signed transaction binary data, and then converting the result to little-endian.
- Due to Transaction Malleability (transaction signatures can be slightly altered in-flight by third parties without compromising their validity), for some mined transactions the final txid may differ from the calculated version.
Here's the creation of Transaction 1, with logging at "debug" level.
stjohn@judgement:work$ python create_transaction_4.py \
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 1000 \
> --feeType fee \
> --fee 225 \
> --logLevel debug
> --changeAddressFilePath data/tx1_change_address.txt \
> --inputsFilePath data/tx1_inputs.json \
> --outputsFilePath data/tx1_outputs.json \
> --privateKeyFilePaths data/tx1_private_key_1.txt \
> --randomValuesFilePath data/tx1_random_values.txt \
> --maxSpendPercentage 5 \
> --maxFee 1000 \
> --feeType fee \
> --fee 225 \
> --logLevel debug
INFO [165: main] Data has been loaded from files.
INFO [175: main] Addresses have been derived from private keys.
DEBUG [176: main] List of private keys and their corresponding addresses:
- 0000000000000000000000007468655f6c6962726172795f6f665f626162656c
-- 1CTumCMjzBfccCJBTkHoPQmAwEqU9Uj2sQ
INFO [187: main] Each input address has been matched to a private key.
DEBUG [633: validateBitcoinAddress] Address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
DEBUG [641: validateBitcoinAddress] Number of leading '1' characters: 1
DEBUG [644: validateBitcoinAddress] base10 value inside address: 383018945214016431340896370610606860961941348280797832512
DEBUG [647: validateBitcoinAddress] Address value in hex: 0f9ee78522f6cc8a88784ae02b0408e452d80259ccc52540
DEBUG [652: validateBitcoinAddress] Checksum: ccc52540
DEBUG [654: validateBitcoinAddress] Address value in hex without checksum: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [657: validateBitcoinAddress] Address value with leading zero bytes added back on: 000f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [660: validateBitcoinAddress] Recalculated checksum: ccc52540
DEBUG [667: validateBitcoinAddress] versionByte: 00
DEBUG [672: validateBitcoinAddress] publicKeyHash: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [676: validateBitcoinAddress] Address 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f validated. No problems found.
DEBUG [274: createAndSignTransaction] Validate change address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
DEBUG [633: validateBitcoinAddress] Address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
DEBUG [641: validateBitcoinAddress] Number of leading '1' characters: 1
DEBUG [644: validateBitcoinAddress] base10 value inside address: 383018945214016431340896370610606860961941348280797832512
DEBUG [647: validateBitcoinAddress] Address value in hex: 0f9ee78522f6cc8a88784ae02b0408e452d80259ccc52540
DEBUG [652: validateBitcoinAddress] Checksum: ccc52540
DEBUG [654: validateBitcoinAddress] Address value in hex without checksum: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [657: validateBitcoinAddress] Address value with leading zero bytes added back on: 000f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [660: validateBitcoinAddress] Recalculated checksum: ccc52540
DEBUG [667: validateBitcoinAddress] versionByte: 00
DEBUG [672: validateBitcoinAddress] publicKeyHash: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [676: validateBitcoinAddress] Address 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f validated. No problems found.
INFO [292: createAndSignTransaction] All arguments validated. No problems found.
DEBUG [317: createAndSignTransaction] Input data 0:
-- txid: 8482e48391425d88fe30bd4066957000335f58e83f854f997146f41b9493b4ce
-- previous_output_index: 9
-- private_key_hex: 0000000000000000000000007468655f6c6962726172795f6f665f626162656c
-- (address): 1CTumCMjzBfccCJBTkHoPQmAwEqU9Uj2sQ
-- bitcoin_amount: 0.00200000
DEBUG [322: createAndSignTransaction] Output data 0:
-- address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
-- bitcoin_amount: 0.00199775
INFO [333: createAndSignTransaction] Number of inputs: 1
INFO [341: createAndSignTransaction] Number of outputs: 1
INFO [353: createAndSignTransaction] Input addresses, with total value to be spent from each:
-- 1CTumCMjzBfccCJBTkHoPQmAwEqU9Uj2sQ: 0.00200000 (bitcoin)
INFO [372: createAndSignTransaction] Output addresses, with total value to be sent to each:
-- 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f: 0.00199775 (bitcoin)
DEBUG [394: createAndSignTransaction] Change address found in output addresses.
INFO [398: createAndSignTransaction] Change address, with total value to be sent to it:
-- 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f: 0.00199775 (bitcoin)
INFO [405: createAndSignTransaction] Total input value: 0.00200000 (bitcoin)
INFO [406: createAndSignTransaction] Total output value: 0.00199775 (bitcoin)
INFO [425: createAndSignTransaction] Total input value is greater than total output value.
-- Some input value has not been assigned to an output.
-- Extra value: 0.00000225 (bitcoin)
-- This extra value will be sent to the change address.
-- Change address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
-- Old change amount: 0.00199775 (bitcoin)
-- New change amount: 0.00200000 (bitcoin)
INFO [429: createAndSignTransaction] New total output value: 0.00200000 (bitcoin)
INFO [439: createAndSignTransaction] Maximum percentage of input value (prior to fee subtraction) that can be spent: 5%
INFO [440: createAndSignTransaction] Note: "spend" means to send bitcoin to any address that is not the change address.
INFO [445: createAndSignTransaction] Maximum spend amount: 0.00010000 (bitcoin)
INFO [453: createAndSignTransaction] Spend amount: 0.00000000 (bitcoin)
INFO [456: createAndSignTransaction] The spend amount is 0.00% of the input value.
INFO [465: createAndSignTransaction] Estimated transaction size: 223 bytes
INFO [467: createAndSignTransaction] Fee type: fee
INFO [469: createAndSignTransaction] Fee: 225 (satoshi)
INFO [481: createAndSignTransaction] Final fee: 225 (satoshi)
INFO [483: createAndSignTransaction] Final fee rate (using estimated transaction size): 1.0090 (satoshi/byte)
INFO [486: createAndSignTransaction] Maximum fee: 1000 (satoshi)
INFO [501: createAndSignTransaction] Fee subtracted from change amount.
INFO [504: createAndSignTransaction] New change amount: 199775 (satoshi), 0.00199775 (bitcoin)
INFO [508: createAndSignTransaction] Transaction created.
DEBUG [513: createAndSignTransaction] Random values:
-- 0072616e646f6d5f627974655f737472696e675f61786178617861735f6d6c6f
INFO [514: createAndSignTransaction] Note: The first random value will be used to sign the first input. The second will be used to sign the second, and so on.
INFO [516: createAndSignTransaction] Transaction signed.
INFO [519: createAndSignTransaction] Signed transaction size: 223 bytes
INFO [520: createAndSignTransaction] signedTxSize - estimatedTxSize = 0 bytes
INFO [522: createAndSignTransaction] Signed transaction fee rate: 1.0090 (satoshi/byte)
DEBUG [527: createAndSignTransaction] Input 0:
Input: {40 bytes unsigned, 66 bytes signable, 179 bytes signed}
- [data] previous_output_hash: ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284 (32 bytes)
- [data] previous_output_index: 09000000 (4 bytes)
- [signed form] script_length: 8a (1 bytes)
- [signed form] scriptSig: 47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76d (138 bytes)
- [data] sequence: ffffffff (4 bytes)
- [used for signing] private_key_hex: 0000000000000000000000007468655f6c6962726172795f6f665f626162656c (32 bytes)
- [source, goes into scriptSig] public_key_hex: 04e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76d (65 bytes)
- [signable form] script_length_scriptPubKey: 19 (1 bytes)
- [signable form] scriptPubKey: 76a9147dc03dfbe8c62821bcd1ab95446b88ed7008a76e88ac (25 bytes)
- [more info] address: 1CTumCMjzBfccCJBTkHoPQmAwEqU9Uj2sQ
- [more info] previous_output_index_int: 9
- [more info] txid: 8482e48391425d88fe30bd4066957000335f58e83f854f997146f41b9493b4ce
DEBUG [531: createAndSignTransaction] Output 0:
Output: {34 bytes}
- [data] value: 5f0c030000000000 (8 bytes)
- [data] script_length: 19 (1 bytes)
- [data] scriptPubKey: 76a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac (25 bytes)
- [more info] address: 12RbVkKwHcwHbMZmnSVAyR4g88ZChpQD6f
- [more info] bitcoin_amount: 0.00199775
- [more info] satoshi_amount: 199775
- [more info] public_key_hash_hex: 0f9ee78522f6cc8a88784ae02b0408e452d80259
DEBUG [532: createAndSignTransaction] Transaction (unsigned form): {84 bytes}
- version: 01000000 (4 bytes)
- input_count: 01 (1 bytes)
- Input 0: {40 bytes}
-- previous_output_hash: ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284 (32 bytes)
-- previous_output_index: 09000000 (4 bytes)
-- script_length: [none] (0 bytes)
-- scriptSig: [none] (0 bytes)
-- sequence: ffffffff (4 bytes)
- output_count: 01 (1 bytes)
- Output 0: {34 bytes}
-- value: 5f0c030000000000 (8 bytes)
-- script_length: 19 (1 bytes)
-- scriptPubKey: 76a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac (25 bytes)
- block_lock_time: 00000000 (4 bytes)
DEBUG [534: createAndSignTransaction] Transaction (signable form 0): {114 bytes}
- version: 01000000 (4 bytes)
- input_count: 01 (1 bytes)
- Input 0 [to be used to sign this signable form]: {66 bytes}
-- previous_output_hash: ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284 (32 bytes)
-- previous_output_index: 09000000 (4 bytes)
-- script_length_scriptPubKey: 19 (1 bytes)
-- scriptPubKey: 76a9147dc03dfbe8c62821bcd1ab95446b88ed7008a76e88ac (25 bytes)
-- sequence: ffffffff (4 bytes)
- output_count: 01 (1 bytes)
- Output 0: {34 bytes}
-- value: 5f0c030000000000 (8 bytes)
-- script_length: 19 (1 bytes)
-- scriptPubKey: 76a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac (25 bytes)
- block_lock_time: 00000000 (4 bytes)
- hash_type_4_byte: 01000000 (4 bytes)
DEBUG [535: createAndSignTransaction] Transaction (signed form): {223 bytes}
- version: 01000000 (4 bytes)
- input_count: 01 (1 bytes)
- Input 0: {179 bytes}
-- previous_output_hash: ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284 (32 bytes)
-- previous_output_index: 09000000 (4 bytes)
-- script_length: 8a (1 bytes)
-- scriptSig: 47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76d (138 bytes)
-- sequence: ffffffff (4 bytes)
- output_count: 01 (1 bytes)
- Output 0: {34 bytes}
-- value: 5f0c030000000000 (8 bytes)
-- script_length: 19 (1 bytes)
-- scriptPubKey: 76a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac (25 bytes)
- block_lock_time: 00000000 (4 bytes)
INFO [540: createAndSignTransaction] Txid (little-endian double SHA256 hash of signed transaction):
4bdd5f653d0100ea4735953e8e22e92321af9074926b3bd33c279c289f2d975a
INFO [214: main] Signed transaction:
0100000001ceb493941bf44671994f853fe8585f330070956640bd30fe885d429183e48284090000008a47304402206a2eea0c908efbd780a34c48b48d80946a6e740c272468427bada3ba9773d39a022076017028c4386020b19b7d1f1640558cd902aeffbfbd85f4637a8be0e92ee1de014104e8ade66f2cc0e43073f4ccea47db279bbab1a5e30a6e8ba49f12538b215c5b9e0d28bd080d35fde878081e8f05dbc23eeba02b544fa83e6d13b5f2145681e76dffffffff015f0c0300000000001976a9140f9ee78522f6cc8a88784ae02b0408e452d8025988ac00000000
Good. That's the end of this project.