Goal
Store bitcoin on an offline Raspberry Pi.
Contents
- Goal
- Contents
- Brief Summary
- Summary
- Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction #2
- Recipe For Manually Mounting A USB Memory Stick
- Representative Sample Of Bash Commands Used
- Downloadable Assets
- Notes
- Financial Information For This Project
- Further Work
- Project Log
Brief Summary
I generated an address on an offline Raspberry Pi. I tested this address by successfully transferring a small amount of bitcoin into and out of it, proving that I could always retrieve bitcoin from it.
I then transferred a larger amount of bitcoin into the address, and stored it there for a week.
Note: All transactions were constructed and signed offline, then manually transferred to an online computer for broadcasting.
Summary
Goal
Store bitcoin on an offline Raspberry Pi.
Overall results:
- I generated an address (the "test address") on an offline Raspberry Pi.
- I validated the test address by successfully transferring a small amount of bitcoin into and out of it. This allowed me to be certain that I could retrieve bitcoin from it.
- I stored a larger amount of bitcoin in the test address for a week, before transferring it back to an exchange service.
- All transactions were constructed and signed offline, then manually transferred to an online computer for broadcasting.
Original plan of action for this project:
- Download necessary code from previous articles.
- Create a private key. Store it on the Raspberry Pi. This will require generating entropy.
- Generate a Bitcoin address from the private key.
- Test this address by transferring some bitcoin into and out of it.
- Store a larger amount of bitcoin in the address.
- The private key will of course be revealed in the article describing this project, so this bitcoin won't be stored permanently in this address. Instead, I'll transfer the bitcoin out again. To store some bitcoin, a reader can follow all the steps apart from this one.
What I actually did during the project:
0) My equipment is listed in the "Equipment" part of the Notes section.
1) I chose this set of previous articles:
- Recipe for generating entropy bytes using dice
- Recipe for generating a Bitcoin address
- Recipe for creating and signing a standard Bitcoin transaction
- Recipe for creating and signing a nonstandard Bitcoin transaction
- Displaying hex bytes for manual copying
2) I downloaded all the assets linked from these articles. Note: Some assets are linked from more than one of these articles.
List of downloaded assets:
- bitcoin_functions.py
- bjorn_edstrom_ripemd160.py
- convert_dice_rolls_to_hex_bytes_2.py
- create_nonstandard_transaction.py
- create_transaction.py
- display_hex_bytes.py
- ecdsa-0.10.tar.gz
- generate_bitcoin_address_3.py
- nonstandard_bitcoin_functions.py
- nonstandard_transaction.py
- pypy_sha256.py
- transaction.py
These assets are linked in the Downloadable Assets section.
3) Using a memory stick, I transferred these assets from my work computer Aineko to the Raspberry Pi. To find out how to do this, please see the section Recipe For Manually Mounting A USB Memory Stick.
4) I logged commands and command output on the Raspberry Pi. Please see the "Recording shell output" part of the Notes section for details. Later, I transferred these logs back to Aineko for integration into this article.
5) I checked and recorded some details about the Raspberry Pi (its operating system, the versions of various tools).
6) I generated a private key using dice and stored it on the Raspberry Pi. I then derived the corresponding Bitcoin address, which I called the "test address".
Note: Files containing the various dice roll results are listed in the Downloadable Assets section. The entropy values derived from these files are included in the "Entropy values generated during this project" part of the Notes section.
7) I calculated an amount of bitcoin to use for validating the test address. Details are included in the section Financial Information For This Project. I used LocalBitcoins to transfer some bitcoin to the test address. LocalBitcoins created a transaction that included this transfer. I named this transaction "tx0".
8) I used a service to obtain information about tx0. Some of this information was needed for constructing a transaction that spent from the test address.
Note: I used various services during this project. They are listed in the "Services used during this project" part of the Notes section.
9) I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 1 (on my LocalBitcoins account). I named this transaction "tx1" and later "tx1a". I used a transaction-broadcasting service to broadcast it to the Bitcoin network. This transaction was never mined. LocalBitcoins saw this transaction and generated a new receiving address for my account, "receiving address 2".
Note: All transactions in this project were manually transferred to the online computer (Aineko) from the offline Raspberry Pi. I used the display_hex_bytes.py tool to display the transaction hex bytes in a more easily-read format.
Note: The addresses used in this project are listed in the "Addresses generated and/or used in this project" part of the Notes section.
Note: The transactions that I created in this project are displayed in the "Transactions created during this project" part of the Notes section. Details about the transactions that LocalBitcoins created are also included.
10) I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 2. I called this transaction "tx1b". This transaction was rejected by two transaction-broadcasting services, because it was a double-spend attempt (it tried to spend the same unspent output as tx1a did, but to a different address, while tx1a was still in the memory pools of the services). I was thinking about the fee rate change and had forgotten that the Bitcoin network would perceive it as a double-spend attempt.
Note: Several points concerning Bitcoin transactions:
- New transactions spend unspent-outputs-of-previous-transactions. These can also be called "inputs".
- The bitcoin balance of an address is the sum of the unspent outputs sent by previous transactions to this address.
- To spend bitcoin from an address, the bitcoin amount must be constructed from complete inputs. Any change can be sent in a new unspent output back to the original address or to another address that you control. Inputs cannot be broken into smaller inputs prior to spending - new inputs (larger or smaller) must be created by a new transaction.
11) I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 1, using a higher fee than in tx1a. I called this transaction "tx1c". This was a replace-by-fee transaction (only the fee was different), which is valid on the Bitcoin network (unlike a double-spend transaction), but the two transaction-broadcasting services still rejected it. I waited until tx1a had been cleared from the memory pool of one of the transaction-broadcasting services (this took about 48 hours), and then uploaded tx1c again to that service. This time, the service accepted tx1c, which was later mined.
Note: A recipe for making replace-by-fee transactions is included in the section Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction #2.
Note: A new entropy value is needed for each transaction signature.
Note: The times taken for confirmation of tx1c and tx3 are shown in the "Transaction confirmation times" part of the Notes section.
12) The successful mining of tx1c validated the test address. It proved that the address was correctly calculated from the private key. I could now move a large amount of bitcoin into this address and be certain that I could retrieve it. Even if I later constructed a new transaction that turned out to be invalid, and discovered that the cause was an error in the code stack used to create and sign a transaction, I knew that eventually this error could be fixed and a valid transaction could be created. I would only risk a temporary lack of access to the bitcoin stored in this address, not its permanent loss.
13) I used LocalBitcoins to transfer a relatively larger amount of bitcoin ($50 worth at the then-current exchange rate) to the test address. LocalBitcoins created a transaction that included this transfer. I named this transaction "tx2".
14) I used a service to obtain information about tx2. Some of this information was needed for constructing a transaction that could spend from the test address (more specifically: could spend the unspent output that tx2 sent to the test address).
15) A week passed, during which $50 worth of bitcoin was stored on the Raspberry Pi.
16) I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 2 (on my LocalBitcoins account). I named this transaction "tx3". I used a transaction-broadcasting service to broadcast it to the Bitcoin network. After a while, tx3 was mined.
17) This project was now completed. I had approximately carried out the original plan of action, with a deviation (tx1b) and a significant amount of extra detail and additional steps.
Notes section:
The Notes section contains the following parts:
- Definitions and acryonyms
- Services used during this project
- Equipment used during this project
- Entropy values generated during this project
- Addresses generated and/or used in this project
- Transactions created during this project
- create_nonstandard_transaction.py settings used to create the transactions
- Time taken to manually transfer transactions by typing
- Transaction confirmation times
- Dice rolling results
- Recording shell output
- Miscellaneous
Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction #2
A previous recipe with this title was published in the article Creating and signing a standard raw Bitcoin transaction, in the section Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction.
Objectives:
- Fine control of the transaction fee.
- Ability to rebroadcast a new transaction with a higher fee if the previous transaction is not mined within a reasonable time period. This new transaction, if mined, should invalidate the previous transaction.
Several points concerning Bitcoin transactions:
- New transactions spend unspent-outputs-of-previous-transactions. These can also be called "inputs".
- The bitcoin balance of an address is the sum of the unspent outputs sent by previous transactions to this address.
- To spend bitcoin from an address, the bitcoin amount must be constructed from complete inputs. Any change can be sent in a new unspent output back to the original address or to another address that you control. Inputs cannot be broken into smaller inputs prior to spending - new inputs (larger or smaller) must be created by a new transaction.
1) Gather the required data for a new transaction. How to do this is not specified in this recipe. Include at least one "change address" output. Inputs should be added as necessary to achieve the desired output values. The sum of the inputs may be greater than the sum of the desired output values, i.e. some bitcoin may be left over. This left-over bitcoin should be sent to the change address output. Include an additional input that is specifically for paying the as-yet-unknown transaction fee. Set the bitcoin in this input to be sent to the change address output.
2) Look at current Bitcoin network transaction fee rates. How to do this is not specified in this recipe. Choose a fee rate for the transaction.
3) Use a software tool to create and sign a transaction with the specified fee rate. This tool must be able to calculate an estimate of the transaction size in order to derive a fee value from the fee rate. This fee value will be stored implicitly in the transaction as the difference between the input values and the output values. After the tool has created and signed the transaction, it should calculate and report the actual fee rate of the final signed form of the transaction. The process / structure of the software tool is not specified in this recipe.
4) Broadcast the transaction to the Bitcoin network or upload the transaction to a service that can do this for you. How to do this is not specified in this recipe.
5) A node will store unconfirmed transactions in its memory pools for a particular time period. If the transaction is not mined (confirmed) within this period, the node will delete it from its memory pool. This period will vary depending on the node. Some reading indicates that the default period is 72 hours (3 days). I have tried this once during this project - the delay was about 48 hours (2 days). After broadcasting the transaction, wait 3 days + a small delay. If the transaction is mined during this period, stop here (and wait for the transaction to be 6 blocks deep in the Bitcoin blockchain). Otherwise, confirm that it has been deleted from the relevant node's memory pool (by e.g. looking up the transaction's txid) and continue to step (6).
Note: If you run a node that accepts replace-by-fee transactions (or have access to a service that does this), then you can upload a new version of the transaction immediately, without waiting for it to be removed from the node's memory pool. If there exists a path through the Bitcoin network from your node to a miner's node, consisting of nodes that all accept replace-by-fee transactions, then the new version of your transaction will propagate along this path, allowing you to quickly replace an unconfirmed transaction with a new version. The miner's node will probably be set to accept replace-by-fee transactions for mining, as this is necessarily more profitable.
6) Look at current Bitcoin network transaction fee rates. How to do this is not specified in this recipe. Choose a higher fee rate than the one chosen in step (2).
7) Repeat steps (2)-(6) until the transaction is mined.
Note: If a transaction disappears from the network (i.e. the memory pools of all public nodes), this doesn't mean that it has vanished permanently. Anyone who stored it can rebroadcast it later - it will still be valid. In order to make it invalid, create a new transaction that uses at least one of the same inputs.
Note: An input in a transaction is an as-yet-unspent output of a previous transaction. Each unspent output can only ever be spent once. If a transaction is broadcast that uses at least one input that has already been spent, this transaction is invalid and will not be mined.
Recipe For Manually Mounting A Usb Memory Stick
0) Copy data that you wish to transfer to the destination computer into a directory named "work", located at the top level of the filesystem on the memory stick.
1) Insert the memory stick into a USB port on the destination computer.
2) If you are using a command-line interface, skip this step. If you are using a graphical user interface, open a terminal emulator.
3) Use the following command sequence to manually mount the memory stick (i.e. make its filesystem accessible).
[Make a new directory to be the mount point for the memory stick. Making this new directory in the /mnt directory requires root permissions, so "sudo" is used.]
[List items in the directory "/mnt"]
memory_stick_mount_point
[List items in the directory "/dev" that begin with "sda"]
/dev/sda
/dev/sda1
[Mount the memory stick located (metaphorically) at the device file /dev/sda1 to the directory /mnt/memory_stick_mount_point]
[
Note that:
-o (lowercase letter "o", not the number zero) specifies that an option string follows.
uid=pi,gid=pi specifies that the user ID is "pi" and the group ID is "pi" (note there are no spaces allowed between these two terms).
/dev/sda1 is the first partition on the first USB memory stick that the computer can detect. [Future: Investigate whether this is accurate.]
]
[List the contents of the top directory in the memory stick filesystem]
work
pi@raspberrypi ~/test $ sudo mkdir /mnt/memory_stick_mount_point
[List items in the directory "/mnt"]
pi@raspberrypi ~/test $ ls -1 /mnt
memory_stick_mount_point
[List items in the directory "/dev" that begin with "sda"]
pi@raspberrypi ~/test $ ls -1 /dev/sda*
/dev/sda
/dev/sda1
[Mount the memory stick located (metaphorically) at the device file /dev/sda1 to the directory /mnt/memory_stick_mount_point]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
[
Note that:
-o (lowercase letter "o", not the number zero) specifies that an option string follows.
uid=pi,gid=pi specifies that the user ID is "pi" and the group ID is "pi" (note there are no spaces allowed between these two terms).
/dev/sda1 is the first partition on the first USB memory stick that the computer can detect. [Future: Investigate whether this is accurate.]
]
[List the contents of the top directory in the memory stick filesystem]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
work
4) Use the following commands to copy data to and from the memory stick.
[List items in the current directory, one line per item]
work.log
[Make a new directory to hold a copy of the contents of the memory stick]
[Copy the contents of the "work" directory on the memory stick to the directory "memory_stick_contents"]
[List the contents of the directory "memory_stick_contents"]
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
display_hex_bytes.py
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
pypy_sha256.py
transaction.py
[Copy the file "work.log" to the memory stick]
[List the contents of the top directory in the memory stick filesystem. This allows you to confirm that the file has been copied over.]
work
work.log
pi@raspberrypi ~/test $ ls -1
work.log
[Make a new directory to hold a copy of the contents of the memory stick]
pi@raspberrypi ~/test $ mkdir memory_stick_contents
[Copy the contents of the "work" directory on the memory stick to the directory "memory_stick_contents"]
pi@raspberrypi ~/test $ cp -r /mnt/memory_stick_mount_point/work/* memory_stick_contents
[List the contents of the directory "memory_stick_contents"]
pi@raspberrypi ~/test $ ls -1 memory_stick_contents
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
display_hex_bytes.py
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
pypy_sha256.py
transaction.py
[Copy the file "work.log" to the memory stick]
pi@raspberrypi ~/test $ cp work.log /mnt/memory_stick_mount_point
[List the contents of the top directory in the memory stick filesystem. This allows you to confirm that the file has been copied over.]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
work
work.log
5) Use the following command sequence to unmount the memory stick. Once unmounted, it can be physically unplugged without causing any problems.
[Unmount the memory stick]
[confirm that it has been unmounted]
[nothing should be displayed]
pi@raspberrypi ~/test $ sudo umount /mnt/memory_stick_mount_point
[confirm that it has been unmounted]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
[nothing should be displayed]
6) Unplug the memory stick from the destination computer.
Representative Sample Of Bash Commands Used
Note: The output is not always included for every command.
[Print the path of the current working directory (pwd = "print working directory")]
/home/pi
[Make a directory named "test"]
[Change directory to "test"]
[Create a file named "work.log"]
[List items in the current directory, one line per item]
work.log
[List items in the directory "/dev" that begin with "sda"]
/dev/sda
/dev/sda1
[Make a new directory to be the mount point for the memory stick. Making this new directory in the /mnt directory requires root permissions, so "sudo" is used.]
[List items in the directory "/mnt"]
drive1
memory_stick_mount_point
[Mount a memory stick located at the device file /dev/sda1 to the directory /mnt/memory_stick_mount_point]
[Copy the contents of the "work" directory on the memory stick to the directory "memory_stick_contents"]
[Check the kernel version]
[Edit a file using the Nano text editor. If the file does not exist, it will be created.]
[Copy last 10 lines of work.log to a new file named "private_key.txt"]
[Print the contents of a file]
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
[Get the byte length of the contents of a file. Use
64
[Copy a file from the "memory_stick_contents" directory to the working directory]
[Unpack the zipped tape archive file ecdsa-0.10.tar.gz]
[Copy the "ecdsa" directory (along with its contents) into the work directory.]
[Copy the file "work.log" to the memory stick (via its mountpoint directory)]
[Unmount the memory stick]
[Print an excerpt from a file. In this case, print lines 40-66 inclusive.]
[Read a file "tx_copied.txt", removing all space and newline characters, and writing the result to a new file "tx.txt"]
[Append a newline to a file]
pi@raspberrypi ~ $ pwd
/home/pi
[Make a directory named "test"]
pi@raspberrypi ~ $ mkdir test
[Change directory to "test"]
pi@raspberrypi ~ $ cd test
[Create a file named "work.log"]
pi@raspberrypi ~/test $ touch work.log
[List items in the current directory, one line per item]
pi@raspberrypi ~/test $ ls -1
work.log
[List items in the directory "/dev" that begin with "sda"]
pi@raspberrypi ~/test $ ls -1 /dev/sda*
/dev/sda
/dev/sda1
[Make a new directory to be the mount point for the memory stick. Making this new directory in the /mnt directory requires root permissions, so "sudo" is used.]
pi@raspberrypi ~/test $ sudo mkdir /mnt/memory_stick_mount_point
[List items in the directory "/mnt"]
pi@raspberrypi ~/test $ ls -1 /mnt
drive1
memory_stick_mount_point
[Mount a memory stick located at the device file /dev/sda1 to the directory /mnt/memory_stick_mount_point]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
[Copy the contents of the "work" directory on the memory stick to the directory "memory_stick_contents"]
pi@raspberrypi ~/test $ cp -r /mnt/memory_stick_mount_point/work/* memory_stick_contents
[Check the kernel version]
pi@raspberrypi ~/test $ uname -r
[Edit a file using the Nano text editor. If the file does not exist, it will be created.]
pi@raspberrypi ~/test $ nano dice_rolls.txt
[Copy last 10 lines of work.log to a new file named "private_key.txt"]
pi@raspberrypi ~/test $ tail -10 work.log > private_key.txt
[Print the contents of a file]
pi@raspberrypi ~/test $ cat private_key.txt
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
[Get the byte length of the contents of a file. Use
tr
to remove the newline character at the end of the file.]
pi@raspberrypi ~/test $ cat private_key.txt | tr -d '\n' | wc -c
64
[Copy a file from the "memory_stick_contents" directory to the working directory]
pi@raspberrypi ~/test $ cp memory_stick_contents/bjorn_edstrom_ripemd160.py bjorn_edstrom_ripemd160.py
[Unpack the zipped tape archive file ecdsa-0.10.tar.gz]
pi@raspberrypi ~/test $ tar -zxvf ecdsa-0.10.tar.gz
[Copy the "ecdsa" directory (along with its contents) into the work directory.]
pi@raspberrypi ~/test $ cp -r ecdsa-0.10/ecdsa ecdsa
[Copy the file "work.log" to the memory stick (via its mountpoint directory)]
pi@raspberrypi ~/test $ cp work.log /mnt/memory_stick_mount_point
[Unmount the memory stick]
pi@raspberrypi ~/test $ sudo umount /mnt/memory_stick_mount_point
[Print an excerpt from a file. In this case, print lines 40-66 inclusive.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
[Read a file "tx_copied.txt", removing all space and newline characters, and writing the result to a new file "tx.txt"]
aineko:work stjohnpiano$ cat tx_copied.txt | tr -d ' \n' > tx.txt
[Append a newline to a file]
aineko:work stjohnpiano$ echo '' >> tx.txt
Example of logging into a Raspberry Pi using the default credentials (username = "pi", password = "raspberry"). Note that the password is not printed to the screen.
[Insert the power cable into the Raspberry Pi. Wait for it to boot up.]
raspberrypi login: pi
Password:
Last login: Sun Mar 27 18:28:14 UTC 2016 on tty1
Linux raspberrypi 4.1.13+ #826 PREEMPT Fri Nov 13 20:13:22 GMT 2015 armv61
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pi@raspberrypi ~ $
Example of shutting down a Raspberry Pi:
pi@raspberrypi ~/test $ sudo halt
[a variety of output is printed, then the Raspberry Pi shuts down]
[Then unplug the power cable.]
Downloadable Assets
This article's assets are files containing 5 sets of 212 dice rolls. 32 bytes of entropy were derived from each set.
List of assets:
- dice_rolls_3.txt (known during this project as dice_rolls.txt)
- dice_rolls_4.txt (known during this project as dice_rolls2.txt)
- dice_rolls_5.txt (known during this project as dice_rolls3.txt)
- dice_rolls_6.txt (known during this project as dice_rolls4.txt)
- dice_rolls_7.txt (known during this project as dice_rolls5.txt)
The asset names have been changed because this datafeed already contains some existing assets with the prefix "dice_rolls".
Asset: Set 1 of the dice roll results
dice_rolls_3.txt
Asset: Set 2 of the dice roll results
dice_rolls_4.txt
Asset: Set 3 of the dice roll results
dice_rolls_5.txt
Asset: Set 4 of the dice roll results
dice_rolls_6.txt
Asset: Set 5 of the dice roll results
dice_rolls_7.txt
The following code assets were developed / tested on my work computer during previous projects. During this project, I used them successfully on the offline computer.
List of assets of other articles:
1) bitcoin_functions.py
2) bjorn_edstrom_ripemd160.py
3) convert_dice_rolls_to_hex_bytes_2.py
4) create_nonstandard_transaction.py
5) create_transaction.py
6) display_hex_bytes.py
7) ecdsa-0.10.tar.gz
8) generate_bitcoin_address_3.py
9) nonstandard_bitcoin_functions.py
10) nonstandard_transaction.py
11) pypy_sha256.py
12) transaction.py
Asset 1: A library of functions for handling standard Bitcoin data types.
bitcoin_functions.py [paywalled]
Asset 2: An implementation of RIPEMD-160, written by Björn Edström.
bjorn_edstrom_ripemd160.py [paywalled]
Asset 3: A script that converts dice roll results into bytes.
convert_dice_rolls_to_hex_bytes_2.py [paywalled]
Asset 4: A script that creates and signs a nonstandard Bitcoin transaction with one standard P2PKH input and one nonstandard P2SH output.
create_nonstandard_transaction.py [paywalled]
Asset 5: A script that creates and signs a standard Bitcoin transaction with one input and one output.
create_transaction.py [paywalled]
Note: This asset was not actually used during this project.
Asset 6: A script that prints a hex byte string, inserting spaces and newlines to make it more readable.
display_hex_bytes.py [paywalled]
Asset 7: A Python implementation of ECDSA cryptography, written by Peter Pearson.
ecdsa-0.10.tar.gz [paywalled]
Asset 8: A script that generates a standard Bitcoin address from a private key.
generate_bitcoin_address_3.py [paywalled]
Asset 9: A library of functions for handling nonstandard Bitcoin data types.
nonstandard_bitcoin_functions.py [paywalled]
Asset 10: A library of classes for nonstandard Bitcoin transactions.
nonstandard_transaction.py [paywalled]
Asset 11: A Python implementation of SHA256.
pypy_sha256.py [paywalled]
Asset 12: A library of classes for standard Bitcoin transactions.
transaction.py [paywalled]
List of the articles that I read in order to choose these assets:
- Recipe for generating entropy bytes using dice
- Recipe for generating a Bitcoin address
- Recipe for creating and signing a standard Bitcoin transaction
- Recipe for creating and signing a nonstandard Bitcoin transaction
- Displaying hex bytes for manual copying
Notes
Parts:
- Definitions and acryonyms
- Services used during this project
- Equipment used during this project
- Entropy values generated during this project
- Addresses generated and/or used in this project
- Transactions created during this project
- create_nonstandard_transaction.py settings used to create the transactions
- Time taken to manually transfer transactions by typing
- Transaction confirmation times
- Dice rolling results
- Recording shell output
- Miscellaneous
Definitions and acryonyms
P2PKH = Pay-To-Public-Key-Hash
P2SH = Pay-To-Script-Hash
previous_output_hash is the big-endian 32-byte double-SHA256 hash of a previous transaction.
tx = transaction
txid = "transaction id". It is the little-endian form of the previous_output_hash.
aka = "also known as". Indicates a secondary name for something. Example: Robert (aka Bob) is a good programmer. Example: Transaction tx1 (aka tx1a) was never mined.
My 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.
My working definition of a nonstandard transaction:
- It has at least one input and at least one output.
- At least one input or output address is not a standard Pay-To-Public-Key-Hash (P2PKH) address.
My working definition of a standard address:
- An uncompressed single-signature Pay-To-Public-Key-Hash (P2PKH) address.
Services used during this project
I used
localbitcoins.com
to:
- store some bitcoin
- transfer a small amount of bitcoin to the test address
- receive this small amount back again from the test address
- transfer a relatively larger amount of bitcoin to the now-validated test address
- receive this larger amount back again from the test address
I used
bitcoinfees.earn.com
to choose fee rates for my transactions. It displays estimated delays (in blocks and in minutes) for ranges of fee rates (in satoshis / byte).
I used the search field at
live.blockcypher.com
to search for transactions by txid.
On the resulting transaction pages e.g. for tx0:
live.blockcypher.com/btc/tx/07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
I was able to click Advanced Details / API Call, which produced a raw text dump of the transaction, e.g.
api.blockcypher.com/v1/btc/main/txs/07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd?limit=50&includeHex=true
Note: I had to read through the transaction raw text dump in order to find the index of a particular unspent output. A service that allowed someone to look up the index of an unspent output would be useful.
I used
live.blockcypher.com/btc/decodetx
to decode a signed transaction. If the service can successfully decode a transaction, this indicates that the transaction is formatted correctly.
I used
live.blockcypher.com/btc/pushtx
to upload a signed transaction for broadcast to the Bitcoin network.
I used
www.blockchain.com/btc/pushtx
to attempt to upload a signed transaction for broadcast to the Bitcoin network. The error message it produced was helpful.
I used the search field at
www.blockchain.com
to search for transactions (by txid) and for addresses.
Equipment used during this project
My work computer: Aineko, a 2008 Macbook running Mac OS X 10.6.8 Snow Leopard, with Python 2.7.13 installed.
The offline computer used during this project: A Raspberry Pi, Model B+ V1.2 [circa 2014]. It has various ports, including 4 USB ports (which allows simultaneous use of a mouse, a keyboard, and a memory stick) and an HDMI port. It does not have an onboard WiFi chip. I have various peripherals for the Raspberry Pi. These are: An 8GB micro SD card with an installed operating system, a Raspberry Pi power cable, a screen with a DVI port, a screen power cable, a DVI male-male connector cable, a DVI female to HDMI male converter, a USB keyboard, a USB mouse, and a plastic case customised for the Raspberry Pi Model B+. The installed operating system is Raspbian GNU/Linux 7 (wheezy) and the Linux kernel version is 4.1.13+. Tools: nano 2.2.6, tee 8.13, Python 2.7.3.
USB memory stick: 8 GB, FAT32 format, name = "NO NAME"
Entropy values generated during this project
Using dice, I generated 5 sets of 212 dice rolls. Files containing the dice roll results are listed in the Downloadable Assets section. I extracted 32 bytes of entropy from each set, producing these files, which contain entropy values:
- private_key.txt
- random_value2.txt
- random_value3.txt
- random_value4.txt
- random_value.txt
The values in these files were printed during the logged work on the Raspberry Pi, so I can go over the project log, find them, and copy them here.
Values:
- private_key.txt
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- random_value.txt
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
- random_value2.txt
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
- random_value3.txt
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
- random_value4.txt
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
Note that random_value2.txt and random_value3.txt contain the same value. The value in random_value3.txt should have been derived from dice_rolls4.txt, but I accidentally derived it from dice_rolls3.txt instead.
Uses of these entropy values:
- private_key.txt was used as the private key for the test address.
- random_value.txt was used to sign tx1a.
- random_value2.txt was used to sign tx1b.
- random_value3.txt was used to sign tx1c.
- random_value4.txt was used to sign tx3.
Addresses generated and/or used in this project
I generated one address: "test address"
Test address:
- Private key (hex bytes):
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- Bitcoin address:
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
The test address was an output address in transactions tx0 and tx2 (both created by the LocalBitcoins service).
I used two receiving addresses on my LocalBitcoins account.
Receiving address 1: "output address"
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
Receiving address 1 was the output address for tx1 (aka tx1a) and tx1c.
Because LocalBitcoins saw tx1a, which used receiving address 1 as its output address, LocalBitcoins generated a second receiving address (receiving address 2), even though tx1a was never mined.
Receiving address 2: "output address", later "lb_address2" (lb = LocalBitcoins)
36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
Receiving address 2 was the output address for tx1b and tx3.
Note from LocalBitcoins concerning receiving addresses:
{To protect your privacy, we provide a new bitcoin address for each transfer. This prevents someone from tracking all the payments you receive by looking at the blockchain.
Note that addresses are valid only for 12 months.}
Because of this note, I used receiving address 1 as an output address in tx1c (mined), even though LocalBitcoins had already generated receiving address 2 for me after seeing tx1a (never mined). LocalBitcoins still interpreted tx1c as a deposit to my account.
Transactions created during this project
Transactions:
- tx0
- tx1 / tx1a
- tx1b
- tx1c
- tx2
- tx3
I'll use:
- txid0 to mean the txid (transaction id) of tx0
- txid1 to mean the txid of tx1 (aka tx1a)
- txid1a to mean the txid of tx1a
- txid1b to mean the txid of tx1b
- txid1c to mean the txid of tx1c
- txid2 to mean the txid of tx2
- txid3 to mean the txid of tx3
Transaction sequence:
- tx0: I used LocalBitcoins to transfer some bitcoin to the test address. LocalBitcoins created a transaction that included this transfer.
- tx1 / tx1a: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 1 (on my LocalBitcoins account). I used a transaction-broadcasting service to broadcast it to the Bitcoin network. This transaction was never mined. LocalBitcoins saw this transaction and generated a new receiving address for my account, "receiving address 2".
- tx1b: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 2. This transaction was rejected by two transaction-broadcasting services, because it was a double-spend attempt (it tried to spend the same unspent output as tx1a did, but to a different address, while tx1a was still in the memory pools of the services).
- tx1c: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 1, using a higher fee than in tx1a. This was a replace-by-fee transaction (only the fee was different), which is valid on the Bitcoin network (unlike a double-spend transaction), but the two transaction-broadcasting services still rejected it. I waited until tx1a had been cleared from the memory pool of one of the transaction-broadcasting services, and then uploaded tx1c again to that service. This time, the service accepted tx1c, which was later mined.
- tx2: I used LocalBitcoins to transfer a relatively larger amount of bitcoin to the test address. LocalBitcoins created a transaction that included this transfer.
- tx3: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 2 (on my LocalBitcoins account). I used a transaction-broadcasting service to broadcast it to the Bitcoin network. After a while, tx3 was mined.
1) tx0: I used LocalBitcoins to transfer some bitcoin to the test address. LocalBitcoins created a transaction that included this transfer.
txid0:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
I did not obtain and use the raw byte sequence of transaction tx0. Instead, I used a service to get the information I needed about an output in tx0. To repeat my steps, browse to the link below, click "Advanced Details", and click "API Call". The result will be the service's information concerning tx0, not the raw form of tx0 as stored in the Bitcoin blockchain.
live.blockcypher.com/btc/tx/07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Key details:
- block_hash:
0000000000000000001b43b8af8973377619def5043634e9cb2d7dd584d973be
- block_height: 550741
- confirmed: 2018-11-19T19:46:37Z
- received: 2018-11-19T19:46:37Z
- txid:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
- vout_sz (number of outputs): 32
tx0 sent a new unspent output to the test address.
From tx0, I acquired the following data of this particular unspent output for use as the input in tx1:
- index: 15
- value: 0.002 bitcoin
- The txid of tx0, which contains this unspent output, is:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
2) tx1 / tx1a: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 1 (on my LocalBitcoins account). I used a transaction-broadcasting service to broadcast it to the Bitcoin network. This transaction was never mined. LocalBitcoins saw this transaction and generated a new receiving address for my account, "receiving address 2".
txid1 / txid1a:
add54b899f1aba8b6276e42af86c3c03b0120a864451640b4a8d3fec89a4a72d
tx1 / tx1a (raw byte form):
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
3) tx1b: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 2. This transaction was rejected by two transaction-broadcasting services, because it was a double-spend attempt (it tried to spend the same unspent output as tx1a did, but to a different address, while tx1a was still in the memory pools of the services).
txid1b:
3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16
tx1b (raw byte form):
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
4) tx1c: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 1, using a higher fee than in tx1a. This was a replace-by-fee transaction (only the fee was different), which is valid on the Bitcoin network (unlike a double-spend transaction), but the two transaction-broadcasting services still rejected it. I waited until tx1a had been cleared from the memory pool of one of the transaction-broadcasting services, and then uploaded tx1c again to that service. This time, the service accepted tx1c, which was later mined.
txid1c:
8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
tx1c (raw byte form):
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
Key details:
- block_hash:
000000000000000000091db255f327f3938cb33cd1076d7554b7bbd22b9c1000
- block_height: 551106
- confirmed: 2018-11-22T20:17:05Z
- received: 2018-11-22T17:46:01.324Z
- hash (txid):
8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
- vout_sz (number of outputs): 1
5) tx2: I used LocalBitcoins to transfer a relatively larger amount of bitcoin to the test address. LocalBitcoins created a transaction that included this transfer.
txid2:
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
I did not obtain and use the raw byte sequence of transaction tx2. Instead, I used a service to get the information I needed about an output in tx2. To repeat my steps, browse to the link below, click "Advanced Details", and click "API Call". The result will be the service's information concerning tx2, not the raw form of tx as stored in the Bitcoin blockchain.
live.blockcypher.com/btc/tx/af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
Key details:
- block_hash:
0000000000000000001f85686e50bbc4e929b50768669165731e5c73a690f680
- block_height: 551219
- block_index: 502
- hash (txid):
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
- total: 4991126340
- fees: 152990
- size: 2822
- preference: high
- relayed_by: 45.79.10.204:8333
- confirmed: 2018-11-23T18:25:35Z
- received: 2018-11-23T18:10:40.724Z
- vout_sz (number of outputs): 85
tx2 sent a new unspent output to the test address.
From tx2, I acquired the following data of this particular unspent output for use as the input in tx3:
- index: 25
- value: 1200000 satoshi (0.012 bitcoin)
- The txid of tx2, which contains this unspent output, is:
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
6) tx3: I created a transaction on the offline Raspberry Pi that transferred the available bitcoin from the test address to receiving address 2 (on my LocalBitcoins account). I used a transaction-broadcasting service to broadcast it to the Bitcoin network. After a while, tx3 was mined.
txid3:
00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093
tx3 (raw byte form):
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
Key details:
- block_hash:
0000000000000000000ab9373f3ce1c96528c09ffa13fe2005a4d32470b7c98b
- block_height: 552081
- confirmed: 2018-11-30T23:27:35Z
- received: 2018-11-30T18:55:34.661Z
- hash (txid):
00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093
- vout_sz (number of outputs): 1
create_nonstandard_transaction.py settings used to create the transactions
tx1 (aka tx1a):
##### START CONTROLS
random_value = "91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "1" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
tx1b:
##### START CONTROLS
random_value = "644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "66" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
tx1c:
##### START CONTROLS
random_value = "644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "66" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
tx3:
##### START CONTROLS
random_value = "f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2",
"previous_output_index": "25",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
"satoshi_amount": "1200000",
#"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx",
"satoshi_amount": "1200000",
#"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "10" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
Time taken to manually transfer transactions by typing
In this project, I read the transactions on the screen of the offline computer (Raspberry Pi) and manually typed them into text files on the online computer (Aineko). Each transaction was a nonstandard P2SH transaction that contained one standard P2PKH input and one nonstandard P2SH output.
I used a tool to display the transaction hex bytes in a more readable format by inserting whitespace. I found that listening to music made the typing process quite tolerable.
I used a stopwatch to record the time taken for typing each transaction, with one exception (tx1c) where I forgot to do so. This time includes a final double-check of each hex character group on the online computer against the original group displayed on the offline computer's screen.
Times taken (minutes:seconds):
- tx1 (aka tx1a): 13:18
- tx1b: 12:37
- tx1c: Not recorded
- tx3: 10:04
From the recorded times, I see that manually typing out a single-input single-output transaction should take about 15 minutes at most, and about 10 minutes if done quickly.
Let's calculate the overall data transfer rate in bits / second. Don't include tx1c in this calculation.
Transaction sizes according to my work:
- tx1 / tx1a: 225 bytes
- tx1b: 226 bytes
- tx3: 226 bytes
Total data size:
225 + 226 + 226 = 677 bytes = 677*8 bits = 5416 bits
Total time:
(13*60 + 18) + (12*60 + 37) + (10*60 + 4) = 2159 seconds
Overall data transfer rate (bits / second):
5416 bits / 2159 seconds = 5416 / 2159 ~=
2.51 bits / second
At this data transfer rate, how long would it hypothetically take to transfer the code assets over to the Raspberry Pi manually, typing them in rather than using a memory stick?
Make a new test directory. Copy these assets into it:
- bitcoin_functions.py
- bjorn_edstrom_ripemd160.py
- convert_dice_rolls_to_hex_bytes_2.py
- create_nonstandard_transaction.py
- create_transaction.py
- display_hex_bytes.py
- ecdsa-0.10.tar.gz
- generate_bitcoin_address_3.py
- nonstandard_bitcoin_functions.py
- nonstandard_transaction.py
- pypy_sha256.py
- transaction.py
Unpack the zipped tape archive file ecdsa-0.10.tar.gz. In the resulting directory ecdsa-0.10, find the directory "ecdsa" and copy it to the test directory.
Delete:
- ecdsa-0.10.tar.gz
- ecdsa-0.10
Open a terminal and change directory to the test directory.
Find the byte length of all the files in the test directory tree.
aineko:test stjohnpiano$ find . -type f -exec wc -c {} \;
23341 ./bitcoin_functions.py
14429 ./bjorn_edstrom_ripemd160.py
7034 ./convert_dice_rolls_to_hex_bytes_2.py
13624 ./create_nonstandard_transaction.py
13000 ./create_transaction.py
2323 ./display_hex_bytes.py
644 ./ecdsa/__init__.py
178 ./ecdsa/_version.py
1640 ./ecdsa/curves.py
7023 ./ecdsa/der.py
24328 ./ecdsa/ecdsa.py
8609 ./ecdsa/ellipticcurve.py
12323 ./ecdsa/keys.py
16105 ./ecdsa/numbertheory.py
2794 ./ecdsa/rfc6979.py
11985 ./ecdsa/six.py
28868 ./ecdsa/test_pyecdsa.py
9263 ./ecdsa/util.py
4270 ./generate_bitcoin_address_3.py
2371 ./nonstandard_bitcoin_functions.py
12817 ./nonstandard_transaction.py
11687 ./pypy_sha256.py
19219 ./transaction.py
23341 + 14429 + 7034 + 13624 + 13000 + 2323 + 644 + 178 + 1640 + 7023 + 24328 + 8609 + 12323 + 16105 + 2794 + 11985 + 28868 + 9263 + 4270 + 2371 + 12817 + 11687 + 19219 =
247875 bytes
Total data:
247875 bytes = 247875 * 8 bits =
1983000 bits
Total time at manual transfer data rate:
1983000 bits / (2.51 bits / second) = 1983000 / 2.51 ~=
790039 seconds ~=
13167 hours ~=
1097 12-hour days ~=
3 years (typing for 12 hours / day)
In practice, typing ASCII code would be significantly faster than typing hex bytes, but this result is a good upper-bound estimate.
Delete the test directory.
Transaction confirmation times
The following times are calculated by subtracting the "received" time from the "confirmed" time as reported by the service live.blockcypher.com. To acquire this information from the service, search for a txid. On the resulting transaction page, click "Advanced Details" then "API Call". On the resulting transaction information page, look for the key names "confirmed" and "received" and record their corresponding values.
Transactions tx0 and tx2 were created by LocalBitcoins, with fees chosen by LocalBitcoins. They are not included here.
Transactions tx1 (aka tx1a) and tx1b were never mined. Transactions tx1c and tx3 were mined.
I assume that "received" time means "the time at which the service first saw the transaction" and that "confirmed" time means "the time at which the transaction was first included in a block".
Transaction details according to the service:
- tx1c: size = 222 bytes, fee = 14586 satoshi
- tx3: size = 222 bytes, fee = 2210 satoshi
Transaction details according to my work:
- tx1c: chosen fee rate = 66 satoshi / byte, estimated size = 221 bytes, size = 226 bytes, fee = 14586 satoshi
- tx3: chosen fee rate = 10 satoshi / byte, estimated size = 221 bytes, size = 226 bytes, fee = 2210 satoshi
Received times:
- tx1c: 2018-11-22T17:46:01.324Z
- tx3: 2018-11-30T18:55:34.661Z
Confirmed times:
- tx1c: 2018-11-22T20:17:05Z
- tx3: 2018-11-30T23:27:35Z
For each transaction, subtract received time from confirmed time to find time taken for confirmation:
- tx1c:
2018-11-22T20:17:05Z - 2018-11-22T17:46:01.324Z =
0 days + (20:17 - 17:46) =
2:31 (hours:minutes)
- tx3:
2018-11-30T23:27:35Z - 2018-11-30T18:55:34.661Z =
0 days + (23:27 - 18:55) =
4:32 (hours:minutes)
Times taken for confirmation (hours:minutes):
- tx1c: 2:31
- tx3: 4:32
Estimated delays according to the service bitcoinfees.earn.com:
- tx1c: 0 blocks (0-35 minutes) for the fee rate of 60 satoshi / byte.
- tx3: 0-7 blocks (0-180 minutes) for the fee rate of 10 satoshi / byte.
Dice rolling results
I found that listening to music made the dice rolling quite tolerable.
Using a set of 5 dice, and rolling them in a tray with raised edges, I generated 5 sets of 212 dice roll results. The files containing these results are included in the Downloadable Assets section.
Table matching sets to filenames:
- Set 1: dice_rolls.txt
- Set 2: dice_rolls2.txt
- Set 3: dice_rolls3.txt
- Set 4: dice_rolls4.txt
- Set 5: dice_rolls5.txt
32 bytes of entropy were derived from each set.
The entropy derived from set 1 was used for the private key of the test address.
The entropy derived from set 2 was used to sign the transaction tx1 (aka tx1a).
The entropy derived from set 3 was used to sign the transaction tx1b.
The entropy derived from set 4 was intended to be used for signing the transaction tx1c. However, I made a mistake and re-used the entropy derived from set 3 to do this.
The entropy derived from set 5 was used to sign the transaction tx3.
I used a stopwatch to record the time taken for each set of 212 results.
Times taken (minutes:seconds):
- Set 1: 10:30
- Set 2: 7:32
- Set 3: 6:33
- Set 4: 5:53
- Set 5: 6:59
Extra entropy generated but not used:
- Set 1: 1 byte
- Set 2: 4 bytes
- Set 3: 1 byte
- Set 4: 1 byte
- Set 5: 5 bytes
From the recorded times, I see that using 5 dice to generate 32 bytes of entropy should take about 10 minutes at most, and about 7 minutes if done quickly.
Let's calculate the overall entropy generation rate in bits / second.
Total entropy bytes: 32*5 + (1+4+1+1+5) = 172 bytes = 172*8 bits = 1376 bits
Total time: (10*60 + 30) + (7*60 + 32) + (6*60 + 33) + (5*60 + 53) + (6*60 + 59) = 2247 seconds
Overall entropy generation rate:
1376 bits / 2247 seconds = 1376 / 2247 ~=
0.61 bits / second
Recording shell output
In a previous project, I learned how to execute a command in the bash shell and simultaneously archive its output in a text file.
The project: Offline installation of a C compiler on Centos 6.9 Minimal on Kalkin
Excerpt:
6) RECORDING SHELL OUTPUT
Use theteecommand.
Example:
program [arguments...] 2>&1 | tee -a outfile
This should display both output and error messages and append these to a storage file.
The -a option means "append".
2>&1can be used in Bash to redirect errors/warnings (which are normally sent to stderr) to normal output (stdout). In this case both will be piped to the next command (tee).
Note:teedoesn't record the command itself, only the output. This can be worked around by echoing the command to the log file before running it. Use the-eflag for theechocommand so that it will interpret backslash-escaped newline characters.
[root@kalkin work]# echo -e "\n\nCOMMAND# rpm --version\n" | tee -a work.log
[root@kalkin work]# rpm --version | tee -a work.log
[root@kalkin work]# echo -e "\n\nCOMMAND# rpm --help\n" | tee -a work.log
[root@kalkin work]# rpm --help | tee -a work.log
Example of capturing output sent to standard error:
# rpm --install rpms/cloog-ppl-0.15.7-1.2.el6.x86_64.rpm --test 2>&1 | tee -a work.log
Note: If the command itself includes a newline sequence "\n", the -e flag in the
echo
command will cause it to be recorded as an actual newline byte. You will have to edit the log file manually in order to correct this. Note: Use a text editor to remove any mistaken commands from the log file (as long as they didn't cause irreversible changes of some kind), so that the command can be run again properly.
You can check that the
tee
is present by running the command
tee --version
. I don't usually record the logging commands themselves in a project. I also don't log every command that I use for gathering information (e.g.
ls -1
,
cat [filename]
).While logging an operation, I usually record the commands (although not in complete detail) along with annotations and comments in a separate text file (usually the main project log). When the operation is finished, I copy the resulting log, piece by piece, into the main project log, integrating the annotations and comments as I go.
Miscellaneous
Each new Bitcoin transaction signature requires a new random value. Using the same random value twice in two different ECDSA signatures (that are both broadcast) could compromise the secrecy of the private key.
Keeping the intermediate results e.g. tx_copied.txt during the project meant that if there were an error, I could go back and look for it without having to completely redo each step.
During logging of the commands on the Raspberry Pi, the text "COMMAND#" was generated as a placeholder. Later, I replaced this placeholder with "pi@raspberrypi ~/test $".
On the LocalBitcoins web application, in Wallet / Receive bitcoins / Old addresses, I found this note:
{To protect your privacy, we provide a new bitcoin address for each transfer. This prevents someone from tracking all the payments you receive by looking at the blockchain.
Note that addresses are valid only for 12 months.}
along with a list of old addresses (although only the first 10 characters of each address are shown).
Listening to music made manually copying a transaction a more tolerable experience.
For transferring data to an offline computer, using a memory stick is not the most secure way (various malware items have been able to store themselves on memory sticks). However, for storing bitcoin, using an offline computer and a memory stick is more secure than using an online computer, and security is always relative.
Ideally, the memory stick should only be used once to transfer all the code to the offline computer. Then, the memory stick should be destroyed, and any data produced on the offline computer should be manually copied to an online computer. See this article for an example of how to display data in a more easily-read format: Displaying hex bytes for manual copying
- In the limit case, code should only be moved onto an offline computer by manually typing it all in. This is not always possible within a useful timeframe. In the "Time taken to manually transfer transactions by typing" part of the Notes section, I estimated an upper bound of 3 years to manually copy the code used in this project to the offline computer. Admittedly, manually copying code would be significantly faster than manually copying hex bytes.
- In practice, steadily increasing security, as and when it is reasonable and affordable to do so, is usually the most effective strategy.
- If this project were repeated, without the logging, it would involve only a single data transfer via memory stick (the initial code installation). Input data (txids, output indices, addresses) was copied over to the offline computer or generated on it. All signed transactions were manually copied over to the online computer.
The errors returned by the transaction-broadcasting services when I uploaded a double-spend attempt (tx1b) are shown below. The same errors occurred when I uploaded a replace-by-fee transaction (tx1c). In both situations, the original transaction (tx1a) was still in the memory pools of both services.
live.blockcypher.com/btc/pushtx:
"Server Error (500)"
www.blockchain.com/btc/pushtx:
"Validation Error: BitcoindException(super=com.neemre.btcdcli4j.core.BitcoindException: Error #-26: 18: txn-mempool-conflict, code=-26)"
Transferring values from the online computer to the offline computer:
On the offline computer, edit create_nonstandard_transaction.py using the Nano text editor. Manually enter the gathered / chosen values (reading them from the online computer), except for the variables
random_value
and
input_data["private_key_hex"]
. - Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- The variable
input_data
is a dictionary that contains several other variables. Delete the existing value for the variable
input_data["private_key_hex"]
. Then use the Nano option "Read File" to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- Note: With long strings, e.g. the txid, you can make a copy on the online computer and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again to form the original txid.
Financial Information For This Project
Parts
- Definitions and prices
- Cost of storing a larger amount of bitcoin in the test address
- Cost of testing the test address
- Total cost of the project
Definitions and prices
1 satoshi = 0.00000001 bitcoin (10^(-8) bitcoin)
USD = United States Dollars ($)
BTC = bitcoin
LocalBitcoins fees:
- Current deposit fee for incoming transactions: 0.00015 BTC
- Current transaction fee (deducted from the LocalBitcoins wallet balance, not from the transaction amount): 0.00005 BTC
Cost of testing the test address
In order to validate the test address, I needed to transfer a small amount of bitcoin in and out of it. I would need this amount to be at least:
(Bitcoin network transaction fee) + (LocalBitcoins deposit fee)
The Bitcoin network transaction fee was needed in order to pay for the second transaction (that will later transfer bitcoin out of the test address).
To calculate the Bitcoin network transaction fee, I used a service to look at current fee rates for Bitcoin transactions, and chose a reasonably high fee rate:
60 satoshi / byte
I estimated that a nonstandard transaction with one P2PKH input and one P2SH output should be approximately 221 bytes. The estimated fee (using the chosen fee rate) would therefore be:
221 bytes * 60 satoshi / byte = 221 * 60 =
13260 satoshi (0.00013260 BTC)
I therefore needed to transfer at least this much to the test address:
(Bitcoin network transaction fee) + (LocalBitcoins deposit fee)
= 0.00013260 + 0.00015
= 0.00028260 BTC
Then-current USD / BTC exchange rate:
$4904.99 / BTC
(4904.99 USD / BTC) * 0.00028260 BTC = 4904.99 * 0.00028260 ~=
$1.39
I decided to transfer approximately $10 worth of bitcoin to the test address, so as to have room to manoeuvre. If the second transaction were not mined, I would need to increase the fee, and upload a new version for broadcasting.
$10 * (1 BTC / 4904.99 USD) = 10 * 1 / 4904.99 ~=
0.00203874 BTC
I transferred 0.0020 bitcoin (~$9.80) from my LocalBitcoins account into the test address. LocalBitcoins created transaction tx0, which included this transfer.
- LocalBitcoins charged a transaction fee of 0.00005 (deducted from my wallet balance, not from the transaction amount).
I created transaction tx1a and tx1b, which were not mined, so no bitcoin was spent on them.
I created transaction tx1c, which transferred 185414 satoshi from the test address to my LocalBitcoins account.
- It included a Bitcoin network transaction fee of 14586 satoshi.
- LocalBitcoins charged a deposit fee of 0.00015 BTC.
Costs of this test:
- LocalBitcoins transaction fee: 0.00005000 bitcoin
- Bitcoin network transaction fee: 14586 satoshi (0.00014586 bitcoin)
- LocalBitcoins deposit fee: 0.00015000 bitcoin
Total cost in bitcoin:
(LocalBitcoins transaction fee) + (Bitcoin network transaction fee) + (LocalBitcoins deposit fee) =
0.00005000 + 0.00014586 + 0.00015000 =
0.00034586 bitcoin
Total cost (USD):
0.00034586 bitcoin * (4904.99 USD / BTC) =
0.00034586 * (4904.99) ~=
$1.70
Cost of storing a larger amount of bitcoin in the test address
I decided to transfer ~$50 worth of bitcoin to the test address.
Then-current USD / BTC exchange rate:
$4212 / BTC
$50 * (1 BTC / 4212 USD) = 50 * 1 / 4212 ~= 0.01187084 ~=
0.0120 bitcoin
I transferred 0.0120 bitcoin (~$50) from my LocalBitcoins account into the test address. LocalBitcoins created transaction tx2, which included this transfer.
- LocalBitcoins charged a transaction fee of 0.00005 (deducted from my wallet balance, not from the transaction amount).
I created transaction tx3, which transferred 0.01182790 bitcoin from the test address to my LocalBitcoins account.
- It included a Bitcoin network transaction fee of 2210 satoshi.
- LocalBitcoins charged a deposit fee of 0.00015 BTC.
Costs:
- LocalBitcoins transaction fee: 0.00005000 bitcoin
- Bitcoin network transaction fee: 2210 satoshi (0.00002210 bitcoin)
- LocalBitcoins deposit fee: 0.00015000 bitcoin
Total cost in bitcoin:
(LocalBitcoins transaction fee) + (Bitcoin network transaction fee) + (LocalBitcoins deposit fee) =
0.00005000 + 0.00002210 + 0.00015000 =
0.00022210 bitcoin
Total cost (USD):
0.00022210 bitcoin * (4212 USD / BTC) =
0.00022210 * (4212) ~=
$0.94
Overall cost of the project
Overall cost in bitcoin:
(Cost of testing the test address) + (Cost of storing a larger amount of bitcoin in the test address) =
0.00034586 bitcoin + 0.00022210 bitcoin = 0.00034586 + 0.00022210 =
0.00056796 bitcoin
Overall cost (USD):
(Cost of testing the test address) + (Cost of storing a larger amount of bitcoin in the test address) =
$1.70 + $0.94 = 1.70 + 0.94 =
$2.64
Note the use of the relevant then-current exchange rates for each subsection of the project.
Further Work
I would like to be able to transfer only a portion of the bitcoin (rather than an whole unspent output) in an offline address to another address. In order to do this, I need to be able to create transactions with two outputs - I could then set a default change output (whose destination would be the original offline address), and send only a portion of the bitcoin to the other output. This requires expansion of the existing code and careful testing.
During this project, transaction sizes (in bytes) differed slightly depending on the source.
- I estimated that a nonstandard transaction with one P2PKH input and one P2SH output should be approximately 221 bytes. All transactions that I created in this project were of this type (tx1, tx1b, tx1c, tx3).
- According to my tests after creating the transactions, they were:
-- tx1 / tx1a: 225 bytes
-- tx1b: 226 bytes
-- tx1c: 226 bytes
-- tx3: 226 bytes
- Transaction sizes according to the service live.blockcypher.com:
-- tx1 / tx1a: 221 bytes
-- tx1b: 222 bytes
-- tx1c: 222 bytes
-- tx3: 222 bytes
Investigate why these discrepancies exist, giving priority to how the estimated size is calculated. I derived the current estimate by adding up the sizes of the transaction component parts while developing the code for creating transactions.
Project Log
My work computer: Aineko, a 2008 Macbook running Mac OS X 10.6.8 Snow Leopard.
aineko:work stjohnpiano$ python --version
Python 2.7.13
I have a Raspberry Pi in my equipment stores. There is some white text on its surface, which states that it is a Model B+ V1.2 and is copyright Raspberry Pi 2014.
I have used this Raspberry Pi in other projects, and it has been connected to the Internet before, so I would not use it to store bitcoin permanently. I can still use it for a test project, though.
It has various ports, including 4 USB ports (which allows simultaneous use of a mouse, a keyboard, and a memory stick) and an HDMI port.
From previous experience, I recall that it does not have an onboard WiFi chip (instead, various suppliers sell add-on USB-connected WiFi chips that can be plugged into it).
I have various peripherals for the Raspberry Pi. These are: An 8GB micro SD card with an installed operating system, a Raspberry Pi power cable, a screen with a DVI port, a screen power cable, a DVI male-male connector cable, a DVI female to HDMI male converter, a USB keyboard, a USB mouse, and a plastic case customised for the Raspberry Pi Model B+.
Future: When I have booted up the Raspberry Pi, check which operating system is installed (I installed it a long time ago and don't recall which OS it was).
I also have a memory stick, which I will use to transfer code to the Raspberry Pi. Using a memory stick is not the most secure way to do this (various malware items have been able to store themselves on memory sticks). However, for storing bitcoin, using an offline computer and a memory stick is more secure than using an online computer, and security is always relative.
Notes:
- Ideally, the memory stick should only be used once to transfer all the code to the offline computer. Then, the memory stick should be destroyed, and any data produced on the offline computer should be manually copied to an online computer. See this article for an example of how to do this: Displaying hex bytes for manual copying
- In the limit case, code should only be moved onto an offline computer by manually typing it all in.
- In practice, steadily increasing security, as and when it is reasonable and affordable to do so, is usually the most effective strategy.
Create a project directory:
storing_bitcoin_on_an_offline_raspberry_pi
In the project directory, create a work directory:
work
Plan of action:
- Download necessary code from previous articles.
- Create a private key. Store it on the Raspberry Pi. This will require generating entropy.
- Generate a Bitcoin address from the private key.
- Test this address by transferring some bitcoin into and out of it.
- Store a larger amount of bitcoin in the address.
- The private key will of course be revealed in the article describing this project, so this bitcoin won't be stored permanently in this address. Instead, I'll transfer the bitcoin out again. To store some bitcoin, a reader can follow all the steps apart from this one.
Hm. The articles that I will need to use are:
- Recipe for generating entropy bytes using dice
- Recipe for generating a Bitcoin address
- Recipe for creating and signing a standard Bitcoin transaction
- Recipe for creating and signing a nonstandard Bitcoin transaction
- Displaying hex bytes for manual copying
Ok. Next, I will download all the assets linked from these articles. Browse to each article and download all linked assets.
Note: Some assets are linked from more than one of these articles.
List of downloaded assets:
- bitcoin_functions.py
- bjorn_edstrom_ripemd160.py
- convert_dice_rolls_to_hex_bytes_2.py
- create_nonstandard_transaction.py
- create_transaction.py
- display_hex_bytes.py
- ecdsa-0.10.tar.gz
- generate_bitcoin_address_3.py
- nonstandard_bitcoin_functions.py
- nonstandard_transaction.py
- pypy_sha256.py
- transaction.py
Move these assets into the work directory.
The work directory contains only these assets. Mac Finder / Get Info reports:
197 KB on disk (169,268 bytes) for 12 items
Future: I remember that Python is installed on the Raspberry Pi. Which version(s) are installed?
I have a USB memory stick (8 GB, FAT32 format, name = "NO NAME"). Insert it into Aineko. It mounts automatically and an icon appears on the Desktop.
Copy work directory to memory stick. Right-click Desktop icon and choose Eject "NO NAME". Unplug the memory stick from Aineko.
Connect the mouse, keyboard, and screen to the Raspberry Pi. The mouse is for opening a terminal emulator program if the Raspberry Pi boots directly into a graphical user interface.
Insert the power cable into the Raspberry Pi. It boots up.
Result:
raspberrypi login:
Enter default credentials:
raspberrypi login: pi
Password:
Last login: Sun Mar 27 17:11:27 UTC 2016 on tty1
Linux raspberrypi 4.1.13+ #826 PREEMPT Fri Nov 13 20:13:22 GMT 2015 armv61
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pi@raspberrypi ~ $
The password was "raspberry" but this was not echoed to the screen.
Ah. Note: The installed OS is Debian GNU/Linux. It's probably Raspbian.
In a previous project, I learned how to execute a command in the bash shell and simultaneously archive its output in a text file.
The project: Offline installation of a C compiler on Centos 6.9 Minimal on Kalkin
Excerpt:
6) RECORDING SHELL OUTPUT
Use theteecommand.
Example:
program [arguments...] 2>&1 | tee -a outfile
This should display both output and error messages and append these to a storage file.
The -a option means "append".
2>&1can be used in Bash to redirect errors/warnings (which are normally sent to stderr) to normal output (stdout). In this case both will be piped to the next command (tee).
Note:teedoesn't record the command itself, only the output. This can be worked around by echoing the command to the log file before running it. Use the-eflag for theechocommand so that it will interpret backslash-escaped newline characters.
[root@kalkin work]# echo -e "\n\nCOMMAND# rpm --version\n" | tee -a work.log
[root@kalkin work]# rpm --version | tee -a work.log
[root@kalkin work]# echo -e "\n\nCOMMAND# rpm --help\n" | tee -a work.log
[root@kalkin work]# rpm --help | tee -a work.log
Example of capturing output sent to standard error:
# rpm --install rpms/cloog-ppl-0.15.7-1.2.el6.x86_64.rpm --test 2>&1 | tee -a work.log
Running the command
tee --version
on the Raspberry Pi shows me that it is present. I will use the approaches shown in the excerpt to log the work done on the Raspberry Pi. I won't record the logging commands themselves in this project. Some commands for gathering information (e.g.
ls -1
,
cat [filename]
) may not be logged. Ok. Next: Insert the memory stick into the Raspberry Pi and mount it.
I did this before in the project How I bought and stored some bitcoin [paywalled].
Excerpt:
Steps for manually mounting a flash drive on a Raspberry Pi:
Insert the USB flash drive into a USB port on the Raspberry Pi.
Note: If the Raspberry Pi automatically started the graphical user interface, then open the program LXTerminal, which is a terminal emulator. It can be accessed from the Desktop via Menu / Accessories / Terminal. On my Raspbian system I have LXTerminal version 0.1.11.
In the terminal, enter the following commands, which are prefixed with a dollar sign and a space ($ ). Do not include this prefix when typing a command into the terminal.
Make a new directory on the graphical desktop to hold the contents of the flash drive:
$ mkdir /home/pi/Desktop/flash_drive_contents
Make a new directory to be the mount point for the flash drive:
$ sudo mkdir /mnt/flash_drive_mount_point
Mount the flash drive:
$ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/flash_drive_mount_point
Note that:
-o (lowercase letter "o", not the number zero) specifies that an option string follows.
uid=pi,gid=pi specifies that the user ID is "pi" and the group ID is "pi" (note there are no spaces allowed between these two terms).
/dev/sda1 is the first partition on the first USB drive that the Raspberry Pi can detect.
Copy the contents of the flash drive to the flash_drive_contents directory on the Desktop:
$ cp -r /mnt/flash_drive_mount_point/* /home/pi/Desktop/flash_drive_contents
Unmount the flash drive:
$ sudo umount /mnt/flash_drive_mount_point
The flash drive can now be unplugged.
Ok. Move to the Raspberry Pi. Insert the memory stick.
pi@raspberrypi ~ $ pwd
/home/pi
pi@raspberrypi ~ $ ls -1
Desktop
Documents
Downloads
indiecity
python_game
Scratch
pi@raspberrypi ~ $ mkdir test
pi@raspberrypi ~ $ cd test
pi@raspberrypi ~/test $ ls -1 /dev/sda*
/dev/sda
/dev/sda1
pi@raspberrypi ~/test $ touch work.log
pi@raspberrypi ~/test $ ls -1
work.log
Now log the work and copy it here. Logged commands are run in the
~/test
directory. While logging, record any annotations or comments here and integrate them into the log when the log has been transferred back from the Raspberry Pi to Aineko (where this article is being written).
pi@raspberrypi ~/test $ tee --version
tee (GNU coreutils) 8.13
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Parker, Richard M. Stallman, and David MacKenzie.
[make a new directory to hold a copy of the contents of the memory stick]
pi@raspberrypi ~/test $ mkdir memory_stick_contents
[make a new directory to be the mount point for the memory stick]
pi@raspberrypi ~/test $ sudo mkdir /mnt/memory_stick_mount_point
pi@raspberrypi ~/test $ ls -1 /mnt
drive1
memory_stick_mount_point
[mount the memory stick]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
$RECYCLE.BIN
Recycled
System Volume Information
work
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point/work
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
display_hex_bytes.py
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
pypy_sha256.py
transaction.py
[copy the contents of the memory stick to the memory_stick_contents directory]
pi@raspberrypi ~/test $ cp -r /mnt/memory_stick_mount_point/work/* memory_stick_contents
pi@raspberrypi ~/test $ ls -1 memory_stick_contents
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
display_hex_bytes.py
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
pypy_sha256.py
transaction.py
[check the OS version details]
pi@raspberrypi ~/test $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 7 (wheezy)"
NAME="Raspbian GNU/Linux"
VERSION_ID="7"
VERSION="7 (wheezy)"
ID=raspbian
ID_LIKE=debian
ANSI_COLOR="1;31"
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
[check the kernel version]
pi@raspberrypi ~/test $ uname -r
4.1.13+
pi@raspberrypi ~/test $ nano --version
[Next: Create a Bitcoin private key, which is 32 bytes long.]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
[how to use the Nano text editor is not specified here]
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls.txt.
Time this using a stopwatch.
Time taken: 10:30.
Approximately 11 minutes.
]
pi@raspberrypi ~/test $ nano dice_rolls.txt
pi@raspberrypi ~/test $ ls -1
dice_rolls.txt
memory_stick_contents
work.log
pi@raspberrypi ~/test $ cat dice_rolls.txt
41223
26165
34316
52546
25334
25225
46332
63516
25465
15244
64526
46346
64443
54222
21236
42122
56626
66121
34113
53616
26466
61546
55451
11642
64351
41236
14241
55242
52546
56336
14322
45444
46556
22443
35464
11626
16466
13562
14265
56141
63666
31416
16
pi@raspberrypi ~/test $ cp memory_stick_contents/convert_dice_rolls_to_hex_bytes_2.py convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ ls -1
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
memory_stick_contents
work.log
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
[
Also, in general, use Nano to remove any mistaken commands from work.log (if they didn't cause irreversible changes of some kind), so that the command can be run again properly. In some cases (e.g. where the command involves a newline), some manual editing of the log may be necessary.
Use
]
[
What are the Python version(s)?
python --version | tee -a work.log
and
python3 --version | tee -a work.log
don't work. no output recorded in work.log.
record them manually here:
]
pi@raspberrypi ~/test $ python --version
Python 2.7.3
pi@raspberrypi ~/test $ python3 --version
Python 3.2.3
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 132
- number of hex characters after conversion: 66
- number of hex bytes: 33
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca30
- hex byte output shortened to the desired length (32 bytes):
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- remaining hex bytes:
30
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Recommendation: Perhaps preserve the 1 extra hex bytes in an entropy storage file.
Extra hex bytes: 30
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[Let's extract the entropy from the log into its own file.]
[copy last 10 lines of work.log to a new file]
pi@raspberrypi ~/test $ tail -10 work.log > private_key.txt
[Use Nano to remove the text around the 32 entropy hex bytes. These 32 bytes will now be treated as the private key.]
pi@raspberrypi ~/test $ nano private_key.txt
pi@raspberrypi ~/test $ cat private_key.txt
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
[get string length of private_key hex bytes - should be 32*2 = 64. Use
pi@raspberrypi ~/test $ cat private_key.txt | tr -d '\n' | wc -c
64
[Next, generate a Bitcoin address from this private key.]
[I'm following the recipe Recipe for generating a Bitcoin address
]
pi@raspberrypi ~/test $ ls -1
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
memory_stick_contents
private_key.txt
work.log
pi@raspberrypi ~/test $ cp memory_stick_contents/bitcoin_functions.py bitcoin_functions.py
pi@raspberrypi ~/test $ cp memory_stick_contents/bjorn_edstrom_ripemd160.py bjorn_edstrom_ripemd160.py
pi@raspberrypi ~/test $ cp memory_stick_contents/ecdsa-0.10.tar.gz ecdsa-0.10.tar.gz
pi@raspberrypi ~/test $ cp memory_stick_contents/pypy_sha256.py pypy_sha256.py
pi@raspberrypi ~/test $ cp memory_stick_contents/generate_bitcoin_address_3.py generate_bitcoin_address_3.py
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
private_key.txt
pypy_sha256.py
work.log
[Unpack the zipped tape archive file ecdsa-0.10.tar.gz.]
pi@raspberrypi ~/test $ tar -zxvf ecdsa-0.10.tar.gz
ecdsa-0.10/
ecdsa-0.10/ecdsa/
ecdsa-0.10/ecdsa/__init__.py
ecdsa-0.10/ecdsa/_version.py
ecdsa-0.10/ecdsa/curves.py
ecdsa-0.10/ecdsa/der.py
ecdsa-0.10/ecdsa/ecdsa.py
ecdsa-0.10/ecdsa/ellipticcurve.py
ecdsa-0.10/ecdsa/keys.py
ecdsa-0.10/ecdsa/numbertheory.py
ecdsa-0.10/ecdsa/rfc6979.py
ecdsa-0.10/ecdsa/six.py
ecdsa-0.10/ecdsa/test_pyecdsa.py
ecdsa-0.10/ecdsa/util.py
ecdsa-0.10/LICENSE
ecdsa-0.10/MANIFEST.in
ecdsa-0.10/NEWS
ecdsa-0.10/PKG-INFO
ecdsa-0.10/README.md
ecdsa-0.10/setup.py
pi@raspberrypi ~/test $ ls -1 ecdsa-0.10
ecdsa
LICENSE
MANIFEST.in
NEWS
PKG-INFO
README.md
setup.py
[Copy the "ecdsa" directory into the work directory.]
pi@raspberrypi ~/test $ cp -r ecdsa-0.10/ecdsa ecdsa
[
Use the Nano editor to edit the controls in generate_bitcoin_address_3.py, according to the recipe.
- Delete the existing value for the variable
]
pi@raspberrypi ~/test $ nano generate_bitcoin_address.py
pi@raspberrypi ~/test $ python generate_bitcoin_address_3.py
### START GENERATION OF BITCOIN ADDRESS
Private key (hex bytes): c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Private key (32 hex bytes): c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Private key (WIF): 5KKJLZJVY7nZpGdSJcE6xwGf6WTD4m5Zjr7mFZh8dvQBaRFyHZf
Bitcoin address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
### END GENERATION OF BITCOIN ADDRESS
[The python generate_bitcoin_address_3.py command took a few seconds.]
[Recipe complete.]
tee (GNU coreutils) 8.13
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Parker, Richard M. Stallman, and David MacKenzie.
[make a new directory to hold a copy of the contents of the memory stick]
pi@raspberrypi ~/test $ mkdir memory_stick_contents
[make a new directory to be the mount point for the memory stick]
pi@raspberrypi ~/test $ sudo mkdir /mnt/memory_stick_mount_point
pi@raspberrypi ~/test $ ls -1 /mnt
drive1
memory_stick_mount_point
[mount the memory stick]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
$RECYCLE.BIN
Recycled
System Volume Information
work
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point/work
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
display_hex_bytes.py
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
pypy_sha256.py
transaction.py
[copy the contents of the memory stick to the memory_stick_contents directory]
pi@raspberrypi ~/test $ cp -r /mnt/memory_stick_mount_point/work/* memory_stick_contents
pi@raspberrypi ~/test $ ls -1 memory_stick_contents
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
create_transaction.py
display_hex_bytes.py
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
pypy_sha256.py
transaction.py
[check the OS version details]
pi@raspberrypi ~/test $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 7 (wheezy)"
NAME="Raspbian GNU/Linux"
VERSION_ID="7"
VERSION="7 (wheezy)"
ID=raspbian
ID_LIKE=debian
ANSI_COLOR="1;31"
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
[check the kernel version]
pi@raspberrypi ~/test $ uname -r
4.1.13+
pi@raspberrypi ~/test $ nano --version
GNU nano version 2.2.6 (compiled 16:52:03, Mar 30 2012)
(C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2009 Free Software Foundation, Inc.
Email: nano@nano-editor.org Web: http://www.nano-editor.org/
Compiled options: --disable-wrapping-as-root --enable-color --enable-extra --enable-multibuffer --enable-nanorc --enable-utf8
[Next: Create a Bitcoin private key, which is 32 bytes long.]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
[how to use the Nano text editor is not specified here]
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls.txt.
Time this using a stopwatch.
Time taken: 10:30.
Approximately 11 minutes.
]
pi@raspberrypi ~/test $ nano dice_rolls.txt
pi@raspberrypi ~/test $ ls -1
dice_rolls.txt
memory_stick_contents
work.log
pi@raspberrypi ~/test $ cat dice_rolls.txt
41223
26165
34316
52546
25334
25225
46332
63516
25465
15244
64526
46346
64443
54222
21236
42122
56626
66121
34113
53616
26466
61546
55451
11642
64351
41236
14241
55242
52546
56336
14322
45444
46556
22443
35464
11626
16466
13562
14265
56141
63666
31416
16
pi@raspberrypi ~/test $ cp memory_stick_contents/convert_dice_rolls_to_hex_bytes_2.py convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ ls -1
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
memory_stick_contents
work.log
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
[
Also, in general, use Nano to remove any mistaken commands from work.log (if they didn't cause irreversible changes of some kind), so that the command can be run again properly. In some cases (e.g. where the command involves a newline), some manual editing of the log may be necessary.
Use
cat work.log
after each command to confirm that its output was recorded as expected.]
[
What are the Python version(s)?
python --version | tee -a work.log
and
python3 --version | tee -a work.log
don't work. no output recorded in work.log.
record them manually here:
]
pi@raspberrypi ~/test $ python --version
Python 2.7.3
pi@raspberrypi ~/test $ python3 --version
Python 3.2.3
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 132
- number of hex characters after conversion: 66
- number of hex bytes: 33
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca30
- hex byte output shortened to the desired length (32 bytes):
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- remaining hex bytes:
30
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Recommendation: Perhaps preserve the 1 extra hex bytes in an entropy storage file.
Extra hex bytes: 30
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[Let's extract the entropy from the log into its own file.]
[copy last 10 lines of work.log to a new file]
pi@raspberrypi ~/test $ tail -10 work.log > private_key.txt
[Use Nano to remove the text around the 32 entropy hex bytes. These 32 bytes will now be treated as the private key.]
pi@raspberrypi ~/test $ nano private_key.txt
pi@raspberrypi ~/test $ cat private_key.txt
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
[get string length of private_key hex bytes - should be 32*2 = 64. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat private_key.txt | tr -d '\n' | wc -c
64
[Next, generate a Bitcoin address from this private key.]
[I'm following the recipe Recipe for generating a Bitcoin address
]
pi@raspberrypi ~/test $ ls -1
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
memory_stick_contents
private_key.txt
work.log
pi@raspberrypi ~/test $ cp memory_stick_contents/bitcoin_functions.py bitcoin_functions.py
pi@raspberrypi ~/test $ cp memory_stick_contents/bjorn_edstrom_ripemd160.py bjorn_edstrom_ripemd160.py
pi@raspberrypi ~/test $ cp memory_stick_contents/ecdsa-0.10.tar.gz ecdsa-0.10.tar.gz
pi@raspberrypi ~/test $ cp memory_stick_contents/pypy_sha256.py pypy_sha256.py
pi@raspberrypi ~/test $ cp memory_stick_contents/generate_bitcoin_address_3.py generate_bitcoin_address_3.py
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bjorn_edstrom_ripemd160.py
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
private_key.txt
pypy_sha256.py
work.log
[Unpack the zipped tape archive file ecdsa-0.10.tar.gz.]
pi@raspberrypi ~/test $ tar -zxvf ecdsa-0.10.tar.gz
ecdsa-0.10/
ecdsa-0.10/ecdsa/
ecdsa-0.10/ecdsa/__init__.py
ecdsa-0.10/ecdsa/_version.py
ecdsa-0.10/ecdsa/curves.py
ecdsa-0.10/ecdsa/der.py
ecdsa-0.10/ecdsa/ecdsa.py
ecdsa-0.10/ecdsa/ellipticcurve.py
ecdsa-0.10/ecdsa/keys.py
ecdsa-0.10/ecdsa/numbertheory.py
ecdsa-0.10/ecdsa/rfc6979.py
ecdsa-0.10/ecdsa/six.py
ecdsa-0.10/ecdsa/test_pyecdsa.py
ecdsa-0.10/ecdsa/util.py
ecdsa-0.10/LICENSE
ecdsa-0.10/MANIFEST.in
ecdsa-0.10/NEWS
ecdsa-0.10/PKG-INFO
ecdsa-0.10/README.md
ecdsa-0.10/setup.py
pi@raspberrypi ~/test $ ls -1 ecdsa-0.10
ecdsa
LICENSE
MANIFEST.in
NEWS
PKG-INFO
README.md
setup.py
[Copy the "ecdsa" directory into the work directory.]
pi@raspberrypi ~/test $ cp -r ecdsa-0.10/ecdsa ecdsa
[
Use the Nano editor to edit the controls in generate_bitcoin_address_3.py, according to the recipe.
- Delete the existing value for the variable
private_key_hex_bytes
. Then use the Nano option "Read File" to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.]
pi@raspberrypi ~/test $ nano generate_bitcoin_address.py
pi@raspberrypi ~/test $ python generate_bitcoin_address_3.py
### START GENERATION OF BITCOIN ADDRESS
Private key (hex bytes): c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Private key (32 hex bytes): c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Private key (WIF): 5KKJLZJVY7nZpGdSJcE6xwGf6WTD4m5Zjr7mFZh8dvQBaRFyHZf
Bitcoin address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
### END GENERATION OF BITCOIN ADDRESS
[The python generate_bitcoin_address_3.py command took a few seconds.]
[Recipe complete.]
Ok. Now copy work.log to the memory stick, then dismount the memory stick.
pi@raspberrypi ~/test $ cp work.log /mnt/memory_stick_mount_point
pi@raspberrypi ~/test $ sudo umount /mnt/memory_stick_mount_point
Unplug the memory stick from the Raspberry Pi.
Insert it into Aineko. It mounts automatically and an icon appears on the Desktop. Open the file work.log and copy its contents into this article (above this point). Merge any annotations and comments into this log, marking them with square brackets.
Done.
So: I have generated this address on an offline computer:
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
I'll call it the "test address".
On Aineko, right-click memory stick's Desktop icon and choose Eject "NO NAME". Unplug the memory stick from Aineko.
Next: Transfer some bitcoin to this address. Later, transfer it out. This will confirm that the address has been correctly derived from the private key.
First: Calculate how much bitcoin to send to the test address.
LocalBitcoins:
- Current deposit fee for incoming transactions: 0.00015 BTC
- Current transaction fee: 0.00005 BTC
Browse to:
bitcoinfees.earn.com
The fee rates are displayed in satoshi per byte of transaction data. A satoshi is 0.00000001 bitcoin.
Choose a high fee in order to have slack available. I'll attempt to use a low fee in the actual transaction.
A nonstandard transaction with one P2PKH input and one P2SH output should be approximately 221 bytes.
The fee rate range 1-2 satoshi / byte includes many transactions waiting for confirmation. Estimated delay = 3-66 blocks (35-840 minutes).
A fee rate of 60 satoshi / byte looks quite high. Estimated delay = 0 blocks (0-35 minutes).
I estimate that a fairly high fee will therefore be 221 bytes * 60 satoshi / byte = 221 * 60 = 13260 satoshi.
13260 satoshi * 1 BTC / 10^8 satoshi = 0.00013260 BTC
So, expected costs:
- LocalBitcoins transaction fee = 0.00005 BTC. This will be deducted from my LocalBitcoins wallet balance, not from the transction amount.
- Bitcoin network transaction fee (high-end) = 0.00013260 BTC.
- LocalBitcoins deposit fee = 0.00015 BTC.
I need to transfer at least this much to the test address:
(Bitcoin network transaction fee) + (LocalBitcoins deposit fee)
= 0.00013260 + 0.00015
= 0.00028260 BTC
This amount will need to cover the transaction costs of the second transaction (that will later transfer bitcoin out of the test address).
Current USD / BTC price:
$4904.99
(4904.99 USD / BTC) * 0.00028260 BTC = 4904.99 * 0.00028260 ~= $1.39
The number of transactions shown waiting for confirmation, especially at the lower fee ranges, is larger than I've usually seen.
I'll transfer $10-worth of bitcoin to the test address, so as to have room to manoeuvre. If the first version of the transaction is not mined, I will need to increase the fee, and upload a new version for broadcasting.
$10 * (1 BTC / 4904.99 USD) = 10 * 1 / 4904.99 ~= 0.00203874 BTC
I'll transfer 0.0020 bitcoin (~$9.8) into the test address.
Ok. Next:
Log in to LocalBitcoins. Transfer 0.0020 bitcoin to the test address:
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
Go to LocalBitcoins / Wallet / Transactions.
The transaction is listed. Message = "Pending send [etc]"
Wait for a while.
I'll call this transction "tx0" in this project.
Refresh the page.
In the latest entry (for the address
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK ),
the txid is shown:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Browse to:
live.blockcypher.com
Search for this txid.
Transaction page loads:
live.blockcypher.com/btc/tx/07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Confirmations: 3/6
Set timer for 40 minutes.
Timer has ended.
Refresh page.
Confirmations: 6+
Click "Advanced Details". Click "API Call".
Result: tx0
{
"block_hash": "0000000000000000001b43b8af8973377619def5043634e9cb2d7dd584d973be",
"block_height": 550741,
"block_index": 455,
"hash": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"hex": "0200000000010184cf2ed9386d5f3edb357e67540063d642a4f1340d77682c6c790d02ccfb4f121f00000017160014ac04ab49d76aeb07d4c49210f60047f640cb196dfeffffff202bcd22000000000017a914aa8f360859518dca87af02cd405c938a5962556f876d8809000000000017a914e3f53dbfc27efc20f5353ed75c5f56a2f4d22f9d87a35705000000000017a91415f9e71c57ae4682c2f69348f46af05e5d92d87087dc2a01000000000017a91452ee98be576a438d87a32f204c229b59d561796887c93a5db70000000017a91463226a9ea0a6d3c1c2722dd676b56356e14ec16887bd3e49000000000017a91463645845356338f13c2a0a1182c1849021e90f5b873a7204000000000017a914fe3859d20324dcad8094ded3867ee0d86e0e12e7870f7706000000000017a914fff7651a1190fd2d860e67c729ba45fa42411c1687618106000000000017a914b7bbaa02f1cf51b05ac667a042e3254f719a34ee87249703000000000017a914f617e48258c4c548665bf9b4de7a3e713db86ee087fb3749000000000017a914e5407a2219ffdb00505afdd828c1ba61ce6b317a875aad04000000000017a914870832203f94963208aead8869cd95e6075446fb878cbe09000000000017a9145504c5f7a8cb1ae9344cfa71646a59e5945e15d187664402000000000017a9144fa6ca9aa833a6219cb6b65b03e84be72042beab876cc90700000000001976a9149269fa94c59aa5054984a6aa36ab906edba3f36088ac400d0300000000001976a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac204e00000000000017a91482f1cf8e9cd1101c20feb549cd2848991ddadaf687685100000000000017a914c42cc570f52a69c9a5fcedf0a1856901aa615f3287c62705000000000017a914319d705ae9480eec4227f0d2bd4adae2ee0e43bb870e7706000000000017a9146c5e0be6a3654619893b01c0e180b74767825bff87184309000000000017a9144de4be7f547ee2c726020aefe4944111e78fd8608780b804000000000017a91462d5e9f939dcca60f43f2b797c860641c2b631aa8762a203000000000017a914ea900e3ea458c4d272257274fa47c32d63cdcd4e87aa3606010000000017a9146b7a98620bc938afa332e100ba9d543a07111daa87a14d10000000000017a914a39e1b5b69c62da1f1ea954a02f5ba9386790b59879afa0400000000001976a91410b77b5a69d4071174c2f480e619075217a83f2788ac904708000000000017a914482f1b3bffbc4c83b3e55c67e7f8add341bb5d908790e71400000000001976a91404a3fd24f45eb2a267a61ab7be2b2043c0f2474c88ac900709000000000017a91499288cbb13aa8a0528abf1999a86d04b17c6ddd687438e01000000000017a914bb22d3ad33802d5ff6fd218413dcbb81f78c3ec48770141507000000001976a914df56a67c8f312699b5114d0e1f8ba63aa0dae8ad88ac40390600000000001976a91459e196681a14c880ff4144cc23a45a14cfaaf0d288ac024830450221009c6f18d0bff51e20e52032f5cf13acc6c734b4a560dc483fc37795de8918b255022022e3cdae51e40d99225d05512e48c686444e79b46bf1c4002824148f7e39c8f7012102fc269453f121876200573e5c1a5b1ecd214064dc0c3f2d2967e4df65dde527163f670800",
"addresses": [
"3AjC3qLFG1KymcynTX5EcdNntD7cBEwN9b",
"3JSWPnAUigZ8uzxoY9FqM3zcEH6mBPPUGj",
"39SZ5WEEBeEgf7M3E4G2fXWrhbctpAKsYR",
"39nRG4yzSf7hgTN2UiFTETBD8Jwy9imeTb",
"3Gc9UGb8d9xiZzx8cWcoFJHidY4yyVTD5L",
"12XPccUSreQ9RwGQEAgeKGo7GdyLcNCokd",
"3JkW1EDxnuq84Q4us4ryvjJz4uqaFhda8y",
"36DMdzKb9WFnQECwPukHotC3z3xBo3FC6W",
"3DzzxttCG7M48Mmd6f6vcCaPWVb2VDaYbT",
"38nsyjcVsgnbyNkNx2seKxFqqWgP4cF6Ke",
"39FXAG2ytLBgtoqCNWWpPwPXevEkffwKBS",
"3Ba1Zj4TeS2sRFm7WDd1xrwRxNqYzMXtPK",
"3AhcQLznoPapj1LShqrkXtWg4kBt21MNR5",
"3BVK68suAqQ52T5UDSytGnEJW5tPMXc13x",
"3NbBuRGMinhcCPsoecMwKphT9BMA4yp6BE",
"3FeqtLafmwNfWDhcwmvzTwweJPNEVDXSq4",
"1MMuVMFnq7dCyxitnHdAFoDcdiwXKgdujx",
"38Gh1N6SQzxQ5o59QFuzh56x3tc5aZ4KnD",
"3R2Sbm82wwTPXhLY9E64CaVgVsKYLFvGA5",
"3Q8EmpdKDtVZmTTrfhBD17K6ZQDLUASCs3",
"38xB7ZzDnAFEyz3hs8cDt1vQxKHZsWu26V",
"3DdPSngv2ssAZAgA9ePPNef7m9cHX3HfWT",
"3KaHzuNmL4QjpzizHExtPtW7TEAZyoCAND",
"19CFPAoWLzUi9rcJ4hnSD5mwJ4xPDWnCpQ",
"3QsD4bUGFUt4Ty48Ni4JxYshheTdwnhZKB",
"3NUM6kHP7ZLzm2fhHnyrWpa1jCAmrZAY1S",
"3AkZ2capQd2GZr3KfMG5guszvzHcVXaD8z",
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"3HErMdjZR9No28jRUiHwBYRLfC4gVqEaaU",
"1EMAcYeU5VNJDAzsLVRRWUp595YZczq9PE",
"3P5GcbPGfkdwT62NLhmBfmiBtS8HJKfV3f",
"1RY9uu5pebzP2BYMBdBjZDJMrXdiQGmYP",
"33hDV7zwRhcgdJmyTWbJFLRMEawYweCNLi"
],
"total": 3234824252,
"fees": 70068,
"size": 1110,
"preference": "high",
"confirmed": "2018-11-19T19:46:37Z",
"received": "2018-11-19T19:46:37Z",
"ver": 2,
"lock_time": 550719,
"double_spend": false,
"vin_sz": 1,
"vout_sz": 32,
"confirmations": 7,
"confidence": 1,
"inputs": [
{
"prev_hash": "124ffbcc020d796c2c68770d34f1a442d6630054677e35db3e5f6d38d92ecf84",
"output_index": 31,
"script": "160014ac04ab49d76aeb07d4c49210f60047f640cb196d",
"output_value": 3234894320,
"sequence": 4294967294,
"addresses": [
"39nRG4yzSf7hgTN2UiFTETBD8Jwy9imeTb"
],
"script_type": "pay-to-script-hash",
"age": 550741,
"witness": [
"30450221009c6f18d0bff51e20e52032f5cf13acc6c734b4a560dc483fc37795de8918b255022022e3cdae51e40d99225d05512e48c686444e79b46bf1c4002824148f7e39c8f701",
"02fc269453f121876200573e5c1a5b1ecd214064dc0c3f2d2967e4df65dde52716"
]
}
],
"outputs": [
{
"value": 2280747,
"script": "a914aa8f360859518dca87af02cd405c938a5962556f87",
"addresses": [
"3HErMdjZR9No28jRUiHwBYRLfC4gVqEaaU"
],
"script_type": "pay-to-script-hash"
},
{
"value": 624749,
"script": "a914e3f53dbfc27efc20f5353ed75c5f56a2f4d22f9d87",
"spent_by": "b69db5fc5af41b17c4c521e95cefd6f19d095bf1856d4219c071251cec723ce6",
"addresses": [
"3NUM6kHP7ZLzm2fhHnyrWpa1jCAmrZAY1S"
],
"script_type": "pay-to-script-hash"
},
{
"value": 350115,
"script": "a91415f9e71c57ae4682c2f69348f46af05e5d92d87087",
"addresses": [
"33hDV7zwRhcgdJmyTWbJFLRMEawYweCNLi"
],
"script_type": "pay-to-script-hash"
},
{
"value": 76508,
"script": "a91452ee98be576a438d87a32f204c229b59d561796887",
"spent_by": "8727eed4e1e629261ada96547b9abcef0d09b98919d04b89a52c68082013d860",
"addresses": [
"39FXAG2ytLBgtoqCNWWpPwPXevEkffwKBS"
],
"script_type": "pay-to-script-hash"
},
{
"value": 3076340425,
"script": "a91463226a9ea0a6d3c1c2722dd676b56356e14ec16887",
"spent_by": "97d499163bf5d78eec5c7c6c4014910a198b5f53b190003dc52396d5d9dfd065",
"addresses": [
"3AjC3qLFG1KymcynTX5EcdNntD7cBEwN9b"
],
"script_type": "pay-to-script-hash"
},
{
"value": 4800189,
"script": "a91463645845356338f13c2a0a1182c1849021e90f5b87",
"addresses": [
"3AkZ2capQd2GZr3KfMG5guszvzHcVXaD8z"
],
"script_type": "pay-to-script-hash"
},
{
"value": 291386,
"script": "a914fe3859d20324dcad8094ded3867ee0d86e0e12e787",
"spent_by": "5e2a287d6ddd2ef615c1481bdfaaf579fd54ddca8b3b022c5fe399c845a2463a",
"addresses": [
"3QsD4bUGFUt4Ty48Ni4JxYshheTdwnhZKB"
],
"script_type": "pay-to-script-hash"
},
{
"value": 423695,
"script": "a914fff7651a1190fd2d860e67c729ba45fa42411c1687",
"addresses": [
"3R2Sbm82wwTPXhLY9E64CaVgVsKYLFvGA5"
],
"script_type": "pay-to-script-hash"
},
{
"value": 426337,
"script": "a914b7bbaa02f1cf51b05ac667a042e3254f719a34ee87",
"addresses": [
"3JSWPnAUigZ8uzxoY9FqM3zcEH6mBPPUGj"
],
"script_type": "pay-to-script-hash"
},
{
"value": 235300,
"script": "a914f617e48258c4c548665bf9b4de7a3e713db86ee087",
"addresses": [
"3Q8EmpdKDtVZmTTrfhBD17K6ZQDLUASCs3"
],
"script_type": "pay-to-script-hash"
},
{
"value": 4798459,
"script": "a914e5407a2219ffdb00505afdd828c1ba61ce6b317a87",
"addresses": [
"3NbBuRGMinhcCPsoecMwKphT9BMA4yp6BE"
],
"script_type": "pay-to-script-hash"
},
{
"value": 306522,
"script": "a914870832203f94963208aead8869cd95e6075446fb87",
"spent_by": "1c2d2ed3714fa9928686297aba600fddc9197b59a5a24be8c7969ac6c344f854",
"addresses": [
"3DzzxttCG7M48Mmd6f6vcCaPWVb2VDaYbT"
],
"script_type": "pay-to-script-hash"
},
{
"value": 638604,
"script": "a9145504c5f7a8cb1ae9344cfa71646a59e5945e15d187",
"spent_by": "0c9fa5c06526270f7205c217f06a6df7effd00f3b35a369e2cac713854735e04",
"addresses": [
"39SZ5WEEBeEgf7M3E4G2fXWrhbctpAKsYR"
],
"script_type": "pay-to-script-hash"
},
{
"value": 148582,
"script": "a9144fa6ca9aa833a6219cb6b65b03e84be72042beab87",
"spent_by": "fa7f13662269af17f9ae2ee938e718ec44d0d2c8ef037429b3f83a7a87e0bffa",
"addresses": [
"38xB7ZzDnAFEyz3hs8cDt1vQxKHZsWu26V"
],
"script_type": "pay-to-script-hash"
},
{
"value": 510316,
"script": "76a9149269fa94c59aa5054984a6aa36ab906edba3f36088ac",
"spent_by": "05e10942209f7254cbb989e1ce3976d5bc7e0b6259ec0b8726407991a32bdaad",
"addresses": [
"1EMAcYeU5VNJDAzsLVRRWUp595YZczq9PE"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 200000,
"script": "76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac",
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 20000,
"script": "a91482f1cf8e9cd1101c20feb549cd2848991ddadaf687",
"addresses": [
"3DdPSngv2ssAZAgA9ePPNef7m9cHX3HfWT"
],
"script_type": "pay-to-script-hash"
},
{
"value": 20840,
"script": "a914c42cc570f52a69c9a5fcedf0a1856901aa615f3287",
"addresses": [
"3KaHzuNmL4QjpzizHExtPtW7TEAZyoCAND"
],
"script_type": "pay-to-script-hash"
},
{
"value": 337862,
"script": "a914319d705ae9480eec4227f0d2bd4adae2ee0e43bb87",
"addresses": [
"36DMdzKb9WFnQECwPukHotC3z3xBo3FC6W"
],
"script_type": "pay-to-script-hash"
},
{
"value": 423694,
"script": "a9146c5e0be6a3654619893b01c0e180b74767825bff87",
"addresses": [
"3Ba1Zj4TeS2sRFm7WDd1xrwRxNqYzMXtPK"
],
"script_type": "pay-to-script-hash"
},
{
"value": 607000,
"script": "a9144de4be7f547ee2c726020aefe4944111e78fd86087",
"spent_by": "abfc5481eccc8b04a866530e8e520194270d06237de56513ab87975054dd9f87",
"addresses": [
"38nsyjcVsgnbyNkNx2seKxFqqWgP4cF6Ke"
],
"script_type": "pay-to-script-hash"
},
{
"value": 309376,
"script": "a91462d5e9f939dcca60f43f2b797c860641c2b631aa87",
"addresses": [
"3AhcQLznoPapj1LShqrkXtWg4kBt21MNR5"
],
"script_type": "pay-to-script-hash"
},
{
"value": 238178,
"script": "a914ea900e3ea458c4d272257274fa47c32d63cdcd4e87",
"addresses": [
"3P5GcbPGfkdwT62NLhmBfmiBtS8HJKfV3f"
],
"script_type": "pay-to-script-hash"
},
{
"value": 17184426,
"script": "a9146b7a98620bc938afa332e100ba9d543a07111daa87",
"addresses": [
"3BVK68suAqQ52T5UDSytGnEJW5tPMXc13x"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1068449,
"script": "a914a39e1b5b69c62da1f1ea954a02f5ba9386790b5987",
"spent_by": "07e826035301cc9c3ad07819b0bac9c47b887c2a704ac1cdde137d438d2a8354",
"addresses": [
"3Gc9UGb8d9xiZzx8cWcoFJHidY4yyVTD5L"
],
"script_type": "pay-to-script-hash"
},
{
"value": 326298,
"script": "76a91410b77b5a69d4071174c2f480e619075217a83f2788ac",
"addresses": [
"12XPccUSreQ9RwGQEAgeKGo7GdyLcNCokd"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 542608,
"script": "a914482f1b3bffbc4c83b3e55c67e7f8add341bb5d9087",
"addresses": [
"38Gh1N6SQzxQ5o59QFuzh56x3tc5aZ4KnD"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1370000,
"script": "76a91404a3fd24f45eb2a267a61ab7be2b2043c0f2474c88ac",
"addresses": [
"1RY9uu5pebzP2BYMBdBjZDJMrXdiQGmYP"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 591760,
"script": "a91499288cbb13aa8a0528abf1999a86d04b17c6ddd687",
"spent_by": "abfc5481eccc8b04a866530e8e520194270d06237de56513ab87975054dd9f87",
"addresses": [
"3FeqtLafmwNfWDhcwmvzTwweJPNEVDXSq4"
],
"script_type": "pay-to-script-hash"
},
{
"value": 101955,
"script": "a914bb22d3ad33802d5ff6fd218413dcbb81f78c3ec487",
"addresses": [
"3JkW1EDxnuq84Q4us4ryvjJz4uqaFhda8y"
],
"script_type": "pay-to-script-hash"
},
{
"value": 118822000,
"script": "76a914df56a67c8f312699b5114d0e1f8ba63aa0dae8ad88ac",
"spent_by": "7416e66c3d4ad4d67a6c03a3018d28b62a3a915e336e5f9bb10da2255f1a1fba",
"addresses": [
"1MMuVMFnq7dCyxitnHdAFoDcdiwXKgdujx"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 407872,
"script": "76a91459e196681a14c880ff4144cc23a45a14cfaaf0d288ac",
"addresses": [
"19CFPAoWLzUi9rcJ4hnSD5mwJ4xPDWnCpQ"
],
"script_type": "pay-to-pubkey-hash"
}
]
}
Key details:
- block_hash:
0000000000000000001b43b8af8973377619def5043634e9cb2d7dd584d973be
- block_height: 550741
- confirmed: 2018-11-19T19:46:37Z
- received: 2018-11-19T19:46:37Z
- txid:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
- vout_sz (number of outputs): 32
Shutting down for the day.
On the Raspberry Pi:
pi@raspberrypi ~/test $ sudo halt
[a variety of output is printed, then the Raspberry Pi shuts down]
To boot the Raspberry Pi up again, unplug the power cable and plug it in again.
Start work again.
Next: Create a transaction that moves the available bitcoin out of the test address. I'll call this "tx1".
I'll transfer it back to my LocalBitcoins account, which will have a nonstandard P2SH address. I will therefore follow this article:
Recipe for creating and signing a nonstandard Bitcoin transaction
Note: If I had decided to transfer the bitcoin to a standard P2PKH address, I would have followed this article:
Recipe for creating and signing a standard Bitcoin transaction
Several points concerning Bitcoin transactions:
- New transactions spend unspent-outputs-of-previous-transactions.
- The bitcoin balance of an address is the sum of the unspent outputs sent by previous transactions to this address.
- To spend bitcoin from an address, the bitcoin amount must be constructed from complete unspent outputs. Any change can be sent in a new unspent output back to the original address or another that you control. Unspent outputs cannot be broken into smaller unspent outputs prior to spending - new unspent outputs (larger or smaller) must be created by a new transaction.
The recipe requires me to gather certain pieces of information.
Let's proceed.
- The txid of the previous transaction (tx0, which transferred the unspent output to the test address) is:
07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
- The index of this unspent output in the previous transaction (the "previous_output_index"):
15
[I found the previous_output_index by searching the raw form of tx0 (included earlier in this article) for the test address, temporarily marking the output that contained it, then counting manually (starting from 0) from the first output until I reached the output containing the test address.]
- The private key (in hex bytes) of the test address is:
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
Note: This is stored on the Raspberry Pi in the file private_key.txt.
- The "input amount" == The bitcoin amount (or satoshi amount) contained within the unspent output:
0.002 bitcoin
- I need a 32-byte random value, to be used when signing the transaction tx1 with the input (each input must sign the transaction).
-- Hm. I'll leave this for now. I will generate 32 bytes of entropy later, when I'm working again on the Raspberry Pi.
-- Note: The random value must also be kept secret, and never exist, however temporarily on an online computer.
The recipe requires me to choose certain pieces of information.
- The output address (which must be a nonstandard P2SH address) is:
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
[This is the current receiving address on my LocalBitcoins account. It starts with the character '3', so I know it's a P2SH address.]
- The "output amount" == The bitcoin amount (or satoshi amount) that I wish to transfer to the output address:
0.002 bitcoin
[Note: This should be equal to the input amount (the code does not have the ability to send change). Any unassigned value will still be sent to the single output address (which in this recipe is the same as the change address).]
- The change address.
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
[Note: In this recipe, the change address must be the same as the single output address.]
- The fee (in satoshi) or fee_rate (in satoshi / byte):
fee_rate = 1 satoshi / byte
This is the lowest end of the fee ranges I looked at earlier.
If the transaction is not mined within 3 days, I'll increase the fee, re-sign it, and broadcast the new version (which will invalidate the older version, because it will spend the same unspent output).
Note: Each new signature requires a new random value. Using the same random value twice in two different signatures could compromise the secrecy of the private key.
I'll switch to the Raspberry Pi.
When I need the information gathered / chosen above, I'll copy it manually into the Raspberry Pi, reading it from Aineko's screen.
Insert the power cable into the Raspberry Pi.
Enter default credentials:
raspberrypi login: pi
Password:
Last login: Sun Mar 27 18:28:14 UTC 2016 on tty1
Linux raspberrypi 4.1.13+ #826 PREEMPT Fri Nov 13 20:13:22 GMT 2015 armv61
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pi@raspberrypi ~ $
The password was "raspberry" but this was not echoed to the screen.
pi@raspberrypi ~ $ pwd
/home/pi
pi@raspberrypi ~ $ ls -1
Desktop
Documents
Downloads
indiecity
python_game
Scratch
test
pi@raspberrypi ~ $ cd test
pi@raspberrypi ~/test $ touch work_log2.txt
I'll begin logging in the new file called "work_log2.txt". Eventually, I'll transfer it via memory stick to Aineko.
Logged commands are run in the
~/test
directory on the Raspberry Pi. While logging, record any annotations or comments here and integrate them into the log when the log has been transferred back from the Raspberry Pi to Aineko (where this article is being written).
[Begin logging on Raspberry Pi.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
work.log
work_log2.txt
[first, generate 32 bytes of entropy to use as the random value for making the transaction signature]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ nano dice_rolls2.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls2.txt.
Time this using a stopwatch.
Time taken: 7:32.
Approximately 8 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 146
- number of hex characters after conversion: 73
- there is one extra hex character that can't be used to form an entire 8-bit byte.
- number of hex bytes: 36
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e279d9258
- hex byte output shortened to the desired length (32 bytes):
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
- remaining hex bytes:
279d9258
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
Recommendation: Perhaps preserve the 4 extra hex bytes in an entropy storage file.
Extra hex bytes: 279d9258
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[Let's extract the entropy from the log into its own file.]
[copy last 15 lines of work_log2.txt to a new file]
pi@raspberrypi ~/test $ tail -15 work_log2.txt > random_value.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value.]
pi@raspberrypi ~/test $ nano random_value.txt
[get string length of random_value.txt hex bytes - should be 32*2 = 64. Use
pi@raspberrypi ~/test $ cat random_value.txt | tr -d '\n' | wc -c
64
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls2.txt
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[Copy needed files from memory_stick_contents to test directory.]
pi@raspberrypi ~/test $ cp memory_stick_contents/create_nonstandard_transaction.py create_nonstandard_transaction.py
pi@raspberrypi ~/test $ cp memory_stick_contents/nonstandard_bitcoin_functions.py nonstandard_bitcoin_functions.py
pi@raspberrypi ~/test $ cp memory_stick_contents/nonstandard_transaction.py nonstandard_transaction.py
pi@raspberrypi ~/test $ cp memory_stick_contents/transaction.py transaction.py
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
transaction.py
work.log
work_log2.txt
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values (reading them from this article displayed on Aineko's screen), except for the variables
- Delete the existing value for the variable
- The variable
Note: With long strings, e.g. the txid, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again to form the original txid.
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy the excerpt lines 40-66 to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 1.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- Amount to be sent to the change address: 0.0020
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.00200000
- Output addresses, with total-value-to-be-received:
-- 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH: 0.00200000
- Total value of all inputs: 0.00200000
- Total value of all outputs: 0.00200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 1.0 (satoshi / byte)
- Calculate 221 * 1.0 and round up to nearest satoshi.
- Final fee: 221 (satoshi)
- Final fee rate (using estimated transaction size): 1.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 199779 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
- previous_output_index: 0f000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 15
- txid: 07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Output 0:
Output:
- value: 630c030000000000
- script_length: 17
- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- bitcoin_amount: 0.00199779
- satoshi_amount: 199779
- redeem_script_hash_hex: 30d540a50d464852194a195529ebfa44af521bbb
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 630c030000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 630c030000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: 8a
-- scriptSig: 473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 630c030000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds.]
[Recipe complete.]
[Let's extract the signed transaction from the log into its own file.]
[copy last 15 lines of work_log2.txt to a new file]
pi@raspberrypi ~/test $ tail -15 work_log2.txt > signed_transaction.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction.txt
pi@raspberrypi ~/test $ cat signed_transaction.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
[get string length of signed_transaction.txt hex bytes. Use
pi@raspberrypi ~/test $ cat signed_transaction.txt | tr -d '\n' | wc -c
450
[450 / 2 = 225 bytes.]
[Hm. Strange. I had expected 221 bytes for a transaction with a single P2PKH input and a single P2SH output. Future: look into this.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
work.log
work_log2.txt
[Copy needed files from memory_stick_contents to test directory.]
pi@raspberrypi ~/test $ cp memory_stick_contents/display_hex_bytes.py display_hex_bytes.py
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
work.log
work_log2.txt
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
[Recipe complete.]
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
work.log
work_log2.txt
[first, generate 32 bytes of entropy to use as the random value for making the transaction signature]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ nano dice_rolls2.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls2.txt.
Time this using a stopwatch.
Time taken: 7:32.
Approximately 8 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 146
- number of hex characters after conversion: 73
- there is one extra hex character that can't be used to form an entire 8-bit byte.
- number of hex bytes: 36
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e279d9258
- hex byte output shortened to the desired length (32 bytes):
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
- remaining hex bytes:
279d9258
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e
Recommendation: Perhaps preserve the 4 extra hex bytes in an entropy storage file.
Extra hex bytes: 279d9258
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[Let's extract the entropy from the log into its own file.]
[copy last 15 lines of work_log2.txt to a new file]
pi@raspberrypi ~/test $ tail -15 work_log2.txt > random_value.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value.]
pi@raspberrypi ~/test $ nano random_value.txt
[get string length of random_value.txt hex bytes - should be 32*2 = 64. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat random_value.txt | tr -d '\n' | wc -c
64
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
dice_rolls2.txt
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[Copy needed files from memory_stick_contents to test directory.]
pi@raspberrypi ~/test $ cp memory_stick_contents/create_nonstandard_transaction.py create_nonstandard_transaction.py
pi@raspberrypi ~/test $ cp memory_stick_contents/nonstandard_bitcoin_functions.py nonstandard_bitcoin_functions.py
pi@raspberrypi ~/test $ cp memory_stick_contents/nonstandard_transaction.py nonstandard_transaction.py
pi@raspberrypi ~/test $ cp memory_stick_contents/transaction.py transaction.py
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_transaction.py
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
transaction.py
work.log
work_log2.txt
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values (reading them from this article displayed on Aineko's screen), except for the variables
random_value
and
input_data["private_key_hex"]
. - Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- The variable
input_data
is a dictionary that contains several other variables. Delete the existing value for the variable
input_data["private_key_hex"]
. Then use the Nano option "Read File" to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.Note: With long strings, e.g. the txid, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again to form the original txid.
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy the excerpt lines 40-66 to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
##### START CONTROLS
random_value = "91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "1" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 1.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- Amount to be sent to the change address: 0.0020
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.00200000
- Output addresses, with total-value-to-be-received:
-- 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH: 0.00200000
- Total value of all inputs: 0.00200000
- Total value of all outputs: 0.00200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 1.0 (satoshi / byte)
- Calculate 221 * 1.0 and round up to nearest satoshi.
- Final fee: 221 (satoshi)
- Final fee rate (using estimated transaction size): 1.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 199779 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
- previous_output_index: 0f000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 15
- txid: 07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Output 0:
Output:
- value: 630c030000000000
- script_length: 17
- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- bitcoin_amount: 0.00199779
- satoshi_amount: 199779
- redeem_script_hash_hex: 30d540a50d464852194a195529ebfa44af521bbb
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 630c030000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 630c030000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: 8a
-- scriptSig: 473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 630c030000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds.]
[Recipe complete.]
[Let's extract the signed transaction from the log into its own file.]
[copy last 15 lines of work_log2.txt to a new file]
pi@raspberrypi ~/test $ tail -15 work_log2.txt > signed_transaction.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction.txt
pi@raspberrypi ~/test $ cat signed_transaction.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
[get string length of signed_transaction.txt hex bytes. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat signed_transaction.txt | tr -d '\n' | wc -c
450
[450 / 2 = 225 bytes.]
[Hm. Strange. I had expected 221 bytes for a transaction with a single P2PKH input and a single P2SH output. Future: look into this.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
work.log
work_log2.txt
[Copy needed files from memory_stick_contents to test directory.]
pi@raspberrypi ~/test $ cp memory_stick_contents/display_hex_bytes.py display_hex_bytes.py
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
work.log
work_log2.txt
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
hex_bytes
. Then use the Nano option "Read File" to paste the contents of the file signed_transaction.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
0100 0000 01cd e235
40f3 033b 59d8 c00f
d9d8 703c 80d5 928a
1772 44b1 2fec 8d58
0f34 dbce 070f 0000
008a 4730 4402 2005
fc76 7d51 3f28 5c38
f718 f4c9 cfb0 909d
4ba2 d801 31ae d21b
3f26 aa63 0a79 f002
2044 c9b3 c0fb 4a9d
1a8b 0c26 9915 3991
12ee a5ee 4fd7 e42f
c0a4 30a4 7e5e cbb4
5201 4104 3ab6 9279
2d6c 8838 fd30 c2ff
45bf 3cbd 4428 6a5c
ac52 ba64 dc06 4528
1020 2b32 06f5 c779
9c3b 72ff 77fd 1976
f105 ced3 cd77 00b0
412e 1126 6f38 88b8
8c30 52c3 ffff ffff
0163 0c03 0000 0000
0017 a914 30d5 40a5
0d46 4852 194a 1955
29eb fa44 af52 1bbb
8700 0000 0001 0000
00
[Recipe complete.]
[End logging on Raspberry Pi.]
Now, on Aineko, create a text file called "tx_copied.txt" in the work directory for this project. Manually type this signed transaction data into tx_copied.txt. Double-check the data.
Time this using a stopwatch.
Time taken: 13:18
Approximately 13 minutes.
Listening to music made this step more tolerable.
Note: Keeping the intermediate results e.g. tx_copied.txt during the project means that if there is an error, I can go back and look for it without having to completely redo each step.
On Aineko, open a terminal and change directory to the work directory.
aineko:work stjohnpiano$ cat tx_copied.txt | tr -d ' \n' > tx.txt
aineko:work stjohnpiano$ echo '' >> tx.txt
aineko:work stjohnpiano$ cat tx.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
So, the signed transaction tx1, now transferred to the online computer, is:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
Let's see if a blockchain information service can decode this transaction.
Browse to:
live.blockcypher.com/btc/decodetx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Decode Transaction".
Result:
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"double_spend": false,
"fees": 221,
"hash": "add54b899f1aba8b6276e42af86c3c03b0120a864451640b4a8d3fec89a4a72d",
"inputs": [
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"age": 550741,
"output_index": 15,
"output_value": 200000,
"prev_hash": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"script": "473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3",
"script_type": "pay-to-pubkey-hash",
"sequence": 4294967295
}
],
"outputs": [
{
"addresses": [
"369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
],
"script": "a91430d540a50d464852194a195529ebfa44af521bbb87",
"script_type": "pay-to-script-hash",
"value": 199779
}
],
"preference": "low",
"received": "2018-11-20T17:00:45.941747651Z",
"relayed_by": "54.224.143.214",
"size": 221,
"total": 199779,
"ver": 1,
"vin_sz": 1,
"vout_sz": 1
}
Looks good. No immediate error reported.
Hm. Its size is reported as 221 bytes.
Earlier, I measured the length of the signed tx hex string as 450. At 2 hex characters per byte, that's 225 bytes. Hm.
Let's check that again.
aineko:work stjohnpiano$ python
Python 2.7.13 (default, Dec 18 2016, 05:35:59)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = "0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008a473044022005fc767d513f285c38f718f4c9cfb0909d4ba2d80131aed21b3f26aa630a79f0022044c9b3c0fb4a9d1a8b0c269915399112eea5ee4fd7e42fc0a430a47e5ecbb4520141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01630c03000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000"
>>> len(x) / 2.0
>>> 225.0
>>>
225 again.
I wonder if the blockchain information service is reformatting some part of the transaction, in a way that miners currently accept.
Let's broadcast the signed transaction.
Browse to:
live.blockcypher.com/btc/pushtx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Broadcast Transaction".
Result:
Transaction page loads:
live.blockcypher.com/btc/tx/add54b899f1aba8b6276e42af86c3c03b0120a864451640b4a8d3fec89a4a72d
Details:
- Transaction Successfully Broadcst
- AMOUNT TRANSACTED: 0.00199779 BTC
- FEES: 0.00000221 BTC
- Confirmations: 0/6
- Miner Preference: LOW
- Size: 221 bytes
- Version: 1
- Relayed By: 54.224.143.214
Current datetime: 2018-11-20 17:20
Browse to:
bitcoinfees.earn.com
Hm.
For the fee range 1-2 satoshi / byte, I see that:
- 7292 unconfirmed transactions with a fee in this range have been seen in the memory pool in the last 336 hours.
- 7753 transactions with a fee in this range were mined in the last 24 hours.
-- Note: I think these were mined, although this is not stated explicitly, rather than "seen in the memory pool but never confirmed", because for some fee ranges this number is greater than the number "transactions with a fee in this range seen in the memory pool in the last 336 hours".
336 hours * (1 day / 24 hours) = 336 / 24 = 14 days = 2 weeks.
Shut down for now.
On the Raspberry Pi:
pi@raspberrypi ~/test $ sudo halt
[a variety of output is printed, then the Raspberry Pi shuts down]
Unplug the power cable from the Raspberry Pi.
Start work again.
Next: Retrieve work_log2.txt from Raspberry Pi and copy it into this article at the appropriate earlier point. Merge various annotations / comments made here into the log.
Insert the power cable into the Raspberry Pi. It boots up.
Enter default credentials.
raspberrypi login: pi
Password:
Last login: Sun Mar 27 22:44:59 UTC 2016 on tty1
Linux raspberrypi 4.1.13+ #826 PREEMPT Fri Nov 13 20:13:22 GMT 2015 armv61
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pi@raspberrypi ~ $
The password was "raspberry" but this was not echoed to the screen.
Insert the memory stick into the Raspberry Pi.
pi@raspberrypi ~ $ cd test
[mount the memory stick]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
[copy work_log2.txt to the memory stick]
pi@raspberrypi ~/test $ cp work_log2.txt /mnt/memory_stick_mount_point
[confirm that the file has been copied over]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
$RECYCLE.BIN
Recycled
System Volume Information
work
work.log
work_log2.txt
[unmount the memory stick]
pi@raspberrypi ~/test $ sudo umount /mnt/memory_stick_mount_point
[confirm that it has been unmounted]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
Unplug the memory stick from the Raspberry Pi.
Insert it into Aineko. It mounts automatically and an icon appears on the Desktop. Open the file work_log2.txt and integrate its contents into this article.
On Aineko, right-click memory stick's Desktop icon and choose Eject "NO NAME". Unplug the memory stick from Aineko.
Current datetime:
2018-11-21 13:00
[nearly 20 hours have gone by]
Reload transaction page.
live.blockcypher.com/btc/tx/add54b899f1aba8b6276e42af86c3c03b0120a864451640b4a8d3fec89a4a72d
Details:
- Transaction Successfully Broadcst
- AMOUNT TRANSACTED: 0.00199779 BTC
- FEES: 0.00000221 BTC
- Confirmations: 0/6
- Miner Preference: LOW
- Size: 221 bytes
- Version: 1
- Relayed By: 85.144.83.16:8333
Hm.
Actually, I won't wait for 3 days. Instead, I'll use this as an opportunity to practise creating a new version of a transaction with a higher fee.
The previous article that contains this recipe is:
Creating and signing a standard raw Bitcoin transaction
Excerpt:
Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction
Objectives:
- Fine control of the transaction fee.
- Ability to rebroadcast a new transaction with a higher fee if the previous transaction is not mined within a reasonable time period. This new transaction, if mined, should invalidate the previous transaction.
Note: This recipe is derived from work in this project but has not been tested.
1) Gather the required data for a new transaction (this process is not specified in this recipe). Include at least one "change address" output. Inputs should be added as necessary to achieve the desired output values. The sum of the inputs may be greater than the sum of the desired output values, i.e. some bitcoin may be left over. Send this left-over bitcoin to the change address output. Include an additional input that is specifically for paying the as-yet-unknown transaction fee. Send the bitcoin from this input to the change address output.
2) Construct the transaction, without including signatures (this process is not specified in this recipe).
3) Calculate the byte length of the result of step (2). Let this result be A.
4) Let the estimated byte length of the final transaction be N. Let the approximate byte length of a single input signature be B. Let the number of inputs be C. Calculate N = A + B x C.
5) Using a fee estimation service, look at fee ranges (in satoshis / byte) and the estimated delays for each range. Choose an acceptable delay. Let the corresponding fee (in satoshis / byte) be D. Let the final transaction fee (in satoshis) be E. Calculate E = D x N.
6) Copy the result of step (2). Subtract E from the value in the change address output. The transaction fee is stored implicitly in the transaction as the difference between the sum of the input values and the sum of the output values.
7) Sign the transaction (this process is not specified in this recipe). Insert the input signatures into the transaction.
8) Let the final byte length of the transaction be M. Calculate M by finding the byte length of the result of step (7).
9) Let the final transaction fee (in satoshis / byte) be F. Calculate F = E / M. Confirm that F is within the original desired fee range.
10) Record the time, date, and blockheight. Broadcast the transaction to the Bitcoin network or upload the transaction to a service that can do this for you.
11) A node will store unconfirmed transactions in its memory pools for a particular time period. If the transaction is not mined (confirmed) within this period, the node will delete it from its memory pool. This period will vary depending on the node. Some reading indicates that the default period is 72 hours (three days). After broadcasting the transaction, wait three days + a small delay. If the transaction is mined during this period, stop here. Otherwise, continue to step (12).
12) Using a fee estimation service, look at fee ranges (in satoshis / byte) and the estimated delays for each range. Choose a higher fee range than was used previously.
13) Repeat steps (5)-(12) until the transaction is mined.
Note: If a transaction disappears from the network (i.e. the memory pools of all public nodes), this doesn't mean that it has vanished permanently. Anyone who stored it can rebroadcast it later - it will still be valid. In order to make it invalid, create a new transaction that uses at least one of the same inputs.
Note: An input in a transaction is an as-yet-unspent output of a previous transaction. Each unspent output can only ever be spent once. If a transaction is broadcast that uses at least one input that has already been spent, this transaction is invalid and will not be mined.
Hm. Many of the steps in this recipe are already handled in the existing code.
Rather than increment the fee slowly in order to get the lowest fee that I can, I'll choose a fee rate that's a bit higher than the cheapest 0-block-delay fee rate shown on the fee estimation service.
Browse to:
bitcoinfees.earn.com
This service estimates that a transaction with a fee rate of 59-60 satoshis per byte should be mined with a delay of 0 block (0-40 minutes).
I'll choose a fee rate of 66 satoshis per byte.
I'll use the name "tx1b" for this second version of transaction tx1.
Switch back to the Raspberry Pi. Most of the necessary information for creating the transaction has already been transferred over and entered into the settings for create_nonstandard_transaction.py.
Double-check that my LocalBitcoins receiving address has not changed.
Log in. It's:
36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
Hm. It's changed.
Ah. The first version of tx1 (let's call it tx1a) is listed in LocalBitcoins / Receive bitcoins / incoming transactions. Therefore, a new address has been generated for receiving bitcoin at this LocalBitcoins account. I had previously thought that the address would change only when a transaction had settled. Evidently the LocalBitcoins receiving address changes when a transaction to that address is seen in their node memory pool(s).
I'll need to use this new receiving address when making tx1b.
Note: Each new signature requires a new random value. Using the same random value twice in two different signatures (that are both broadcast) could compromise the secrecy of the private key. I'll need to generate another 32 bytes of entropy.
I'll begin logging in a new file called "wlog3.txt".
pi@raspberrypi ~/test $ touch wlog3.txt
Eventually, I'll transfer it via memory stick to Aineko.
Logged commands are run in the
~/test
directory on the Raspberry Pi. While logging, record any annotations or comments here and integrate them into the log when the log has been transferred back from the Raspberry Pi to Aineko (where this article is being written).
[Begin logging on Raspberry Pi.]
[first, generate 32 bytes of entropy to use as the random value for making the transaction signature]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
wlog3.txt
work.log
work_log2.txt
pi@raspberrypi ~/test $ nano dice_rolls3.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls3.txt.
Time this using a stopwatch.
Time taken: 6:33
Approximately 7 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 132
- number of hex characters after conversion: 66
- number of hex bytes: 33
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb04006
- hex byte output shortened to the desired length (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
- remaining hex bytes:
06
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
Recommendation: Perhaps preserve the 1 extra hex bytes in an entropy storage file.
Extra hex bytes: 06
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[Let's extract the entropy from the log into its own file.]
[copy last 15 lines of wlog3.txt to a new file]
pi@raspberrypi ~/test $ tail -15 wlog3.txt > random_value2.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value for signing the transaction tx1b.]
pi@raspberrypi ~/test $ nano random_value2.txt
[get string length of random_value2.txt hex bytes - should be 32*2 = 64. Use
pi@raspberrypi ~/test $ cat random_value2.txt | tr -d '\n' | wc -c
64
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
wlog3.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values (reading them from this article displayed on Aineko's screen), except for the variables
- Most variable values are already entered from when I made tx1a. Exceptions: The output address and the change address (change both of these to:
36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx )
- Note: With long strings, e.g. the output address, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again on the offline Raspberry Pi to form the original address.
- Delete the existing value for the variable
- Change the fee_rate to 66 (satoshi / byte).
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy an excerpt (lines 40-66) to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 66.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- Amount to be sent to the change address: 0.0020
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.00200000
- Output addresses, with total-value-to-be-received:
-- 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx: 0.00200000
- Total value of all inputs: 0.00200000
- Total value of all outputs: 0.00200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 66.0 (satoshi / byte)
- Calculate 221 * 66.0 and round up to nearest satoshi.
- Final fee: 14586 (satoshi)
- Final fee rate (using estimated transaction size): 66.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 185414 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
- previous_output_index: 0f000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 15
- txid: 07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Output 0:
Output:
- value: 46d4020000000000
- script_length: 17
- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- bitcoin_amount: 0.00185414
- satoshi_amount: 185414
- redeem_script_hash_hex: 382b8c40b25f104e9d0277ed91ddf3c849aa3403
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: 8b
-- scriptSig: 483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds to run.]
[Recipe complete.]
[Let's extract the signed transaction from the log into its own file.]
[copy last 15 lines of wlog3.txt to a new file]
pi@raspberrypi ~/test $ tail -15 wlog3.txt > signed_transaction2.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction2.txt
pi@raspberrypi ~/test $ cat signed_transaction2.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
[get string length of signed_transaction2.txt hex bytes. Use
pi@raspberrypi ~/test $ cat signed_transaction2.txt | tr -d '\n' | wc -c
452
[452 / 2 = 226 bytes.]
[Interesting.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value.txt
signed_transaction2.txt
signed_transaction.txt
transaction.py
transaction.pyc
wlog3.txt
work.log
work_log2.txt
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
[Recipe complete.]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
wlog3.txt
work.log
work_log2.txt
pi@raspberrypi ~/test $ nano dice_rolls3.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls3.txt.
Time this using a stopwatch.
Time taken: 6:33
Approximately 7 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 132
- number of hex characters after conversion: 66
- number of hex bytes: 33
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb04006
- hex byte output shortened to the desired length (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
- remaining hex bytes:
06
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
Recommendation: Perhaps preserve the 1 extra hex bytes in an entropy storage file.
Extra hex bytes: 06
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[Let's extract the entropy from the log into its own file.]
[copy last 15 lines of wlog3.txt to a new file]
pi@raspberrypi ~/test $ tail -15 wlog3.txt > random_value2.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value for signing the transaction tx1b.]
pi@raspberrypi ~/test $ nano random_value2.txt
[get string length of random_value2.txt hex bytes - should be 32*2 = 64. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat random_value2.txt | tr -d '\n' | wc -c
64
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value.txt
signed_transaction.txt
transaction.py
transaction.pyc
wlog3.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values (reading them from this article displayed on Aineko's screen), except for the variables
random_value
and
input_data["private_key_hex"]
. - Most variable values are already entered from when I made tx1a. Exceptions: The output address and the change address (change both of these to:
36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx )
- Note: With long strings, e.g. the output address, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again on the offline Raspberry Pi to form the original address.
- Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value2.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- Change the fee_rate to 66 (satoshi / byte).
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy an excerpt (lines 40-66) to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
##### START CONTROLS
random_value = "644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "66" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 66.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- Amount to be sent to the change address: 0.0020
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.00200000
- Output addresses, with total-value-to-be-received:
-- 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx: 0.00200000
- Total value of all inputs: 0.00200000
- Total value of all outputs: 0.00200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 66.0 (satoshi / byte)
- Calculate 221 * 66.0 and round up to nearest satoshi.
- Final fee: 14586 (satoshi)
- Final fee rate (using estimated transaction size): 66.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 185414 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
- previous_output_index: 0f000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 15
- txid: 07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Output 0:
Output:
- value: 46d4020000000000
- script_length: 17
- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- bitcoin_amount: 0.00185414
- satoshi_amount: 185414
- redeem_script_hash_hex: 382b8c40b25f104e9d0277ed91ddf3c849aa3403
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: 8b
-- scriptSig: 483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds to run.]
[Recipe complete.]
[Let's extract the signed transaction from the log into its own file.]
[copy last 15 lines of wlog3.txt to a new file]
pi@raspberrypi ~/test $ tail -15 wlog3.txt > signed_transaction2.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction2.txt
pi@raspberrypi ~/test $ cat signed_transaction2.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
[get string length of signed_transaction2.txt hex bytes. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat signed_transaction2.txt | tr -d '\n' | wc -c
452
[452 / 2 = 226 bytes.]
[Interesting.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value.txt
signed_transaction2.txt
signed_transaction.txt
transaction.py
transaction.pyc
wlog3.txt
work.log
work_log2.txt
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
hex_bytes
. Then use the Nano option "Read File" to paste the contents of the file signed_transaction2.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
0100 0000 01cd e235
40f3 033b 59d8 c00f
d9d8 703c 80d5 928a
1772 44b1 2fec 8d58
0f34 dbce 070f 0000
008b 4830 4502 2100
af98 4f21 f309 6c47
b968 4d9c ccf7 6988
597a ccbd b55f f0b6
6992 ef4b 3006 1608
0220 63ae 31b6 465d
eb45 1d3f 5351 45e2
00bf 09e4 d51d 0c64
0b90 d4d9 e25b 9c97
b2c2 0141 043a b692
792d 6c88 38fd 30c2
ff45 bf3c bd44 286a
5cac 52ba 64dc 0645
2810 202b 3206 f5c7
799c 3b72 ff77 fd19
76f1 05ce d3cd 7700
b041 2e11 266f 3888
b88c 3052 c3ff ffff
ff01 46d4 0200 0000
0000 17a9 1438 2b8c
40b2 5f10 4e9d 0277
ed91 ddf3 c849 aa34
0387 0000 0000 0100
0000
[Recipe complete.]
[End logging on Raspberry Pi.]
Now, on Aineko, create a text file called "tx1b_copied.txt" in the work directory for this project. Manually type this signed transaction data into tx1b_copied.txt. Double-check the data.
Time this using a stopwatch.
Time taken: 12:37
Approximately 13 minutes.
Listening to music made this step more tolerable.
Note: Keeping the intermediate results e.g. tx1b_copied.txt during the project means that if there is an error, I can go back, find it, and fix it without having to completely redo each step.
On Aineko, open a terminal and change directory to the work directory.
aineko:work stjohnpiano$ cat tx1b_copied.txt | tr -d ' \n' > tx1b.txt
aineko:work stjohnpiano$ echo '' >> tx1b.txt
aineko:work stjohnpiano$ cat tx1b.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
[Recipe complete.]
So, the signed transaction tx1b, now transferred to the online computer, is:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
Let's see if a blockchain information service can decode this transaction.
Browse to:
live.blockcypher.com/btc/decodetx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Decode Transaction".
Result:
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"double_spend": false,
"fees": 14586,
"hash": "3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16",
"inputs": [
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"age": 550741,
"output_index": 15,
"output_value": 200000,
"prev_hash": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"script": "483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3",
"script_type": "pay-to-pubkey-hash",
"sequence": 4294967295
}
],
"outputs": [
{
"addresses": [
"36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
],
"script": "a914382b8c40b25f104e9d0277ed91ddf3c849aa340387",
"script_type": "pay-to-script-hash",
"value": 185414
}
],
"preference": "high",
"received": "2018-11-21T16:04:32.919394406Z",
"relayed_by": "54.226.63.120",
"size": 222,
"total": 185414,
"ver": 1,
"vin_sz": 1,
"vout_sz": 1
}
Looks good. No immediate error reported.
Hm. Its size is reported as 222 bytes.
Some details:
- fee: 14586 satoshi
- preference: high
- hash (txid):
3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16
Let's check the byte length of tx1b using Python.
aineko:work stjohnpiano$ python
Python 2.7.13 (default, Dec 18 2016, 05:35:59)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = "0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b30061608022063ae31b6465deb451d3f535145e200bf09e4d51d0c640b90d4d9e25b9c97b2c20141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000"
>>> len(x) / 2.0
>>> 226.0
>>>
Hm. 226 bytes.
Anyway, let's press on and broadcast the signed transaction tx1b.
Browse to:
live.blockcypher.com/btc/pushtx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Broadcast Transaction".
Result:
- "Server Error (500)"
Hm.
Let's look up the txid.
Browse to:
live.blockcypher.com/btc/tx/3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16
Result:
"No transaction found with the hash
3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16"
Hm.
I'll try another broadcast service.
Browse to:
www.blockchain.com/btc/pushtx
Paste the signed transaction into the text box.
Click "Submit Transaction".
Result:
"Validation Error: BitcoindException(super=com.neemre.btcdcli4j.core.BitcoindException: Error #-26: 18: txn-mempool-conflict, code=-26)"
Ah. Some searching and reading indicates that in order for the second version of the transaction to be mined, the first version must first remain unconfirmed for some time (3 days?) and then be removed from the memory pool.
- Note: My attempting to broadcast tx1b (which spends the same output to a different receiving address) looks exactly like an attempted double-spend.
-- Ah. Should have realised this earlier before I simply changed the output address. I was just thinking about fees, but in retrospect, this is obvious. Bitcoin was designed specifically to reject this second transaction, because it could have been a double-spend attack on a merchant.
Hm. I should try to follow the replace-by-fee approach more exactly (which means: change only the fee, not any of the output addresses).
I can make a new transaction (tx1c) which sends the bitcoin to the first LocalBitcoins receiving address again, but this time with a high fee.
Will LocalBitcoins still credit my account with this bitcoin amount i.e. will it treat this previous receiving address as still belonging to my account (and only my account)?
Log in to LocalBitcoins.
In Wallet / Receive bitcoins / Old addresses, I find:
"To protect your privacy, we provide a new bitcoin address for each transfer. This prevents someone from tracking all the payments you receive by looking at the blockchain.
Note that addresses are valid only for 12 months."
along with a list of old addresses (although only the first 10 characters of each address are shown).
Ok. I can re-use the LocalBitcoins receiving address that I used originally in tx1.
I'll create a new version of the transaction, tx1c, where everything is the same as tx1 except for the fee and the random_value.
Let's try again.
Switch back to the Raspberry Pi.
Original LocalBitcoins receiving address, used in tx1:
369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
Note: Each new signature requires a new random value. Using the same random value twice in two different signatures (that are both broadcast) could compromise the secrecy of the private key. I'll need to generate another 32 bytes of entropy.
I'll begin logging in a new file called "w4.txt".
pi@raspberrypi ~/test $ touch w4.txt
Eventually, I'll transfer w4.txt to Aineko via memory stick.
Logged commands are run in the
~/test
directory on the Raspberry Pi. While logging, record any annotations or comments here and integrate them into the log when the log has been transferred back from the Raspberry Pi to Aineko (where this article is being written).
[Begin logging on Raspberry Pi.]
[first, generate 32 bytes of entropy to use as the random value for making the transaction signature]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ nano dice_rolls4.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls4.txt.
Time this using a stopwatch.
Time taken: 5:53
Approximately 6 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 132
- number of hex characters after conversion: 66
- number of hex bytes: 33
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb04006
- hex byte output shortened to the desired length (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
- remaining hex bytes:
06
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
Recommendation: Perhaps preserve the 1 extra hex bytes in an entropy storage file.
Extra hex bytes: 06
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[copy last 15 lines of w4.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w4.txt > random_value3.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value for signing the transaction tx1c.]
pi@raspberrypi ~/test $ nano random_value3.txt
pi@raspberrypi ~/test $ cat random_value3.txt
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
[get string length of random_value3.txt hex bytes - should be 32*2 = 64. Use
pi@raspberrypi ~/test $ cat random_value3.txt | tr -d '\n' | wc -c
64
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value.txt
signed_transaction2.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
wlog3.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values, except for the variable
- Most variable values are already entered from when I made tx1b. Exceptions: The output address and the change address (change both of these to the original LocalBitcoins receiving address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH )
- Note: With long strings, e.g. the output address, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again on the offline Raspberry Pi to form the original address.
- Delete the existing value for the variable
- Confirm that the fee_rate is set to 66 (satoshi / byte).
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy an excerpt (lines 40-66) to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 66.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- Amount to be sent to the change address: 0.0020
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.00200000
- Output addresses, with total-value-to-be-received:
-- 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH: 0.00200000
- Total value of all inputs: 0.00200000
- Total value of all outputs: 0.00200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 66.0 (satoshi / byte)
- Calculate 221 * 66.0 and round up to nearest satoshi.
- Final fee: 14586 (satoshi)
- Final fee rate (using estimated transaction size): 66.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 185414 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
- previous_output_index: 0f000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 15
- txid: 07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Output 0:
Output:
- value: 46d4020000000000
- script_length: 17
- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- bitcoin_amount: 0.00185414
- satoshi_amount: 185414
- redeem_script_hash_hex: 30d540a50d464852194a195529ebfa44af521bbb
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: 8b
-- scriptSig: 483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds to run.]
[Recipe complete.]
[Let's extract the signed transaction from the log into its own file.]
[copy last 15 lines of w4.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w4.txt > signed_transaction3.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction3.txt
pi@raspberrypi ~/test $ cat signed_transaction3.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
[get string length of signed_transaction3.txt hex bytes. Use
pi@raspberrypi ~/test $ cat signed_transaction3.txt | tr -d '\n' | wc -c
452
[452 / 2 = 226 bytes.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value.txt
signed_transaction2.txt
signed_transaction3.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
wlog3.txt
work.log
work_log2.txt
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
[Recipe complete.]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ nano dice_rolls4.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls4.txt.
Time this using a stopwatch.
Time taken: 5:53
Approximately 6 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 132
- number of hex characters after conversion: 66
- number of hex bytes: 33
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb04006
- hex byte output shortened to the desired length (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
- remaining hex bytes:
06
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
Recommendation: Perhaps preserve the 1 extra hex bytes in an entropy storage file.
Extra hex bytes: 06
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[copy last 15 lines of w4.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w4.txt > random_value3.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value for signing the transaction tx1c.]
pi@raspberrypi ~/test $ nano random_value3.txt
pi@raspberrypi ~/test $ cat random_value3.txt
644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040
[get string length of random_value3.txt hex bytes - should be 32*2 = 64. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat random_value3.txt | tr -d '\n' | wc -c
64
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value.txt
signed_transaction2.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
wlog3.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values, except for the variable
random_value
. - Most variable values are already entered from when I made tx1b. Exceptions: The output address and the change address (change both of these to the original LocalBitcoins receiving address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH )
- Note: With long strings, e.g. the output address, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again on the offline Raspberry Pi to form the original address.
- Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value3.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- Confirm that the fee_rate is set to 66 (satoshi / byte).
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy an excerpt (lines 40-66) to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
##### START CONTROLS
random_value = "644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "66" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 66.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- Amount to be sent to the change address: 0.0020
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.00200000
- Output addresses, with total-value-to-be-received:
-- 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH: 0.00200000
- Total value of all inputs: 0.00200000
- Total value of all outputs: 0.00200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 66.0 (satoshi / byte)
- Calculate 221 * 66.0 and round up to nearest satoshi.
- Final fee: 14586 (satoshi)
- Final fee rate (using estimated transaction size): 66.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 185414 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
- previous_output_index: 0f000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 15
- txid: 07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd
Output 0:
Output:
- value: 46d4020000000000
- script_length: 17
- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- address: 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
- bitcoin_amount: 0.00185414
- satoshi_amount: 185414
- redeem_script_hash_hex: 30d540a50d464852194a195529ebfa44af521bbb
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce07
-- previous_output_index: 0f000000
-- script_length: 8b
-- scriptSig: 483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: 46d4020000000000
-- script_length: 17
-- script: a91430d540a50d464852194a195529ebfa44af521bbb87
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds to run.]
[Recipe complete.]
[Let's extract the signed transaction from the log into its own file.]
[copy last 15 lines of w4.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w4.txt > signed_transaction3.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction3.txt
pi@raspberrypi ~/test $ cat signed_transaction3.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
[get string length of signed_transaction3.txt hex bytes. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat signed_transaction3.txt | tr -d '\n' | wc -c
452
[452 / 2 = 226 bytes.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value.txt
signed_transaction2.txt
signed_transaction3.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
wlog3.txt
work.log
work_log2.txt
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
hex_bytes
. Then use the Nano option "Read File" to paste the contents of the file signed_transaction3.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
0100 0000 01cd e235
40f3 033b 59d8 c00f
d9d8 703c 80d5 928a
1772 44b1 2fec 8d58
0f34 dbce 070f 0000
008b 4830 4502 2100
af98 4f21 f309 6c47
b968 4d9c ccf7 6988
597a ccbd b55f f0b6
6992 ef4b 3006 1608
0220 5f6b ad0d ce3f
c5c0 1ac3 128f 6433
02d5 5b95 2edf 656b
e25e e996 049d 74a0
e41c 0141 043a b692
792d 6c88 38fd 30c2
ff45 bf3c bd44 286a
5cac 52ba 64dc 0645
2810 202b 3206 f5c7
799c 3b72 ff77 fd19
76f1 05ce d3cd 7700
b041 2e11 266f 3888
b88c 3052 c3ff ffff
ff01 46d4 0200 0000
0000 17a9 1430 d540
a50d 4648 5219 4a19
5529 ebfa 44af 521b
bb87 0000 0000 0100
0000
[Recipe complete.]
[End logging on Raspberry Pi.]
Now, on Aineko, create a text file called "tx1c_copied.txt" in the work directory for this project. Manually type the signed transaction data displayed on the Raspberry Pi's screen into tx1c_copied.txt. Double-check the data.
I forgot to time this using a stopwatch.
Listening to music made this step more tolerable.
Note: Keeping the intermediate results e.g. tx1c_copied.txt during the project means that if there is an error, I can go back, find it, and fix it without having to completely redo each step.
On Aineko, open a terminal and change directory to the work directory.
aineko:work stjohnpiano$ cat tx1c_copied.txt | tr -d ' \n' > tx1c.txt
aineko:work stjohnpiano$ echo '' >> tx1c.txt
aineko:work stjohnpiano$ cat tx1c.txt
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
[Recipe complete.]
So, the signed transaction tx1c, now transferred to the online computer Aineko, is:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
Let's see if a blockchain information service can decode this transaction.
Browse to:
live.blockcypher.com/btc/decodetx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Decode Transaction".
Result:
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"double_spend": false,
"fees": 14586,
"hash": "8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0",
"inputs": [
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"age": 550741,
"output_index": 15,
"output_value": 200000,
"prev_hash": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"script": "483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3",
"script_type": "pay-to-pubkey-hash",
"sequence": 4294967295
}
],
"outputs": [
{
"addresses": [
"369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
],
"script": "a91430d540a50d464852194a195529ebfa44af521bbb87",
"script_type": "pay-to-script-hash",
"value": 185414
}
],
"preference": "high",
"received": "2018-11-21T17:18:53.214885842Z",
"relayed_by": "54.226.63.120",
"size": 222,
"total": 185414,
"ver": 1,
"vin_sz": 1,
"vout_sz": 1
}
Looks good. No immediate error reported.
Some details:
- size: 222 bytes
- fee: 14586 satoshi
- preference: high
- hash (txid):
8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
Let's check the byte length of tx1c using Python.
aineko:work stjohnpiano$ python
Python 2.7.13 (default, Dec 18 2016, 05:35:59)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = "0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000"
>>> len(x) / 2.0
>>> 226.0
>>>
226 bytes.
Let's broadcast the signed transaction tx1c.
Browse to:
live.blockcypher.com/btc/pushtx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Broadcast Transaction".
Result:
- "Server Error (500)"
Hm.
I'll try another broadcast service.
Browse to:
www.blockchain.com/btc/pushtx
Paste the signed transaction into the text box.
Click "Submit Transaction".
Result:
"Validation Error: BitcoindException(super=com.neemre.btcdcli4j.core.BitcoindException: Error #-26: 18: txn-mempool-conflict, code=-26)"
Hm.
Evidently, these two broadcast-transaction services do not support replace-by-fee transactions.
I'll look up the txid.
Browse to:
live.blockcypher.com/btc/tx/8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
Result:
"No transaction found with the hash
8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0"
Next: Retrieve wlog3.txt and w4.txt from the Raspberry Pi and copy them into this article at the appropriate earlier points. Merge various annotations / comments made here into these logs.
Insert the memory stick into the Raspberry Pi.
[mount the memory stick]
[copy wlog3.txt to the memory stick]
[copy w4.txt to the memory stick]
[confirm that the files have been copied over]
$RECYCLE.BIN
Recycled
System Volume Information
w4.txt
wlog3.txt
work
work.log
work_log2.txt
[unmount the memory stick]
[confirm that it has been unmounted]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
[copy wlog3.txt to the memory stick]
pi@raspberrypi ~/test $ cp wlog3.txt /mnt/memory_stick_mount_point
[copy w4.txt to the memory stick]
pi@raspberrypi ~/test $ cp w4.txt /mnt/memory_stick_mount_point
[confirm that the files have been copied over]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
$RECYCLE.BIN
Recycled
System Volume Information
w4.txt
wlog3.txt
work
work.log
work_log2.txt
[unmount the memory stick]
pi@raspberrypi ~/test $ sudo umount /mnt/memory_stick_mount_point
[confirm that it has been unmounted]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
Unplug the memory stick from the Raspberry Pi.
Shut down for now.
On the Raspberry Pi:
pi@raspberrypi ~/test $ sudo halt
[a variety of output is printed, then the Raspberry Pi shuts down]
Unplug the power cable from the Raspberry Pi.
Insert the memory stick into Aineko. It mounts automatically and an icon appears on the Desktop. Copy the files wlog3.txt and w4.txt to the work directory for this project on Aineko.
On Aineko, right-click memory stick's Desktop icon and choose Eject "NO NAME". Unplug the memory stick from Aineko.
Integrate the contents of the files wlog3.txt and w4.txt into this article.
Done.
Hm.
Let "replace-by-fee transaction" mean "a new version of a transaction in which nothing has changed other than an increased transaction fee (which means: a lower value in one or more of the output addresses)"
I have read that (some?) miners run nodes that will accept a replace-by-fee transaction, because it will be more profitable to mine than the transaction that it replaces.
However, in order to get this replace-by-fee transaction (tx1c) to a miner's node, I have two options (are there more?):
a) Run my own node, and continually broadcast to the Bitcoin network the new replace-by-fee version of the transaction. Hopefully, this will propagate through the section of the Bitcoin network that accepts replace-by-fee transactions, until it reaches a mining node.
a1) Know someone personally who runs their own node and accepts replace-by-fee transactions.
b) Wait until the first version of the transaction (tx1 / tx1a) is cleared out of the memory pools of many (all?) of the Bitcoin nodes or until it is actually mined. If it is cleared, and not mined, I can broadcast the new version tx1c. This could take a long time, as nodes can choose to keep the first version in their memory pools (and relay it) as long as they like.
- Note: If tx1 is cleared without being mined, I could also broadcast tx1b, as this would no longer look like an attempted double-spend.
Another option: Search online for services that accept replace-by-fee transactions. This is a version of option a1.
Let's check if tx1 has been mined or cleared.
Refresh transaction page (tx1):
live.blockcypher.com/btc/tx/add54b899f1aba8b6276e42af86c3c03b0120a864451640b4a8d3fec89a4a72d
Result:
"No transaction found with the hash
add54b899f1aba8b6276e42af86c3c03b0120a864451640b4a8d3fec89a4a72d"
Current datetime: 2018-11-22 17:45
[about 48 hours have gone by since original broadcast of tx1]
Refresh transaction page (tx1b):
live.blockcypher.com/btc/tx/3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16
Result:
"No transaction found with the hash
3677f15c9a6e62a02df0a571370ceb0de9fa90efd56441e3dcb7fe9eff188d16"
Hm. Interesting. This service does not appear to have either transaction (tx1 or tx1b) in its memory pool.
What about tx1c?
Refresh transaction page (tx1c):
live.blockcypher.com/btc/tx/8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
Result:
"No transaction found with the hash
8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0"
Ah. I think that:
- this service accepted tx1 for broadcast. tx1 was never mined. eventually it was cleared from the memory pool.
- while tx1 was in the memory pool, this service rejected tx1b (as an attempt double-spend) and tx1c (also as an attempted double-spend, even though it was actually a replace-by-fee).
Log in to LocalBitcoins. It shows a pending transaction (tx1) and no new completed transaction.
Searching for both
LocalBitcoins receiving address 1:
- 369Dpo9CrJASneaHLdwWfKym7N84XTUyvH
and
LocalBitcoins receiving address 2:
- 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
on
live.blockcypher.com
produces "No transactions detected" and a balance of 0.0 BTC.
So, I think I can now try to upload tx1c to this service for broadcast. Transaction tx1 is no longer in this service's memory pool, blocking tx1c from being uploaded.
First, check current fees.
Browse to:
bitcoinfees.earn.com
The cheapest 0-block-estimated-delay fee range that I see is 53-54 satoshi / byte.
The fee rate 66 satoshi / byte in transaction tx1c should ensure a relatively quick inclusion into the blockchain.
tx1c:
0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb870000000001000000
Browse to:
live.blockcypher.com/btc/pushtx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Broadcast Transaction".
Result:
Transaction page loads:
live.blockcypher.com/btc/tx/8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
Details:
- Transaction Successfully Broadcst
- AMOUNT TRANSACTED: 0.00185414 BTC
- FEES: 0.00014586 BTC
- Confirmations: 0/6
- Miner Preference: HIGH
- Size: 222 bytes
- Version: 1
- Relayed By: 54.242.109.171
Current datetime: 2018-11-22 18:00
Hm.
If I search for these txids and addresses on
www.blockchain.com
I find that tx1 is still stored in that service's system (as "unconfirmed"), and tx1b and tx1c are not.
It's possible that the blockcypher service nodes are surrounded in the Bitcoin network by nodes that have stored tx1 and reject replace-by-fee transactions like tx1c. Even though tx1c has been uploaded to a node, I may still have to wait until tx1 has been cleared out of more memory pools. By the time that happens, tx1c may also have been removed from many memory pools, and I may have to upload it for broadcast again.
Current datetime: 2018-11-23 10:40
Refresh transaction page:
live.blockcypher.com/btc/tx/8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
Confirmations: 6+
Excellent. Transaction tx1c has been mined.
Click Advanced Details.
- Block Hash:
000000000000000000091db255f327f3938cb33cd1076d7554b7bbd22b9c1000
- Block Height: 551,106
- Transaction Index: 668
Click API Call.
Result: tx1c
{
"block_hash": "000000000000000000091db255f327f3938cb33cd1076d7554b7bbd22b9c1000",
"block_height": 551106,
"block_index": 668,
"hash": "8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0",
"hex": "0100000001cde23540f3033b59d8c00fd9d8703c80d5928a177244b12fec8d580f34dbce070f0000008b483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff0146d402000000000017a91430d540a50d464852194a195529ebfa44af521bbb8700000000",
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
],
"total": 185414,
"fees": 14586,
"size": 222,
"preference": "high",
"relayed_by": "54.242.109.171",
"confirmed": "2018-11-22T20:17:05Z",
"received": "2018-11-22T17:46:01.324Z",
"ver": 1,
"double_spend": false,
"vin_sz": 1,
"vout_sz": 1,
"confirmations": 67,
"confidence": 1,
"inputs": [
{
"prev_hash": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"output_index": 15,
"script": "483045022100af984f21f3096c47b9684d9cccf76988597accbdb55ff0b66992ef4b3006160802205f6bad0dce3fc5c01ac3128f643302d55b952edf656be25ee996049d74a0e41c0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3",
"output_value": 200000,
"sequence": 4294967295,
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"script_type": "pay-to-pubkey-hash",
"age": 550741
}
],
"outputs": [
{
"value": 185414,
"script": "a91430d540a50d464852194a195529ebfa44af521bbb87",
"spent_by": "618ceedd53735af8c3024f0fe13184357544d1af73503dd6ad819fd6ef6b7bc6",
"addresses": [
"369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
],
"script_type": "pay-to-script-hash"
}
]
}
Key details:
- block_hash:
000000000000000000091db255f327f3938cb33cd1076d7554b7bbd22b9c1000
- block_height: 551106
- confirmed: 2018-11-22T20:17:05Z
- received: 2018-11-22T17:46:01.324Z
- hash (txid):
8b0f7ba372b61b195cd237429c9a5d079aaf9887e72dd094f2fa942a0f7ccfc0
My record of the broadcast time:
2018-11-22 18:00
blockcypher.com's record of the broadcast time:
2018-11-22T17:46
Fairly close.
Using the times from blockcypher.com:
- Broadcast time: 2018-11-22 17:46
- Confirmation time: 2018-11-22 20:17
Time taken ~= 2.5 hours
Log on to LocalBitcoins.
Go to Wallet / Transactions.
- Latest received transaction:
-- Datetime: 11/22/2018 20:31
-- Received BTC: 0.00170414
-- Description: Deposit to 369Dpo......
-- Deposit Fee BTC: 0.00015000
The test address has now been validated. I have moved some bitcoin into it and then successfully retrieved it. This proves that the address was correctly calculated from the private key.
I can now move a large amount of bitcoin into this address and be certain that I can retrieve it. Even if I later construct a new transaction that turns out to be invalid, and discover that the cause was an error in the code stack used to create and sign a transaction, I know that eventually this error could be fixed and a valid transaction could be created. I would only risk a temporary lack of access to the bitcoin stored in this address, not its permanent loss.
So, I'll now test this approach. I'll transfer a larger amount of bitcoin into the test address, store it for a while, and then transfer it back out. This is the process that can be used to securely store bitcoin offline until it is needed.
Log in to LocalBitcoins.
Current exchange rate:
$4212 / 1 BTC
Using my LocalBitcoins account, I'll transfer ~$50 worth of bitcoin to the test address.
$50 * (1 BTC / $4212) = 50 * 1 / 4212 = 0.01187084 ~= 0.012
Test address:
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
I've transferred 0.0120 bitcoin to the test address. LocalBitcoins charged a transaction fee of 0.00005 bitcoin.
Current datetime: 2018-11-23 18:22
Wait 5-10 minutes.
Refresh LocalBitcoins / Wallet / Transactions.
Latest transaction:
- 11/23/2018 18:08
- Sent BTC: 0.012
- Sent to:
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- txid:
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
Browse to:
live.blockcypher.com
Search for this txid.
Transaction page loads:
live.blockcypher.com/btc/tx/af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
Details:
- AMOUNT TRANSACTED: 49.9112634 BTC
- FEES: 0.0015299 BTC
- CONFIRMATIONS: 0/6
- Miner Preference: HIGH
- Size: 2822 bytes
- Version: 2
- Relayed By: 45.79.10.204:8333
- 1 Input Consumed
- 85 Outputs Created
Set timer for 30 minutes.
Timer has finished.
Refresh transaction page.
Confirmation: 1/6
Set timer for 1 hour.
I refreshed the transaction page after 43 minutes.
Confirmations: 6+
Click Advanced Details / API Call.
Result: tx2
{
"block_hash": "0000000000000000001f85686e50bbc4e929b50768669165731e5c73a690f680",
"block_height": 551219,
"block_index": 502,
"hash": "af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2",
"hex": "020000000001017abbae8a4b2b7200ae3fe62454c1dd39031a1b94461590420202ca09652f7e4e2900000017160014514082c38bf390edbdcd7ea45a2afd27dd44ac88feffffff5588cf34000000000017a9143b1404353aa25fa35e00d1199023e4dbc4ccbfb387f5730a000000000017a914e0ac955a7ca184724a36b74326e9dd1473f5580e8778a010000000000017a9148736e84b40ae4e75d98e3bf5398cc5f3ae6f011287504d06000000000017a91481aa83966e76c850e87a11a03eddf6fa73e786a387b7cf05000000000017a914a7a798eb8307456405068b4547a29edd5d9d972b874dca06000000000017a9147bd968cd765e600ff784e18cf9280af46dcc017587320408000000000017a914be75e425f70abdec55256f6f985fc711872a89d687b3ba00000000000017a9140c040f8168f8dbcaf0e990103780e41021768d2a876a0a05000000000017a91458af46baa689a19dd3963c45c49b123654a8fbb887b77712000000000017a914d2c8032f1ae2ccfb2430c7ad608716eba301f27387fbbd09000000000017a9148ee013a317f0e083b27d47baf1a646a75519532c8700350c000000000017a9147a9b7668b80d51543d771abdf656c1a9e71dc4c7873f6e06000000000017a9146ee9e13deae04aff06a6fa4739858f21bedfc070876b5505000000000017a91424470831d0e6e045d047ba5a89a6af42b682eff38786a203000000000017a9144e3ce92f09e1313ff7845231ce02ed3eae2324ea8728f018000000000017a914ff57bc4784f8075b95175b8f9d7f3d0663770dda87f49307000000000017a9146f0795b6a9a662de22c9e7b07972d53477dc3cc687aaa90a000000000017a91400a14d1d06a91b95efa29376cd728176caa8b2a5876ed912000000000017a914d925d1065fd834a536e9422878ec948f266cf00987f3fa07000000000017a9140f00d11ef3157d1c4d9cf8f6e2d839fd0f43bf098749d023000000000017a91431ddd15e88a817370d82998825d1c4c4af52d9f587e5c207000000000017a914d0220fdca7bf25bdef88969db44d3a29097f015287b35105000000000017a91467ca4930f8a09c3e013989b93bb780a919fb48cb8710f108000000000017a914b99fb98272a8f2733f291aee7467e86753f2398a877ccc560f0100000017a9146b208ae81f844e45c43f9e17c5530ef02ba49fe787804f1200000000001976a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388acda4507000000000017a91415b7bf3e57a9d4f88ccf474f0a05780f3696559d877ba967120000000017a9143e696fd23509b8b6637fd463dab1725fc49b2ea787a54706000000000017a9145a21e377a91fe0936d1cfdc64d45afef5debed4987100707000000000017a914c5789ae5d6a57151b83ef64701dc170b969270e78725430a000000000017a914d902f426611e443f514a16949986a9cdf11fdbc587af9e65000000000017a91435cf6e0694f45f6b039feb2c734a482129bea10d87c9050c000000000017a914a267c025e8b1bc82170b8f27582bc87a298e3ace87d6a30d000000000017a914ad35985c54ba3b16392ded0d4184ce55eefc0c958773b706000000000017a91477113252766830267d54bf0152ea2b8156d65d15874a6c0e000000000017a914dff6a651bbb23b69de926f1ba121dd50be046e4a8784c909000000000017a914ef91c009a28fabff2eb07526a1365808a0e38a7287fc4914000000000017a91463346b99c3ef401c690425571e999e6ef5544d4f878ead11000000000017a9143fa9e9680697e8c089284feebb06bb577d4a534f8739be14000000000017a91405e19ef872775f9393f6193e3a9f23dd8c51e4e1871b17a900000000001976a9149d526dbf65d7358848f98d2702561474fb80601f88aca24b30000000000017a914bfb57dc2acad1372fb9140c78c0249ff3d20fe4e8793dc06000000000017a914dd5cf71eb6c75a61a97940440773c36e5e5816198701d406000000000017a914c59a73e0d41d083a21126ba420e60456c6c1cb9e878fb40f000000000017a9146707f646bacfc8066b791ef83ea0f1aef1b756d58702e720000000000017a914365971c1d49a417129a5ce34757cc1acfde944f087603305000000000017a9149a7b245b5a86f78b55e03d393ad1716b1f761dc087ece307000000000017a9148a85d9a402749d206270f99ee2da99c87fe81eb587aae98e00000000001976a914976c1c20664b3d76042b01c98c1933c85de2788788acc04504000000000017a914247884269766403c87ac818f6ed5db655d86bb3f878cc404000000000017a914a4eff4f61ed5384adbb5497e7f67147e59e26d3887c5da04000000000017a91442b920a9892c866bf6218ec107d02698a0738b4d87234101000000000017a914f87797bdf2a392c9c66c363dfc9968521c7a85648725941300000000001976a9143ca960973e95ee40468d92388d7421399a5a1aad88ac0f9f0300000000001976a9141bd917d52d595181570ef17e39f2bf4ea7ae0de288acd77b0b000000000017a914ebc33c8912509c1cd8681981b25889bb2d1cfcac87ee5e33000000000017a9144c4f0c5780b5d26d77e87e412f306333ed78e08d8753900300000000001976a914a6b9bf2b77e6ede60bba794082092034e680d58888acb35f15000000000017a914ab3792a73b283541f66a9f82e869a03e53b8338a8774dbff00000000001976a914a2ff1026a9ed716efbe74473a04a7643e7059b7b88aceac90e000000000017a9145099ae0c09a8f6973d24824c5922abb8ee54127987e9ed0a000000000017a914480d6e62f69ba7ad85689b2625e5a3c2794c5ea487966e0500000000001976a91422855356ff846270d18a83696b2293ae26185a8488ace22606000000000017a914b25da5e2acd5f15e3834493eb55a4354c1eecd1c87d7fc08000000000017a91433f974a43d1cc3bc6c212ab8009e2b69546acdb087a4a105000000000017a914d710f90d7f6d66c9e05b5443ad670ad3a503f6e487ee450400000000001976a9144a6f9c2b63256961a35beec88f534cfdcbfcc68388ace0510700000000001976a914f1b6b0f57ac696834257794e544e3f2b3aefd7ff88ac7d4507000000000017a914c2c9edcb25fa41e7f430704fc192a6c5e084946e87200436000000000017a914c2f270a1416ad36157931543b5f7771bbe2e712b8735ed0400000000001976a9145a53953abed389f72b403a5a170305db300d54a488ac84280a000000000017a91407a1e28534524bc92e766e575b982203befcc85a87c86500000000000017a914cf29d7ffaf5171ca9be395a2b9affee644d6a52987777d0300000000001976a9142c9bcc3cb570e5f6903b56031b13cd3e18a1de1588acbba36c00000000001976a9146ded876b1a5beecd895308688b5d948cfae897fe88ac416e06000000000017a914d49820b7f13679af09679814a4a97b9132c6cc28875e9c0e000000000017a91426b3e6491a7c929bfe8d339ab7a5dd98cb9ef3c9872d3e05000000000017a9146e176372192c96d926d36d15332d5cf95d1dd3c787a9370b000000000017a9149b2d27552bf03012f237e664ee4cf37806d62aca875e0b21000000000017a914b83714debe64d20c5b340a719a1ce899872a048187941b0e000000000017a91452b7aa5d6ab1e0c7284078e6f0c83ac05f9c5af6877bd204000000000017a9148ca4f89847852e99f61091825b7cf9e56fa923298766a854000000000017a914d5ca13f7e4d9dd67946b10aa5aca2cbd8a77da2d87eac6a500000000001976a914e1ca1236a1f078fd51c40681a9bf745fcad8246d88aca0c20b000000000017a91433d21539705f0eb3210596751aae09eada7eb47f8702483045022100f95714dc9ae10ccb37cbace8991c217783d673b2a0387726735545ab59452a5a022010de0390eed54ea962c1445f2157c6dc81032c7b4bbf7f77c7de070043936331012103dc484d558d2f7ed34e2131255330552d3a4a8417054a3ab060397872af73f81632690800",
"addresses": [
"13YFK5BuzaUHgNHaGWMKLZ7hdRpCkCKYtK",
"149Xh9L2vXAUifrndHV4kockC4WbEyup2M",
"154sNTmf9vPJB8ewB4jbCYFvm2QZ4Dxw2K",
"16XkT3zCwD31Aiacp2qai2pUBsmK2D6Xrr",
"17nahzp9omaMcXVavFi3ArdGBe1Dx2X5k7",
"19Ebwi5vkWprkwH4bnwSuLRLoQqBd4iXHf",
"1B2FCiJyPhqZW12gJa8YFkTZxdvZR7v2ja",
"1EoeYaAZ2mKtxfMBf9AD3qkTJzcsdsLP9L",
"1FLqqN7RdL7Kf63CExZ6qA9uegVgY2b4yX",
"1Frr2AuG8cJGcAahPvfNU2M4G2QRmqDEvs",
"1GCZgkn6L1zFqM5NhGL4jEeQsKwvjvS7sK",
"1Mas7K3wJXgGjW7MSJXp2bAbfFToQNDdSd",
"1P34hqoXi1xTTJPbo7SncLFaeDZvfEDy6D",
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"31kM9x1evVgyz6TqrikJCouXsedi9EjyGb",
"32E7avWJ9gxaVCfP1eNwZYZW8xt5ARJCgk",
"32PNaqqQ5LNcVNVkKLABNqo9yPLaGyRomQ",
"32nYtyjTsGfyxF8JVfkH5Ptdgiqo5AtEve",
"334M3BL9n6u1mMY3SyE9ySoFq2TyCk33Nf",
"33frEYKAqNVE8adVroLUx2ZyKDTRC5HsUF",
"34zqLqgoofeaJXQBdGXkfN97wEobHApj2G",
"351rd4c9C8JLfAK9Ua7nHbbEXq6jPmvp8f",
"35Df7UQiU5cA18gp4EopUp1s5xTgobHhjk",
"36Egm7nRS85UCDZpkLrXgmro5jmJMzLz6x",
"36R249Gks9iHMBdjxuTMeFpxj1gFN6iMAe",
"36RqDoq5TvGTvceSDM3qHku2HEPrRKNsNo",
"36bYEBgviuYSgtRj3oiXKwRbfTCJ4acYfz",
"36ePZc6fbpKwpjEUJNFjDX5ibe9Cgtins9",
"375PmdPUd9T6KA95kCoeCbJnid1SrxDYfK",
"37P28KCeGUJfXUBwRKJ74Dcb3Gmza4YkJ7",
"37Ve3JaqoGFvopiTXXUCLcrK6j4EQ9oJVv",
"37mpJ6TAcY4BMr4yV1t4nksKQBmVqg9G3t",
"38Fzfa6pHn4z8uznMLsMi1yUzC6qMKsXYZ",
"38eVyVJZqTBvgsPcRwbJk5yCErM8NMMLyi",
"38phbfiEfKoqk87C1xUjKwadBq3zVtSKtj",
"393C5kjWZ96WKLiZHQ6bDc4HpwtkFnyc8k",
"39EPMaLong4ZxYp6BmmYPJJVjTFsZsEjBQ",
"39mwMqN2YtathQUeXJkh3RupAQjjQTavxY",
"39pfs3HRy56gjPHT9FPCsKxVf3gwk9Bi1r",
"39ubLRepPE8FdvYa5dr4id1HxHDqXN2m1m",
"3AjZcmAeebyT7N2qtMaqsYbQCSpLGtoSmq",
"3B5o4WhgQh8MjZr2M7pGV7AX1QkQ9jSJvn",
"3B9orNburYLxCu4DnQkjfgm5ei25CBr4RH",
"3BTTDAn8HrmS2Lx48EoJy6v35B4jvAUW8p",
"3Bj8GhmkAjnofYH55YLrqK3UsK32mc8LfR",
"3BoURuGhintHeuhbugaq7ZfYXmaMHxoNfQ",
"3Bp61qdr6hNL8YLddSFqfqjZB4ppQFCwov",
"3CYawD9Zattwi4XR1v87ia6Bk62MsF4DAr",
"3CsJbg1YDxonVSf4HhjDn6P5CTDwr92p42",
"3CysV1QUpHyjL1t7bZFXZYsxzuHQzSpJEn",
"3DWdMp1QZZyQ8ogzBWP1eieNnKa9WqpaNF",
"3E1xvUS2dUemBpVSMchF4BuwCAJWQMaRte",
"3EKTX65jDKjPCFcN8c1qE7vZjsMKBUucr8",
"3EWg9nqhaHCXNM7eygm6CJRTN5CBhM6AR4",
"3EiUJuWs62WPaJDU6YZrghjquZ2A518gS1",
"3FmqW9Fgdap6HG3qiKqFSFbZWFwG4QdMP2",
"3FqWkcCFrhrJt3oZggGAPMaLQxRL15eEDy",
"3GVjgLVR2KKRYmvMbGynHtQc6ZuJrzMvwy",
"3Gj8CVyDuA212EryfqitDThmRnsYCJm2GP",
"3GyVYSt25fKHr6bYn9Y8jCogo45rad36e9",
"3HJL3ck2f4rVFGZW2VcYmpThW27UQ6bmjJ",
"3HUs2b24FfbCp8xq3qXgHMSxDeFVMuN4PC",
"3Hx8PTyqUFoih4EpEcY7eLna3VBhxRt3VN",
"3JV4EyKnfZ3TVNnWqEz5stbbsGFVUDnZCU",
"3JcWGttMtrTyWBmfSE4biuriEtmfLmeCxq",
"3K45YDUupjgDgFKwsswHCbN6TwZC8CJnKu",
"3KAgQR7ioQUQLF8wPnsKQh3iH4AkEeE7iQ",
"3KSxv2KEPvyy2H6QKBHFAv9VogbrGr2J8c",
"3KToSnM1qPtjuVtmBQZxrCUrkRH6XsaD3B",
"3Kh9X7zwC4tyN9vRtvDh5Q33sdq3G4xcNq",
"3Khr4tiq1sUMrT6A8ntESCJxPoJcrZZujL",
"3LaPvcAKeKADQWSbnasm5TpeU64Woj1tbb",
"3LfXH7Pf39uUfEfHiH4ticwUMukERCKkHr",
"3LuXRwEjTDTHyDUM1JBgBVFZnWEDUxEBvc",
"3M57REhvZzMniiHeUMgCQfDTTGH3DhnLbU",
"3MBRw2eryjDC7SN1okjooSjsqPXax8UaJu",
"3MJBY5jZfxtfhs52Y2ghST86cAYjJ7WsV6",
"3MUU6Q4MoXvgrLC4vx6rYSA9MPtL2BSABA",
"3MVBrhzu6GcbEy7W9x6Xeqf2JavzY4MYdM",
"3MsUdHGxaM3bxVPf8qvZFKgChzjouRRB4e",
"3N7E5qpKE2QvPjBZ6eXZG4weFvmRcGMtVB",
"3NAz2pUtoZe544SipVBBhWvjPKhUHXLJbc",
"3PBcbtey4J4S91se4jYKjRys73epnSLLS1",
"3PXk2HiNDxNDBoo4VoPYzBNjQ7Y9T6X4L5",
"3QLnmZqxi2cn7q52MGof8mJk5Rb2FsHwBt",
"3Qy9LRkdQoBPWyq2tyZg2giuCV9QnjXQiz"
],
"total": 4991126340,
"fees": 152990,
"size": 2822,
"preference": "high",
"relayed_by": "45.79.10.204:8333",
"confirmed": "2018-11-23T18:25:35Z",
"received": "2018-11-23T18:10:40.724Z",
"ver": 2,
"lock_time": 551218,
"double_spend": false,
"vin_sz": 1,
"vout_sz": 85,
"confirmations": 12,
"confidence": 1,
"inputs": [
{
"prev_hash": "4e7e2f6509ca020242901546941b1a0339ddc15424e63fae00722b4b8aaebb7a",
"output_index": 41,
"script": "160014514082c38bf390edbdcd7ea45a2afd27dd44ac88",
"output_value": 4991279330,
"sequence": 4294967294,
"addresses": [
"39pfs3HRy56gjPHT9FPCsKxVf3gwk9Bi1r"
],
"script_type": "pay-to-script-hash",
"age": 551213,
"witness": [
"3045022100f95714dc9ae10ccb37cbace8991c217783d673b2a0387726735545ab59452a5a022010de0390eed54ea962c1445f2157c6dc81032c7b4bbf7f77c7de07004393633101",
"03dc484d558d2f7ed34e2131255330552d3a4a8417054a3ab060397872af73f816"
]
}
],
"outputs": [
{
"value": 3461000,
"script": "a9143b1404353aa25fa35e00d1199023e4dbc4ccbfb387",
"addresses": [
"375PmdPUd9T6KA95kCoeCbJnid1SrxDYfK"
],
"script_type": "pay-to-script-hash"
},
{
"value": 685045,
"script": "a914e0ac955a7ca184724a36b74326e9dd1473f5580e87",
"addresses": [
"3NAz2pUtoZe544SipVBBhWvjPKhUHXLJbc"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1089656,
"script": "a9148736e84b40ae4e75d98e3bf5398cc5f3ae6f011287",
"spent_by": "ecf32728178b6d85031d6726504f39e09fc2efe1479c22d5d54b8df86d86cb0b",
"addresses": [
"3E1xvUS2dUemBpVSMchF4BuwCAJWQMaRte"
],
"script_type": "pay-to-script-hash"
},
{
"value": 413008,
"script": "a91481aa83966e76c850e87a11a03eddf6fa73e786a387",
"addresses": [
"3DWdMp1QZZyQ8ogzBWP1eieNnKa9WqpaNF"
],
"script_type": "pay-to-script-hash"
},
{
"value": 380855,
"script": "a914a7a798eb8307456405068b4547a29edd5d9d972b87",
"spent_by": "f6989c89f9c774374ff117119c875e8bb86767049cedc63a8eed22f5fd808e23",
"addresses": [
"3GyVYSt25fKHr6bYn9Y8jCogo45rad36e9"
],
"script_type": "pay-to-script-hash"
},
{
"value": 445005,
"script": "a9147bd968cd765e600ff784e18cf9280af46dcc017587",
"addresses": [
"3CysV1QUpHyjL1t7bZFXZYsxzuHQzSpJEn"
],
"script_type": "pay-to-script-hash"
},
{
"value": 525362,
"script": "a914be75e425f70abdec55256f6f985fc711872a89d687",
"spent_by": "4b8b716d72e966ce8fefa1e439059428d065274a934d59a36d6453ba509833df",
"addresses": [
"3K45YDUupjgDgFKwsswHCbN6TwZC8CJnKu"
],
"script_type": "pay-to-script-hash"
},
{
"value": 47795,
"script": "a9140c040f8168f8dbcaf0e990103780e41021768d2a87",
"addresses": [
"32nYtyjTsGfyxF8JVfkH5Ptdgiqo5AtEve"
],
"script_type": "pay-to-script-hash"
},
{
"value": 330346,
"script": "a91458af46baa689a19dd3963c45c49b123654a8fbb887",
"spent_by": "0100701dc7e325eeb9105f68a63274a911ff6a11b2ddf28f755cf08720bdd4a1",
"addresses": [
"39mwMqN2YtathQUeXJkh3RupAQjjQTavxY"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1210295,
"script": "a914d2c8032f1ae2ccfb2430c7ad608716eba301f27387",
"addresses": [
"3LuXRwEjTDTHyDUM1JBgBVFZnWEDUxEBvc"
],
"script_type": "pay-to-script-hash"
},
{
"value": 638459,
"script": "a9148ee013a317f0e083b27d47baf1a646a75519532c87",
"addresses": [
"3EiUJuWs62WPaJDU6YZrghjquZ2A518gS1"
],
"script_type": "pay-to-script-hash"
},
{
"value": 800000,
"script": "a9147a9b7668b80d51543d771abdf656c1a9e71dc4c787",
"addresses": [
"3CsJbg1YDxonVSf4HhjDn6P5CTDwr92p42"
],
"script_type": "pay-to-script-hash"
},
{
"value": 421439,
"script": "a9146ee9e13deae04aff06a6fa4739858f21bedfc07087",
"addresses": [
"3BoURuGhintHeuhbugaq7ZfYXmaMHxoNfQ"
],
"script_type": "pay-to-script-hash"
},
{
"value": 349547,
"script": "a91424470831d0e6e045d047ba5a89a6af42b682eff387",
"addresses": [
"34zqLqgoofeaJXQBdGXkfN97wEobHApj2G"
],
"script_type": "pay-to-script-hash"
},
{
"value": 238214,
"script": "a9144e3ce92f09e1313ff7845231ce02ed3eae2324ea87",
"addresses": [
"38phbfiEfKoqk87C1xUjKwadBq3zVtSKtj"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1634344,
"script": "a914ff57bc4784f8075b95175b8f9d7f3d0663770dda87",
"addresses": [
"3Qy9LRkdQoBPWyq2tyZg2giuCV9QnjXQiz"
],
"script_type": "pay-to-script-hash"
},
{
"value": 496628,
"script": "a9146f0795b6a9a662de22c9e7b07972d53477dc3cc687",
"addresses": [
"3Bp61qdr6hNL8YLddSFqfqjZB4ppQFCwov"
],
"script_type": "pay-to-script-hash"
},
{
"value": 698794,
"script": "a91400a14d1d06a91b95efa29376cd728176caa8b2a587",
"spent_by": "10a3504ce524d77bc803466396fcae150c1fa1c5fbd2a42df4616be51db67df6",
"addresses": [
"31kM9x1evVgyz6TqrikJCouXsedi9EjyGb"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1235310,
"script": "a914d925d1065fd834a536e9422878ec948f266cf00987",
"addresses": [
"3MVBrhzu6GcbEy7W9x6Xeqf2JavzY4MYdM"
],
"script_type": "pay-to-script-hash"
},
{
"value": 522995,
"script": "a9140f00d11ef3157d1c4d9cf8f6e2d839fd0f43bf0987",
"spent_by": "571297585d081add53553d095622b2125088718c2ba3166e6e7b8e00821b5214",
"addresses": [
"334M3BL9n6u1mMY3SyE9ySoFq2TyCk33Nf"
],
"script_type": "pay-to-script-hash"
},
{
"value": 2347081,
"script": "a91431ddd15e88a817370d82998825d1c4c4af52d9f587",
"addresses": [
"36Egm7nRS85UCDZpkLrXgmro5jmJMzLz6x"
],
"script_type": "pay-to-script-hash"
},
{
"value": 508645,
"script": "a914d0220fdca7bf25bdef88969db44d3a29097f015287",
"spent_by": "9ffcbe2a07ce5415b531c2bc93fd6d7a06df1694ad01902f06e557b1868d299d",
"addresses": [
"3LfXH7Pf39uUfEfHiH4ticwUMukERCKkHr"
],
"script_type": "pay-to-script-hash"
},
{
"value": 348595,
"script": "a91467ca4930f8a09c3e013989b93bb780a919fb48cb87",
"addresses": [
"3B9orNburYLxCu4DnQkjfgm5ei25CBr4RH"
],
"script_type": "pay-to-script-hash"
},
{
"value": 586000,
"script": "a914b99fb98272a8f2733f291aee7467e86753f2398a87",
"addresses": [
"3JcWGttMtrTyWBmfSE4biuriEtmfLmeCxq"
],
"script_type": "pay-to-script-hash"
},
{
"value": 4552313980,
"script": "a9146b208ae81f844e45c43f9e17c5530ef02ba49fe787",
"addresses": [
"3BTTDAn8HrmS2Lx48EoJy6v35B4jvAUW8p"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1200000,
"script": "76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac",
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 476634,
"script": "a91415b7bf3e57a9d4f88ccf474f0a05780f3696559d87",
"addresses": [
"33frEYKAqNVE8adVroLUx2ZyKDTRC5HsUF"
],
"script_type": "pay-to-script-hash"
},
{
"value": 308783483,
"script": "a9143e696fd23509b8b6637fd463dab1725fc49b2ea787",
"spent_by": "c93bf4c398277bf1f1ef4aa8f3aa64fd5c5df7e1faba0ef6087e46ac96fd89b9",
"addresses": [
"37P28KCeGUJfXUBwRKJ74Dcb3Gmza4YkJ7"
],
"script_type": "pay-to-script-hash"
},
{
"value": 411557,
"script": "a9145a21e377a91fe0936d1cfdc64d45afef5debed4987",
"spent_by": "4e378798f181ebf31e6a5fcee911baa5fb409d3a4834cc1d9a822e287bbf59d7",
"addresses": [
"39ubLRepPE8FdvYa5dr4id1HxHDqXN2m1m"
],
"script_type": "pay-to-script-hash"
},
{
"value": 460560,
"script": "a914c5789ae5d6a57151b83ef64701dc170b969270e787",
"addresses": [
"3Kh9X7zwC4tyN9vRtvDh5Q33sdq3G4xcNq"
],
"script_type": "pay-to-script-hash"
},
{
"value": 672549,
"script": "a914d902f426611e443f514a16949986a9cdf11fdbc587",
"addresses": [
"3MUU6Q4MoXvgrLC4vx6rYSA9MPtL2BSABA"
],
"script_type": "pay-to-script-hash"
},
{
"value": 6659759,
"script": "a91435cf6e0694f45f6b039feb2c734a482129bea10d87",
"addresses": [
"36bYEBgviuYSgtRj3oiXKwRbfTCJ4acYfz"
],
"script_type": "pay-to-script-hash"
},
{
"value": 787913,
"script": "a914a267c025e8b1bc82170b8f27582bc87a298e3ace87",
"addresses": [
"3GVjgLVR2KKRYmvMbGynHtQc6ZuJrzMvwy"
],
"script_type": "pay-to-script-hash"
},
{
"value": 893910,
"script": "a914ad35985c54ba3b16392ded0d4184ce55eefc0c9587",
"addresses": [
"3HUs2b24FfbCp8xq3qXgHMSxDeFVMuN4PC"
],
"script_type": "pay-to-script-hash"
},
{
"value": 440179,
"script": "a91477113252766830267d54bf0152ea2b8156d65d1587",
"addresses": [
"3CYawD9Zattwi4XR1v87ia6Bk62MsF4DAr"
],
"script_type": "pay-to-script-hash"
},
{
"value": 945226,
"script": "a914dff6a651bbb23b69de926f1ba121dd50be046e4a87",
"spent_by": "cee24fc0d864f421bf896dc2a30b631a9a570b94506b66bc44e1cb969da43ee4",
"addresses": [
"3N7E5qpKE2QvPjBZ6eXZG4weFvmRcGMtVB"
],
"script_type": "pay-to-script-hash"
},
{
"value": 641412,
"script": "a914ef91c009a28fabff2eb07526a1365808a0e38a7287",
"spent_by": "cd2fa51e7d2fcb069b2baf768d5dcdc4ae01375b1f56db1accc9dcc20be5098e",
"addresses": [
"3PXk2HiNDxNDBoo4VoPYzBNjQ7Y9T6X4L5"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1329660,
"script": "a91463346b99c3ef401c690425571e999e6ef5544d4f87",
"spent_by": "1ef28779f6da39a919b869ab8ec2a940965f4d22b9121bc3969514c6ef72c155",
"addresses": [
"3AjZcmAeebyT7N2qtMaqsYbQCSpLGtoSmq"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1158542,
"script": "a9143fa9e9680697e8c089284feebb06bb577d4a534f87",
"spent_by": "4b8b716d72e966ce8fefa1e439059428d065274a934d59a36d6453ba509833df",
"addresses": [
"37Ve3JaqoGFvopiTXXUCLcrK6j4EQ9oJVv"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1359417,
"script": "a91405e19ef872775f9393f6193e3a9f23dd8c51e4e187",
"addresses": [
"32E7avWJ9gxaVCfP1eNwZYZW8xt5ARJCgk"
],
"script_type": "pay-to-script-hash"
},
{
"value": 11081499,
"script": "76a9149d526dbf65d7358848f98d2702561474fb80601f88ac",
"addresses": [
"1FLqqN7RdL7Kf63CExZ6qA9uegVgY2b4yX"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 3165090,
"script": "a914bfb57dc2acad1372fb9140c78c0249ff3d20fe4e87",
"addresses": [
"3KAgQR7ioQUQLF8wPnsKQh3iH4AkEeE7iQ"
],
"script_type": "pay-to-script-hash"
},
{
"value": 449683,
"script": "a914dd5cf71eb6c75a61a97940440773c36e5e58161987",
"spent_by": "cd2fa51e7d2fcb069b2baf768d5dcdc4ae01375b1f56db1accc9dcc20be5098e",
"addresses": [
"3MsUdHGxaM3bxVPf8qvZFKgChzjouRRB4e"
],
"script_type": "pay-to-script-hash"
},
{
"value": 447489,
"script": "a914c59a73e0d41d083a21126ba420e60456c6c1cb9e87",
"addresses": [
"3Khr4tiq1sUMrT6A8ntESCJxPoJcrZZujL"
],
"script_type": "pay-to-script-hash"
},
{
"value": 1029263,
"script": "a9146707f646bacfc8066b791ef83ea0f1aef1b756d587",
"spent_by": "ecf32728178b6d85031d6726504f39e09fc2efe1479c22d5d54b8df86d86cb0b",
"addresses": [
"3B5o4WhgQh8MjZr2M7pGV7AX1QkQ9jSJvn"
],
"script_type": "pay-to-script-hash"
},
{
"value": 2156290,
"script": "a914365971c1d49a417129a5ce34757cc1acfde944f087",
"addresses": [
"36ePZc6fbpKwpjEUJNFjDX5ibe9Cgtins9"
],
"script_type": "pay-to-script-hash"
},
{
"value": 340832,
"script": "a9149a7b245b5a86f78b55e03d393ad1716b1f761dc087",
"addresses": [
"3FmqW9Fgdap6HG3qiKqFSFbZWFwG4QdMP2"
],
"script_type": "pay-to-script-hash"
},
{
"value": 517100,
"script": "a9148a85d9a402749d206270f99ee2da99c87fe81eb587",
"addresses": [
"3EKTX65jDKjPCFcN8c1qE7vZjsMKBUucr8"
],
"script_type": "pay-to-script-hash"
},
{
"value": 9365930,
"script": "76a914976c1c20664b3d76042b01c98c1933c85de2788788ac",
"spent_by": "7f731c7ae76998c12516133e701cc2cd5f4b95638821f5ac877e398fb531d5cd",
"addresses": [
"1EoeYaAZ2mKtxfMBf9AD3qkTJzcsdsLP9L"
],
"script_type": "pay-to-pubkey-hash"
},
{
"value": 280000,
"script": "a914247884269766403c87ac818f6ed5db655d86bb3f87",
"spent_by": "d117fb707a3489a2e2bcdd8ddcc348d0e8c81011441be56f23d189ccb373948d",
"addresses": [
"351rd4c9C8JLfAK9Ua7nHbbEXq6jPmvp8f"
],
"script_type": "pay-to-script-hash"
}
],
"next_outputs": "https://api.blockcypher.com/v1/btc/main/txs/af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2?instart=0\u0026outstart=50\u0026limit=50"
}
Key details:
- block_hash:
0000000000000000001f85686e50bbc4e929b50768669165731e5c73a690f680
- block_height: 551219
- block_index: 502
- hash (txid):
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
- total: 4991126340
- fees: 152990
- size: 2822
- preference: high
- relayed_by: 45.79.10.204:8333
- confirmed: 2018-11-23T18:25:35Z
- received: 2018-11-23T18:10:40.724Z
Hm. Note this section at the end:
"next_outputs": "https://api.blockcypher.com/v1/btc/main/txs/af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2?instart=0\u0026outstart=50\u0026limit=50"
There are 85 outputs. I will eventually need to find the previous_output_index within this transaction. I'll search for the test address in the transaction data included above. If it's there, I don't need to browse to the supplied url to get the remaining outputs.
Yes, it's there.
Copy the transaction data to a new text file. Search for the test address. Select all outputs that come after it in the outputs list and delete them. Each output is contained within pairs of curly braces ('{' and '}'). A readthrough shows me that curly braces are not included within output data. Use the "Find All" feature in my text editor (TextWrangler) to discover that there are 26 total occurrences of '{'. There are therefore 26 outputs. They are zero-indexed, so the previous_output_index of the output sent to my test address in transaction tx2 is 25.
Test address:
1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
I'll copy the specific output data here:
{
"value": 1200000,
"script": "76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac",
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"script_type": "pay-to-pubkey-hash"
},
Let's summarise:
The index of the output that I will use as an input in tx3 is:
25
The value in this unspent output is:
1200000 satoshi (0.012 bitcoin)
The txid of tx2, which contains this unspent output, is:
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
These 3 pieces of information, together with the private key of the test address (which is where this output is now stored in the blockchain), allow me to spend this bitcoin in a new transaction.
[nearly a week has passed]
The datetime of confirmation of tx2 was:
2018-11-23T18:25:35Z
Current datetime:
2018-11-30T12:42 UTC
Ok. I've successfully stored the bitcoin on the Raspberry Pi. I'll now demonstrate how to send it back to an exchange (LocalBitcoins).
I'll gather the necessary information for tx3.
My LocalBitcoins account will have a nonstandard P2SH address. I will follow this recipe again:
Recipe for creating and signing a nonstandard Bitcoin transaction
Let's look at fee rates. Browse to:
bitcoinfees.earn.com
I'll choose a fee rate of 10 satoshi / byte. Estimated delay = 0-7 blocks (0-180 minutes).
- This is the lowest fee rate that has an estimated delay starting at 0 blocks. The fee rate of 7-8 satoshi / byte has an estimated delay of 1-8 blocks (0-180 minutes).
Gathered information:
Unspent output:
- index: 25
- value: 1200000 satoshi (0.012 bitcoin)
- The txid of tx2, which contains this unspent output, is:
af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
- The private key (in hex bytes) of the test address is:
c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
-- Note: This is stored on the Raspberry Pi in the file private_key.txt.
Chosen information:
Log into LocalBitcoins. Current receiving address is:
36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- This was the output address in tx1b.
- This will be the output address for tx3. I'll call it "lb_address2" (lb = LocalBitcoins).
- The "output amount" == The bitcoin amount (or satoshi amount) that I wish to transfer to the output address:
1200000 satoshi (0.012 bitcoin)
-- Note: This should be equal to the input amount (the code does not have the ability to send change). Any unassigned value will still be sent to the single output address (which in this recipe is the same as the change address).
- The change address.
36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
-- Note: In this recipe, the change address must be the same as the single output address.
- The fee (in satoshi) or fee_rate (in satoshi / byte):
fee_rate = 10 satoshi / byte
I'll switch to the Raspberry Pi.
When I need the information gathered / chosen above, I'll copy it manually into the Raspberry Pi, reading it from Aineko's screen.
Insert the power cable into the Raspberry Pi.
Enter default credentials:
raspberrypi login: pi
Password:
Last login: Mon Mar 28 04:20:15 UTC 2016 on tty1
Linux raspberrypi 4.1.13+ #826 PREEMPT Fri Nov 13 20:13:22 GMT 2015 armv61
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pi@raspberrypi ~ $
The password was "raspberry" but this was not echoed to the screen.
pi@raspberrypi ~ $ pwd
/home/pi
pi@raspberrypi ~ $ ls -1
Desktop
Documents
Downloads
indiecity
python_game
Scratch
test
w4.txt
wlog3.txt
pi@raspberrypi ~ $ cd test
pi@raspberrypi ~/test $
I'll begin logging in the new file called "w5.txt".
pi@raspberrypi ~/test $ touch w5.txt
Eventually, I'll transfer w5.txt to Aineko via memory stick.
Logged commands are run in the
~/test
directory on the Raspberry Pi. While logging, record any annotations or comments here and integrate them into the log when the log has been transferred back from the Raspberry Pi to Aineko (where this article is being written).
[Begin logging on Raspberry Pi.]
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value.txt
signed_transaction2.txt
signed_transaction3.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
w5.txt
wlog3.txt
work.log
work_log2.txt
[first, generate 32 bytes of entropy to use as the random value for making the transaction signature]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ nano dice_rolls5.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls5.txt.
Time this using a stopwatch.
Time taken: 6:59
Approximately 7 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
Hm. Note: I find that
Perhaps, when signing tx1c, I used the entropy derived from dice_rolls3.txt, not dice_rolls4.txt.
Yup, checking the files "random_value.txt", "random_value2.txt", and "random_value3.txt" with
pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 150
- number of hex characters after conversion: 75
- there is one extra hex character that can't be used to form an entire 8-bit byte.
- number of hex bytes: 37
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f9b315219aa
- hex byte output shortened to the desired length (32 bytes):
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
- remaining hex bytes:
9b315219aa
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
Recommendation: Perhaps preserve the 5 extra hex bytes in an entropy storage file.
Extra hex bytes: 9b315219aa
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[copy last 15 lines of w5.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w5.txt > random_value4.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value for signing the transaction tx3.]
pi@raspberrypi ~/test $ nano random_value4.txt
pi@raspberrypi ~/test $ cat random_value4.txt
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
[get string length of random_value4.txt hex bytes - should be 32*2 = 64. Use
pi@raspberrypi ~/test $ cat random_value4.txt | tr -d '\n' | wc -c
64
[I had to use
pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls5.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value4.txt
random_value.txt
signed_transaction2.txt
signed_transaction3.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
w5.txt
wlog3.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values, except for the variable
- Delete the existing value for the variable
- The private key stays the same (tx3 is spending from the test address, the same as in tx1).
- Note: With long strings, e.g. the txid, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again on the offline Raspberry Pi to form the original txid.
- Double-check that the fee_rate is set to 10 (satoshi / byte).
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy an excerpt (lines 40-66) to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 10.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- Amount to be sent to the change address: 0.01200000
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.01200000
- Output addresses, with total-value-to-be-received:
-- 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx: 0.01200000
- Total value of all inputs: 0.01200000
- Total value of all outputs: 0.01200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 10.0 (satoshi / byte)
- Calculate 221 * 10.0 and round up to nearest satoshi.
- Final fee: 2210 (satoshi)
- Final fee rate (using estimated transaction size): 10.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 1197790 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
- previous_output_index: 19000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 25
- txid: af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
Output 0:
Output:
- value: de46120000000000
- script_length: 17
- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- bitcoin_amount: 0.01197790
- satoshi_amount: 1197790
- redeem_script_hash_hex: 382b8c40b25f104e9d0277ed91ddf3c849aa3403
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
-- previous_output_index: 19000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: de46120000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
-- previous_output_index: 19000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: de46120000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
-- previous_output_index: 19000000
-- script_length: 8b
-- scriptSig: 483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: de46120000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds to run.]
[Recipe complete.]
[Let's extract the signed transaction from the log into a separate file.]
[copy last 15 lines of w5.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w5.txt > signed_transaction4.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction4.txt
pi@raspberrypi ~/test $ cat signed_transaction4.txt
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
[get string length of signed_transaction4.txt hex bytes. Use
pi@raspberrypi ~/test $ cat signed_transaction4.txt | tr -d '\n' | wc -c
452
[I had to use
[452 / 2 = 226 bytes.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
[Recipe complete.]
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value.txt
signed_transaction2.txt
signed_transaction3.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
w5.txt
wlog3.txt
work.log
work_log2.txt
[first, generate 32 bytes of entropy to use as the random value for making the transaction signature]
[
I'm following the recipe Recipe for generating entropy bytes using dice
to generate 32 bytes of entropy.
32 * 8 = 256
round_up( 256 / 1.3333 * 1.1 ) = 212 dice rolls
]
pi@raspberrypi ~/test $ nano dice_rolls5.txt
[
Perform 212 dice rolls, using Nano to record the results in dice_rolls5.txt.
Time this using a stopwatch.
Time taken: 6:59
Approximately 7 minutes.
]
[Use the Nano editor to edit the controls in convert_dice_rolls_to_hex_bytes_2.py, according to the recipe.]
pi@raspberrypi ~/test $ nano convert_dice_rolls_to_hex_bytes_2.py
Hm. Note: I find that
dice_rolls_file_path
is set to be "dice_rolls3.txt", not "dice_rolls4.txt" as expected. Perhaps, when signing tx1c, I used the entropy derived from dice_rolls3.txt, not dice_rolls4.txt.
Yup, checking the files "random_value.txt", "random_value2.txt", and "random_value3.txt" with
cat
shows me that random_value2.txt and random_value3.txt contain the same value. Ah well. pi@raspberrypi ~/test $ python convert_dice_rolls_to_hex_bytes_2.py
### START CONVERSION OF DICE ROLLS TO HEX BYTES
- number of dice rolls: 212
- number of dice rolls in the list [1234]: 150
- number of hex characters after conversion: 75
- there is one extra hex character that can't be used to form an entire 8-bit byte.
- number of hex bytes: 37
- desired number of hex bytes: 32
- the hex bytes produced are sufficient.
- hex byte output:
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f9b315219aa
- hex byte output shortened to the desired length (32 bytes):
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
- remaining hex bytes:
9b315219aa
Result: Desired amount of entropy (32 bytes) has been produced.
Entropy (32 bytes):
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
Recommendation: Perhaps preserve the 5 extra hex bytes in an entropy storage file.
Extra hex bytes: 9b315219aa
### END CONVERSION OF DICE ROLLS TO HEX BYTES
[Recipe complete.]
[copy last 15 lines of w5.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w5.txt > random_value4.txt
[Use Nano to remove the text around the 32 entropy hex bytes contained in the output. I will later use these 32 bytes as the random value for signing the transaction tx3.]
pi@raspberrypi ~/test $ nano random_value4.txt
pi@raspberrypi ~/test $ cat random_value4.txt
f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f
[get string length of random_value4.txt hex bytes - should be 32*2 = 64. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat random_value4.txt | tr -d '\n' | wc -c
64
[I had to use
nano
to manually add the two newline characters "\n" in this command in w5.txt. The
-e
flag with
echo
enables interpretation of backslash escapes.]pi@raspberrypi ~/test $ ls -1
bitcoin_functions.py
bitcoin_functions.pyc
bjorn_edstrom_ripemd160.py
bjorn_edstrom_ripemd160.pyc
convert_dice_rolls_to_hex_bytes_2.py
create_nonstandard_transaction.py
dice_rolls2.txt
dice_rolls3.txt
dice_rolls4.txt
dice_rolls5.txt
dice_rolls.txt
display_hex_bytes.py
ecdsa
ecdsa-0.10
ecdsa-0.10.tar.gz
generate_bitcoin_address_3.py
memory_stick_contents
nonstandard_bitcoin_functions.py
nonstandard_bitcoin_functions.pyc
nonstandard_transaction.py
nonstandard_transaction.pyc
private_key.txt
pypy_sha256.py
pypy_sha256.pyc
random_value2.txt
random_value3.txt
random_value4.txt
random_value.txt
signed_transaction2.txt
signed_transaction3.txt
signed_transaction.txt
transaction.py
transaction.pyc
w4.txt
w5.txt
wlog3.txt
work.log
work_log2.txt
[Now, proceed with the recipe in Recipe for creating and signing a nonstandard Bitcoin transaction ]
[I'll use the existing directory "test" as the work directory.]
[ecdsa-0.10.tar.gz is already unpacked.]
[
Use the Nano editor to edit the controls in create_nonstandard_transaction.py, according to the recipe. Manually enter the gathered / chosen values, except for the variable
random_value
. - Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value4.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- The private key stays the same (tx3 is spending from the test address, the same as in tx1).
- Note: With long strings, e.g. the txid, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again on the offline Raspberry Pi to form the original txid.
- Double-check that the fee_rate is set to 10 (satoshi / byte).
]
pi@raspberrypi ~/test $ nano create_nonstandard_transaction.py
[Note: In create_nonstandard_transaction.py, all control values are strings (i.e. are contained within quotation marks).]
[Let's record a copy of the settings. They are on lines 41-65. I'll copy an excerpt (lines 40-66) to the log.]
pi@raspberrypi ~/test $ cat create_nonstandard_transaction.py | sed -n '40,66p'
##### START CONTROLS
random_value = "f78c5ebf0efac89d60aedb38c30906ad5b22ae522a3e29819248c21d59e8397f"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2",
"previous_output_index": "25",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
"satoshi_amount": "1200000",
#"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx",
"satoshi_amount": "1200000",
#"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "10" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
pi@raspberrypi ~/test $ python create_nonstandard_transaction.py
### START CREATION OF NONSTANDARD BITCOIN TRANSACTION
- Fee type: fee_rate
- Fee rate: 10.0 (satoshi / byte)
- Number of inputs (i.e. as-yet-unspent outputs): 1
- Number of outputs: 1
- Change address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- Amount to be sent to the change address: 0.01200000
- Input addresses, with total-value-to-be-sent:
-- 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK: 0.01200000
- Output addresses, with total-value-to-be-received:
-- 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx: 0.01200000
- Total value of all inputs: 0.01200000
- Total value of all outputs: 0.01200000
- Total value of all inputs exactly matches total value of all outputs.
- Estimated transaction size: 221 bytes
- Fee rate: 10.0 (satoshi / byte)
- Calculate 221 * 10.0 and round up to nearest satoshi.
- Final fee: 2210 (satoshi)
- Final fee rate (using estimated transaction size): 10.0000 (satoshi per byte)
- Fee subtracted from amount to be sent to change address.
- New amount to be sent to change address: 1197790 (satoshi)
Input 0:
Input (without signature):
- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
- previous_output_index: 19000000
- sequence: ffffffff
- private_key_hex: c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca
- public_key_hex: 043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
- script_length_scriptPubKey: 19
- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
- script_length: None
- scriptSig: None
- address: 1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK
- previous_output_index_int: 25
- txid: af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2
Output 0:
Output:
- value: de46120000000000
- script_length: 17
- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- address: 36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx
- bitcoin_amount: 0.01197790
- satoshi_amount: 1197790
- redeem_script_hash_hex: 382b8c40b25f104e9d0277ed91ddf3c849aa3403
Nonstandard Transaction (unsigned form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
-- previous_output_index: 19000000
-- script_length: None
-- scriptSig: None
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: de46120000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
Nonstandard Transaction (signable form):
- version: 01000000
- input_count: 01
- Input [to be used to sign this signable form]:
-- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
-- previous_output_index: 19000000
-- script_length_scriptPubKey: 19
-- scriptPubKey: 76a9140a2a6e4834efa5c7c31eed1ebeadf94a370a1e9388ac
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: de46120000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Nonstandard Transaction (signed form):
- version: 01000000
- input_count: 01
- Input:
-- previous_output_hash: d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af
-- previous_output_index: 19000000
-- script_length: 8b
-- scriptSig: 483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3
-- sequence: ffffffff
- output_count: 01
- Output [P2SH]:
-- value: de46120000000000
-- script_length: 17
-- script: a914382b8c40b25f104e9d0277ed91ddf3c849aa340387
- block_lock_time: 00000000
- hash_type_4_byte: 01000000
Signed transaction:
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
### END CREATION OF BITCOIN TRANSACTION
[The python create_nonstandard_transaction.py command took a few seconds to run.]
[Recipe complete.]
[Let's extract the signed transaction from the log into a separate file.]
[copy last 15 lines of w5.txt to a new file]
pi@raspberrypi ~/test $ tail -15 w5.txt > signed_transaction4.txt
[Use Nano to remove the text around the signed transaction hex string contained in the output.]
pi@raspberrypi ~/test $ nano signed_transaction4.txt
pi@raspberrypi ~/test $ cat signed_transaction4.txt
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
[get string length of signed_transaction4.txt hex bytes. Use
tr
to remove the newline character at the end of the file.]pi@raspberrypi ~/test $ cat signed_transaction4.txt | tr -d '\n' | wc -c
452
[I had to use
nano
to edit w5.txt manually and insert the newline character "\n" in this command.][452 / 2 = 226 bytes.]
[Finally, follow the recipe in the article Displaying hex bytes for manual copying to make the signed transaction easier to read and manually copy from the offline Raspberry Pi to the online Aineko.]
[
Use the Nano editor to edit the controls in display_hex_bytes.py, according to the recipe.
- Delete the existing value for the variable
hex_bytes
. Then use the Nano option "Read File" to paste the contents of the file signed_transaction4.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.]
pi@raspberrypi ~/test $ nano display_hex_bytes.py
pi@raspberrypi ~/test $ python display_hex_bytes.py
0100 0000 01d2 2723
6f72 471b d19c e1c0
aa7b 1c1a 761e fd70
fb56 b28e fb6b 6b0b
26cc 8838 af19 0000
008b 4830 4502 2100
f03c 6252 1817 e4fa
f31a bd01 782c 7df2
fcef 8a22 3440 0068
f1a8 21b2 9fe1 29da
0220 1185 879e 760f
ac3d 9f2d bdc2 e2af
074c 32c7 0088 dd83
9108 971c 3990 5f5b
5bbf 0141 043a b692
792d 6c88 38fd 30c2
ff45 bf3c bd44 286a
5cac 52ba 64dc 0645
2810 202b 3206 f5c7
799c 3b72 ff77 fd19
76f1 05ce d3cd 7700
b041 2e11 266f 3888
b88c 3052 c3ff ffff
ff01 de46 1200 0000
0000 17a9 1438 2b8c
40b2 5f10 4e9d 0277
ed91 ddf3 c849 aa34
0387 0000 0000 0100
0000
[Recipe complete.]
[End logging on Raspberry Pi.]
Now, on Aineko, create a text file called "tx3_copied.txt" in the work directory for this project. Manually type the signed transaction data displayed on the Raspberry Pi's screen into tx3_copied.txt. Double-check the data.
Time taken: 10:04
Approximately 10 minutes.
Listening to music made this step more tolerable.
Note: Keeping the intermediate results e.g. tx3_copied.txt during the project means that if there is an error, I can go back, find it, and fix it without having to completely redo each step.
On Aineko, open a terminal and change directory to the work directory.
aineko:work stjohnpiano$ cat tx3_copied.txt | tr -d ' \n' > tx3.txt
aineko:work stjohnpiano$ echo '' >> tx3.txt
aineko:work stjohnpiano$ cat tx3.txt
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
[Recipe complete.]
So, the signed transaction tx3, now transferred to the online computer Aineko, is:
0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa3403870000000001000000
Let's check the byte length of tx3 using Python.
aineko:work stjohnpiano$ python
Python 2.7.13 (default, Dec 18 2016, 05:35:59)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = ""
>>> len(x) / 2.0
>>> 226.0
>>>
226 bytes.
Next: Retrieve w5.txt from the Raspberry Pi and copy it into this article at the appropriate earlier point. Merge various annotations / comments made here into this log.
Insert the memory stick into the Raspberry Pi.
[mount the memory stick]
[copy w5.txt to the memory stick]
[confirm that the file has been copied over]
$RECYCLE.BIN
Recycled
System Volume Information
w4.txt
w5.txt
wlog3.txt
work
work.log
work_log2.txt
[unmount the memory stick]
[confirm that it has been unmounted]
pi@raspberrypi ~/test $ sudo mount -o uid=pi,gid=pi /dev/sda1 /mnt/memory_stick_mount_point
[copy w5.txt to the memory stick]
pi@raspberrypi ~/test $ cp w5.txt /mnt/memory_stick_mount_point
[confirm that the file has been copied over]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
$RECYCLE.BIN
Recycled
System Volume Information
w4.txt
w5.txt
wlog3.txt
work
work.log
work_log2.txt
[unmount the memory stick]
pi@raspberrypi ~/test $ sudo umount /mnt/memory_stick_mount_point
[confirm that it has been unmounted]
pi@raspberrypi ~/test $ ls -1 /mnt/memory_stick_mount_point
Unplug the memory stick from the Raspberry Pi.
Insert the memory stick into Aineko. It mounts automatically and an icon appears on the Desktop. Copy the file w5.txt to the work directory for this project on Aineko.
On Aineko, right-click memory stick's Desktop icon and choose Eject "NO NAME". Unplug the memory stick from Aineko.
Integrate the contents of the file w5.txt into the marked section earlier in this article.
Done.
Shut down the Raspberry Pi for now.
On the Raspberry Pi:
pi@raspberrypi ~/test $ sudo halt
[a variety of output is printed, then the Raspberry Pi shuts down]
Unplug the power cable from the Raspberry Pi.
Switch to Aineko.
Let's see if a blockchain information service can decode this transaction.
Browse to:
live.blockcypher.com/btc/decodetx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Decode Transaction".
Result:
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"double_spend": false,
"fees": 2210,
"hash": "00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093",
"inputs": [
{
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"age": 551219,
"output_index": 25,
"output_value": 1200000,
"prev_hash": "af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2",
"script": "483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3",
"script_type": "pay-to-pubkey-hash",
"sequence": 4294967295
}
],
"outputs": [
{
"addresses": [
"36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
],
"script": "a914382b8c40b25f104e9d0277ed91ddf3c849aa340387",
"script_type": "pay-to-script-hash",
"value": 1197790
}
],
"preference": "low",
"received": "2018-11-30T18:53:12.967335417Z",
"relayed_by": "54.166.113.205",
"size": 222,
"total": 1197790,
"ver": 1,
"vin_sz": 1,
"vout_sz": 1
}
Looks good. No immediate error reported.
Some details:
- size: 222
- fee: 2210
- preference: low
- hash (txid):
00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093
Let's broadcast the signed transaction tx3.
Browse to:
live.blockcypher.com/btc/pushtx
Paste the signed transaction into the text box named "Transaction Hex". Network is set to "Bitcoin".
Click "Broadcast Transaction".
Result:
Transaction page loads:
live.blockcypher.com/btc/tx/00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093
Details:
- Transaction Successfully Broadcst
- AMOUNT TRANSACTED: 0.0119779 BTC
- FEES: 0.0000221 BTC
- Confirmations: 0/6
- Miner Preference: LOW
- Size: 222 bytes
- Version: 1
- Relayed By: 54.166.113.205
Current datetime: 2018-11-30 19:10
Set timer for 2 hours.
Timer has finished.
[some additional time passes]
Current datetime: 2018-11-30 21:47
Refresh transaction page.
Confirmations: 0/6
I'll wait until tomorrow to check again.
Current datetime:
2018-12-01 10:56
Refresh transaction page:
live.blockcypher.com/btc/tx/00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093
Confirmations: 6+
Excellent. Transaction tx3 has been mined.
Click Advanced Details.
- Block Hash:
0000000000000000000ab9373f3ce1c96528c09ffa13fe2005a4d32470b7c98b
- Block Height: 552,081
- Transaction Index: 1,941
Click API Call.
Result: tx3
{
"block_hash": "0000000000000000000ab9373f3ce1c96528c09ffa13fe2005a4d32470b7c98b",
"block_height": 552081,
"block_index": 1941,
"hash": "00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093",
"hex": "0100000001d227236f72471bd19ce1c0aa7b1c1a761efd70fb56b28efb6b6b0b26cc8838af190000008b483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3ffffffff01de4612000000000017a914382b8c40b25f104e9d0277ed91ddf3c849aa34038700000000",
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK",
"36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
],
"total": 1197790,
"fees": 2210,
"size": 222,
"preference": "low",
"relayed_by": "54.166.113.205",
"confirmed": "2018-11-30T23:27:35Z",
"received": "2018-11-30T18:55:34.661Z",
"ver": 1,
"double_spend": false,
"vin_sz": 1,
"vout_sz": 1,
"confirmations": 60,
"confidence": 1,
"inputs": [
{
"prev_hash": "af3888cc260b6b6bfb8eb256fb70fd1e761a1c7baac0e19cd11b47726f2327d2",
"output_index": 25,
"script": "483045022100f03c62521817e4faf31abd01782c7df2fcef8a2234400068f1a821b29fe129da02201185879e760fac3d9f2dbdc2e2af074c32c70088dd839108971c39905f5b5bbf0141043ab692792d6c8838fd30c2ff45bf3cbd44286a5cac52ba64dc06452810202b3206f5c7799c3b72ff77fd1976f105ced3cd7700b0412e11266f3888b88c3052c3",
"output_value": 1200000,
"sequence": 4294967295,
"addresses": [
"1vkb4YyPMFcxyC83Z5m5zuN45xASoHeNK"
],
"script_type": "pay-to-pubkey-hash",
"age": 551219
}
],
"outputs": [
{
"value": 1197790,
"script": "a914382b8c40b25f104e9d0277ed91ddf3c849aa340387",
"spent_by": "c04e603ac81372592857fefbf1ffe8b689c0d723fd007f43fb9862d171864565",
"addresses": [
"36p1w3YrNKd2Q3xaXbe9ASUQkeynjVLfDx"
],
"script_type": "pay-to-script-hash"
}
]
}
Key details:
- block_hash:
0000000000000000000ab9373f3ce1c96528c09ffa13fe2005a4d32470b7c98b
- block_height: 552081
- confirmed: 2018-11-30T23:27:35Z
- received: 2018-11-30T18:55:34.661Z
- hash (txid):
00f630f5152f4fce9831933fcd4eb878428308755f9f8e31a3135de6a4754093
Using the times from blockcypher.com:
- Broadcast time: 2018-11-30 18:55
- Confirmation time: 2018-11-30 23:27
Time taken ~= 4.5 hours
Log on to LocalBitcoins.
Go to Wallet / Transactions.
- Latest received transaction:
-- Datetime: 11/30/2018 23:57
-- Received BTC: 0.0118279
-- Description: Deposit to 36p1w3......
-- Deposit Fee BTC: 0.00015000
I have successfully transferred the relatively larger amount of stored bitcoin from the Raspberry Pi to the LocalBitcoins exchange.
Excellent.
That's the end of the project.
Now, begin writing up the analysis. There may be some clean-up / archival work, which I may document here.
I'll preserve the dice rolling results as assets of this article.
Boot up the Raspberry Pi and transfer the files:
- dice_rolls.txt
- dice_rolls2.txt
- dice_rolls3.txt
- dice_rolls4.txt
- dice_rolls5.txt
to Aineko via memory stick.
I've written recipes:
- Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction
- Recipe For Manually Mounting A USB Memory Stick
Now test them.
Boot up the Raspberry Pi.
In the home directory ("/home/pi"), make a new directory "test2".
Copy the entropy byte files from the "test" directory to the "test2" directory. These are:
- private_key.txt
- random_value2.txt
- random_value3.txt
- random_value4.txt
- random_value.txt
Note that random_value2.txt and random_value3.txt contain the same value. The value in random_value3.txt should have been derived from dice_rolls4.txt, but was accidentally derived from dice_rolls3.txt instead.
random_value.txt was used to sign tx1a.
random_value2.txt was used to sign tx1b.
random_value3.txt was used to sign tx1c.
random_value4.txt was used to sign tx3.
Copy the signed transaction files to the test2 directory as well.
Delete the "test" directory, which contains almost everything on the Raspberry Pi that I used during this project. I used the command
rm -r test
to do this. In the home directory, also delete:
- w4.txt
- w5.txt
- wlog3.txt
These were temporary backup files.
Change directory to the test2 directory.
Rename:
- signed_transaction.txt to tx1a_original.txt
- signed_transaction2.txt to tx1b_original.txt
- signed_transaction3.txt to tx1c_original.txt
- signed_transaction4.txt to tx3_original.txt
Delete the directory
/mnt/memory_stick_mount_point
. It was created with root permissions, so root permissions are required to delete it. Use the command
sudo rmdir /mnt/memory_stick_mount_point
. First, I will test:
Recipe For Manually Mounting A USB Memory Stick
because I'll also use it to transfer the code assets to the Raspberry Pi, in preparation for testing the other recipe.
Insert the memory stick into Aineko. It mounts automatically and an icon appears on the Desktop. Delete everything on it.
Make a new directory named "code_assets" on the memory stick. From the work directory in the project directory on Aineko, copy the code assets into the code_assets directory.
On Aineko, right-click memory stick's Desktop icon and choose Eject "NO NAME". Unplug the memory stick from Aineko.
Follow the recipe as closely as possible. Make a new directory named "memory_stick_contents" in the test2 directory on the Raspberry Pi. Copy the contents of the code_assets directory on the memory stick to the memory_stick_contents directory on the Raspberry Pi.
Note: This time, there's no "work.log" file to copy to the memory stick. Test this recipe section by copying private_key.txt to the memory stick, and then delete it from the memory stick.
Recipe completed. Works fine.
Next, I will test:
Recipe For Managing The Fee And Broadcast Of A Bitcoin Transaction
I won't test it completely. At the appropriate points, I'll assume that the events (e.g. transaction confirmation) occur as they did during the project.
Copy the files in the memory_stick_contents directory to the parent test2 directory. The command I used was:
cp memory_stick_contents/* .
Unpack the zipped tape archive file ecdsa-0.10.tar.gz, then copy the "ecdsa" directory into the test2 directory.
At this point, I assume that I have gathered the required data for a new transaction (step 1), and that I have looked at current Bitcoin network transaction fee rates and chosen a fee rate for the transaction (step 2). Actually, I'm re-using the values used for tx1a. The fee rate is 1 satoshi / byte.
Edit create_nonstandard_transaction.py using the Nano text editor so that its settings section (lines 40-66) are the settings originally used to create tx1a. Manually enter the gathered / chosen values (reading them from the main project log (this text file) displayed on Aineko's screen), except for the variables
random_value
and
input_data["private_key_hex"]
. - Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- The variable
input_data
is a dictionary that contains several other variables. Delete the existing value for the variable
input_data["private_key_hex"]
. Then use the Nano option "Read File" to paste the contents of the file private_key.txt into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- Note: With long strings, e.g. the txid, you can make a copy on the online computer (Aineko, in this case) and split it into groups of 4 characters, then manually copy each group over to the offline Raspberry Pi, then do a double-check of the group values, and finally delete the spaces again to form the original txid.
tx1a settings:
##### START CONTROLS
random_value = "91fbb8a38082b09e6ed984fda95866dfab95dc66b0cb6b5133dd87d07315364e"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "1" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
I used this command to direct the output of the transaction creation into a file:
python create_nonstandard_transaction.py > tx1a.txt
Then I used the Nano text editor to delete most of the contents of tx1a, leaving only the final signed form of the transaction.
This completes step 3 of the recipe.
The command
diff tx1a.txt tx1a_original.txt
produced no output, confirming that the two files are identical. At this point, I assume that I have broadcast transaction tx1a (step 4), that 2 days have passed, that it has not been mined, and that it has now been removed from the memory pool of the node run by the broadcast service (step 5).
I also assume that I have looked at current Bitcoin network transaction fee rates and chosen a new and higher fee rate for the transaction (step 6). Actually, I'm re-using the values used for tx1c. The fee rate is 66 satoshi / byte.
Note: I'm not re-constructing tx1b, as it was a double-spend attempt (it tried to spend the same unspent output as tx1a did, but to a different address, while tx1a was still in the memory pool), and it is not relevant to testing this recipe.
Edit create_nonstandard_transaction.py using the Nano text editor so that its settings section (lines 40-66) are the settings originally used to create tx1c. Manually enter the gathered / chosen values (reading them from the main project log (this text file) displayed on Aineko's screen), except for the variable
random_value
. - Delete the existing value for the variable
random_value
. Then use the Nano option "Read File" to paste the contents of the file random_value3.txt (used to sign the original tx1c) into the position of the value for this variable (i.e. between the quotation marks). Then press the Backspace key to delete the final newline of the file that was also pasted in.- The details of the input that I am trying to spend do not need to be changed. This refers to every subvariable contained in the dictionary variable
input_data
. - The output address and the change address do not need to be changed. I am trying to send the available bitcoin to the same output address.
- I only need to change the fee_rate and the random_value.
tx1c settings:
##### START CONTROLS
random_value = "644dc86dd0cb4518d9d7f68db2d6e9455e34ceeb32c897df2616418c4c9bb040"
# random_value must be between 1 and 32 bytes. If random_value_type is "raw_bytes", then random_value must be between 1 and 32 ASCII characters. If random_value_type is "hex_bytes", then random_value must be an even number of hex characters and between 2 and 64 hex characters.
# Note: Every ECDSA signature (one for each input in a transaction) requires new random entropy.
# random_value_type options: ["raw_bytes", "hex_bytes"]
random_value_type = "hex_bytes"
input_data = {
"txid": "07cedb340f588dec2fb14472178a92d5803c70d8d90fc0d8593b03f34035e2cd",
"previous_output_index": "15",
"private_key_hex": "c592e1dad5e9871fdeffb551b4544b0a1cf0378c6371d7a397ff5faf04c934ca",
#"satoshi_amount": "241777",
"bitcoin_amount": "0.0020",
"input_type": "p2pkh",
}
output_data = {
"address": "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH",
#"satoshi_amount": "241000",
"bitcoin_amount": "0.0020",
"output_type": "p2sh",
}
change_address = "369Dpo9CrJASneaHLdwWfKym7N84XTUyvH"
# note: the fee will be subtracted from the amount that is being sent to the change address.
fee = "225" # satoshi
fee_rate = "66" # satoshi / byte
# fee_type options: ["fee", "fee_rate"]
fee_type = "fee_rate"
##### END CONTROLS
I used this command to direct the output of the transaction creation into a file:
python create_nonstandard_transaction.py > tx1c.txt
Then I used the Nano text editor to delete most of the contents of tx1c, leaving only the final signed form of the transaction.
This completes another iteration of steps 2-3 of the recipe.
The command
diff tx1c.txt tx1c_original.txt
produced no output, confirming that the two files are identical. At this point, I assume that I have broadcast transaction tx1c, that it has been mined within 5 hours, and that it is now 6 blocks deep in the Bitcoin blockchain, i.e. the same events have happened as those that occurred during this project, and I have had a successful result.
Ok. I'll count that as a successful test of the recipe.
Shut down the Raspberry Pi.
I've finished writing the analysis (various sections, notes, summary). Boot up the Raspberry Pi, delete the test2 directory, and shut it down again. Insert the memory stick into Aineko and delete the work directory on it.
[start of notes]
Changes from the original text:
- I have not always preserved the format of any excerpts from webpages on other sites (e.g. not preserving the original bold/italic styles, changing the list structures, not preserving hyperlinks).
- I have not always preserved the format of any computer output (e.g. from running bash commands). Examples: Setting input lines in bold text, adding/removing newlines in order to make a sequence of commands easier to read, using hyphens for lists and sublists instead of indentation, breaking wide tables into consecutive sections.
[end of notes]