I wanted the second session to be practical, so I decided to tinker with the Electrum wallet to drive home some of the Bitcoin transactions concepts introduced in the theoretical session. I decided to go with Electrum over Bitcoin Core because it is lightweight: installation and setup is faster as there is not need to download the blockchain. On the other hand, Bitcoin Core has a lot of functionality readily available to explore the blockchain. A third session on blockchain exploration using Bitcoin Core would be the natural next step.
After loading the wallet with some Bitcoin, we turned to the console view of Electrum. First we checked the addresses available:
>> listaddresses()
[
"18tc1LCXMSAGPziTk3HuUKKUQ286uyiMd7",
"1Jc4645oAT1T4b11aBVFL84ejVsmWkKs1n",
"1FwX6t96ab2KKuMHehRF3CR1K3mtxCVtXo",
"1Chp3HR94Z7ZsjG9nHFhz5BPNrjypoiHw5",
"19DCsPuYcJ69p8Hfk2RsXrfSQTFQkBbL1S"
]
>> getseed()
{
"mnemonic": "unable beard giant feather nobody special pants also stop decide hallway slide",
"seed": "d95a9af9f0e3241bc778909fd4f7eebb",
"version": 4
}To retrieve the private key associated with a public key we can use the command dumpprivkey:
>> dumpprivkey("1CaPam1wUfJttt5Gkd71wzifVdjxrE9W7o")
[
"5JxQWPa2sqxBfyyyFhRKdQFKRb47FNVuhBed7YtVg5xFada4UC1"
]Now, lets see what is the balance of our wallet:
>> getbalance()
{
"confirmed": "0.001"
}And the unspent transaction outputs where this balance comes from:
>> listunspent()
[
{
"address": "18tc1LCXMSAGPziTk3HuUKKUQ286uyiMd7",
"coinbase": false,
"height": 0,
"is_pubkey": false,
"prevout_hash": "1c27a5ec75e4e4367f0074edded0659d33b86d52dc8683086aa248716f0261da",
"prevout_n": 0,
"scriptPubKey": "76a914568b50da42f77d267a037c5dc9ad90ff863af0d488ac",
"value": "0.001"
}
]Notice the scriptPubKey of the transaction: "76a91...". This is the computational puzzle that anyone wishing to spend this transaction output must solve, which in this case means signing with the private key associated with the address "18tc1...".
Also, notice the hash of the transaction, that serves as the transaction id: "1c27a...". A following transaction that spends this transaction would reference this hash.
Let's go ahead and create another transaction spending 0.5 mBTC to address "1Jc46...". To achieve this, we have first to create a transaction (using the createrawtransaction command), then request Electrum to sign it (using the signrawtransaction command), and finally publish it to the blockchain (using the sendrawtransaction command). Of course, these three functions are performed by Electrum when sending bitcoins through the GUI, but it is more instructive (and fun :) ) to perform them by hand:
>> tx = wallet.make_unsigned_transaction([("1Jc4645oAT1T4b11aBVFL84ejVsmWkKs1n", 50000)], None, None, None)
This creates a transaction sending 0.5 mBTC to address "1Jc46...". Electrum chooses the unspent transaction outputs to create the transaction. The decision is straightforward in this case as there is only one unspent transaction output available in the wallet. Lets see the transaction created by Electrum:
>> decoderawtransaction(tx.raw)
This creates a transaction sending 0.5 mBTC to address "1Jc46...". Electrum chooses the unspent transaction outputs to create the transaction. The decision is straightforward in this case as there is only one unspent transaction output available in the wallet. Lets see the transaction created by Electrum:
>> decoderawtransaction(tx.raw)
{
"inputs": [
{
"address": null,
"prevout_hash": "1c27a5ec75e4e4367f0074edded0659d33b86d52dc8683086aa248716f0261da",
"prevout_n": 0,
"sequence": 4294967295,
"signatures": []
}
],
"lockTime": 0,
"outputs": [
{
"address": "1Jc4645oAT1T4b11aBVFL84ejVsmWkKs1n",
"is_pubkey": false,
"prevout_n": 0,
"scriptPubKey": "76a914c11b46240cb97ad18fd08e472c299296324819de88ac",
"value": 50000
},
{
"address": "15AuBAcN96nDH3FXZFtG3m5ySfG85w5qJ9",
"is_pubkey": false,
"prevout_n": 1,
"scriptPubKey": "76a9142dbfccee75eaed84d180d800499ceab579fbd0c288ac",
"value": 30000
}
],
"version": 1
}
The transaction has one input (the only unspent transaction output in the wallet), with transaction id "1c27a...", and two outputs:
"1Jc46...": 0.0005
"15AuB...": 0.0003
Where the values in the transactions are expressed, as is standard, in satoshis (1 satoshi = 10e-8 bitcoins = 0.00000001 bitcoins). Although we only wanted to send bitcoins to the address "1Jc46...", Electrum creates a transaction with two outputs. The reason is that all transaction outputs must be fully spent. Therefore, Electrum sends the requested 0.5 mBTC to addess "1Jc46...", and the rest (0.3 mBTC) to a new address in the wallet. Why send the change to a new address and not the original address "18tc1..."? Electrum by default does not reuse addresses, to increase privacy. Why 0.3 mBTC, where are the other 0.2 mBTC? These are the fees left to the miners.
Also note that the signature to the input is set to null, thus the transaction is not finalized and cannot be send yet. To finalize it, lets create a list with the private keys associated with the addresses with associated unspent funds:
>> private = [pr[0] for pr in dumpprivkeys( public )]
>> txsigned = signrawtransaction(tx.raw, tx.get_input_info(), private)
"1Jc46...": 0.0005
"15AuB...": 0.0003
Where the values in the transactions are expressed, as is standard, in satoshis (1 satoshi = 10e-8 bitcoins = 0.00000001 bitcoins). Although we only wanted to send bitcoins to the address "1Jc46...", Electrum creates a transaction with two outputs. The reason is that all transaction outputs must be fully spent. Therefore, Electrum sends the requested 0.5 mBTC to addess "1Jc46...", and the rest (0.3 mBTC) to a new address in the wallet. Why send the change to a new address and not the original address "18tc1..."? Electrum by default does not reuse addresses, to increase privacy. Why 0.3 mBTC, where are the other 0.2 mBTC? These are the fees left to the miners.
Also note that the signature to the input is set to null, thus the transaction is not finalized and cannot be send yet. To finalize it, lets create a list with the private keys associated with the addresses with associated unspent funds:
>> public = map(lambda x:x.get('address'), listunspent())
['18tc1LCXMSAGPziTk3HuUKKUQ286uyiMd7']
>> public
>> private
['5JxQWPa2sqxBfyyyFhRKdQFKRb47FNVuhBed7YtVg5xFada4UC1']
The private key "5JxQW..." corresponds to the address "18tc1...". We can now sign the transaction with this private key:>> txsigned = signrawtransaction(tx.raw, tx.get_input_info(), private)
The variable txsigned contains the signed transaction:
The part in bold (76a9142dbfccee75eaed84d180d800499ceab579fbd0c288ac) is the signature to the unspent transaction output. Finally, lets send the signed transaction to the network:
The response to the sendrawtransaction command is the transaction id: "65c2d...". Finally, lets take a look at the list of unspent transaction outputs again:
As expected there are now two addresses with associated unspent funds: "1Jc46..." with 0.5 mBTC and the change address "15AuB..." with 0.3 mBTC.
Of course, all this could have been easily accomplished through the GUI:
>> txsigned.raw
"0100000001da61026f7148a26a088386dc526db8339d65d0deed74007f36e4e475eca5271c000000008b483045022100a83c4163b62573625e919cf440243365a0a2c4ceb2ca3c51727928786b4e394b02206379678a8e8e76e85dcd8472b86197bc5f28ede3a34ed6bda6c5312736ee005d014104786afa5fa718aa563d51eb305ccf097359145fa99e389484e69c3aa4617786a936da6837e2890448918f4d5b1cbfe132b9e210e0a3b43a2fd766ffe7d7f4c7e7ffffffff0230750000000000001976a9142dbfccee75eaed84d180d800499ceab579fbd0c288ac50c30000000000001976a914c11b46240cb97ad18fd08e472c299296324819de88ac00000000"
>> sendrawtransaction(txsigned.raw)
"65c2d3d164b36b9926705069043ab8d40df6187b023791d7ee53900aad4486ad"The response to the sendrawtransaction command is the transaction id: "65c2d...". Finally, lets take a look at the list of unspent transaction outputs again:
>> listunspent()
[
{
"address": "15AuBAcN96nDH3FXZFtG3m5ySfG85w5qJ9",
"coinbase": false,
"height": 0,
"is_pubkey": false,
"prevout_hash": "65c2d3d164b36b9926705069043ab8d40df6187b023791d7ee53900aad4486ad",
"prevout_n": 0,
"scriptPubKey": "76a9142dbfccee75eaed84d180d800499ceab579fbd0c288ac",
"value": "0.0003"
},
{
"address": "1Jc4645oAT1T4b11aBVFL84ejVsmWkKs1n",
"coinbase": false,
"height": 0,
"is_pubkey": false,
"prevout_hash": "65c2d3d164b36b9926705069043ab8d40df6187b023791d7ee53900aad4486ad",
"prevout_n": 1,
"scriptPubKey": "76a914c11b46240cb97ad18fd08e472c299296324819de88ac",
"value": "0.0005"
}
]As expected there are now two addresses with associated unspent funds: "1Jc46..." with 0.5 mBTC and the change address "15AuB..." with 0.3 mBTC.
Of course, all this could have been easily accomplished through the GUI: