Bitcoin is a decentralised digital currency which has been growing rapidly in popularity and use. You can send bitcoins to people and businesses around the world quickly, easily, and
with significantly less fees than international wire transfers, PayPal, or credit cards. You can even buy beer almost instantly; Here is a photo of me buying beer using Bitcoin.
If you’re developing a Bitcoin application, or even want to just play around with it, you can do so without costing anything and use a minimal amount of system resources. This blog post covers some technical topics about the Bitcoin block chain, which you might want to read up on the subject beforehand.
The different Bitcoin networks
The standard Bitcoin client, Bitcoin Core has three networks it can run on: mainnet, testnet, and regtest.
This is the real Bitcoin network, with the block chain that everyone uses. You can of course experiment with this network, but there are a few downsides:
- It’s generally frowned upon to experiment on a production network. Even though it has been proven to be solid for 5 years, you might risk damaging it, or be wasting space on the block chain for no good reason.
- It costs real money—not only to buy bitcoins in the first place—but also transaction fees, even when sending bitcoins to yourself. If you were writing software that made transactions within unit tests, you could run out of bitcoins quite quickly.
- Block mining rate. Blocks are mined around every 10 minutes. It would be a waste of time to have to wait an hour for your 6 confirmations in a test environment.
- Synchronising the block chain. This behemoth is (as of April 2014) just under 20GB in size and growing.
This is the test network that runs in parallel with mainnet, except that the value of these coins are negligible. It exists to experiment with a block chain that won’t harm the mainnet block chain, e.g. with new features to Bitcoin Core. It also has the intention to be easier to mine blocks, and therefore it is essentially free to acquire testnet bitcoins.
Every now and then the developers nuke the ledger to prevent selling off testnet bitcoins, and also to reset the mining difficulty low enough so a CPU can effectively mine. Currently it is called testnet3.
The testnet runs on a different TCP port, has a different genesis block, and the Bitcoin addresses start with different letters. This is to make sure users don’t accidentally shift between the two networks. Many consideration. Super developer. Wow.
Now for the downsides of using this for your own testing:
- It is difficult to mine testnet coins. While the Bitcoin Core developers suggest not to, I suspect people are using GPUs/ASICs to mine testnet blocks in order to get their test bitcoins faster. This causes the difficulty to go up so a standard laptop is not able to mine in a small amount of time. I ran mine for around 24 hours hoping to get one block, but nothing came through.
- The other way to get testnet coins is asking people and using testnet faucets. This is a great alternative, but doesn’t really give you many bitcoins to test the new large-scale Bitcoin exchange you just made.
- The testnet3 block chain is also a mini-behemoth currently at 1.1GB. You will need to download this but even at this smaller size it is <rant size=”small” region=”first-world”>not cheap when your ADSL+ is down because of incompetent telecommunications companies, and have to rely on expensive mobile data.</rant>
New in Bitcoin Core 0.9.0, the “Regression Test” mode allows mining with practically zero difficulty and is initially disconnected from any existing network. It also has its own genesis block, and when you start your client, no peers are registered, and nothing is initially mined by anyone.
The great thing about the regtest network is that you don’t need to use a chunky amount of disk space, nor a massive amount of CPU power to mine thousands of test bitcoins. After the initialisation of the Bitcoin Core daemon, i.e. bitcoind, the whole regtest data directory is 17MB. It takes around a minute and around 2MB of extra disk space to mine 100 blocks.
This is the network we’ll be using for testing.
Building the Bitcoin docker image
Building the image takes a few minutes, so if you’re doing this interactively, let’s multi-task. After cloning the repository, hop into it and run:
The Dockerfile sets up the Bitcoin PPA which at the time of writing is version 0.9.0. There is a version 0.9.1 which was released specifically to handle the Heartbleed bug. Apparently version 0.9.0 is safe from the vulnerability due to the fact that it symbolically links to the OpenSSL library. As long as your OpenSSL library is up to date, and you don’t expose your RPC port, you should be safe.
We are going to run two docker instances, one for Alice and one for Bob. Both containers will run their own Bitcoin peer using bitcoind, and initially the only thing in common will be the regtest genesis block which is hard-coded in Bitcoin Core.
Your Own Bitcoin Network
After the docker image is built, load up two shells/terminals, preferably with a window split so you can see both at once. Run the following commands in their own windows:
Here’s a screenshot of approximately what you should be seeing:
Once you’re in, you should have bitcoind in your path. Start bitcoind on both containers like so:
I have set up an alias in the container’s .bashrc called “rt” which is a short-cut to “bitcoind -regtest”. The rest of the examples will use this. Using rt, this is the equivalent of the previous command:
You can run some commands to check out the state of the regtest network. Right now there are no mined blocks, and no peers connected. For example:
The output of getpeerinfo above shows that there are no connected peers. Let’s change that and make Bob get in touch with Alice. To tell bitcoind about Alice, we tell Bob to manually add Alice as a peer using Alice’s IP address.
A log entry in both peers should appear similar to the following. If not, try it again or wait a bit.
Now, when running getpeerinfo on Alice, we can see Bob as a listed peer:
Now that we have a two node Bitcoin network, let’s mine some blocks!
Just on Alice, run setgenerate, and once that is done, check out your new, freshly mined 50 bitcoins:
Block rewards are released after 100 confirmations (why?), so on the 101st block mined, we should have 50 BTC available to spend. Here is a screenshot of the output of Alice and Bob, after Alice mining, and after Bob syncing the mined blocks.
Let’s send some of this to Bob! On Bob’s instance, let’s grab a new address to receive to:
Notice how the address “mm47sczsEDYAGF2fp7xHSRpWQzCvpE1eZt” starts with an “m” instead of a “1”? This is that extra safety feature I mentioned earlier to not to mix mainnet with the testing networks.
On Alice’s instance, we can use this address to send 42 bitcoins to Bob:
Now Alice has 8 bitcoins remaining, but Bob’s getbalance command still shows 0. This is because there hasn’t been at least 6 confirmations yet. To do this, just get one of the nodes to quickly mine 6 blocks:
And the final screenshot shows Bob just received 6 blocks and his balance is now 42 bitcoins:
Apart from unit testing, continuous integration, and staging environments, a configuration like this leads to many interesting things you can do. For example you can try the same experiment above without initially connecting the two nodes together. The beauty of the block chain is that Bob gets paid even if he’s not connected to the network. He will be able to spend his new coins when he synchronises with the network.
You can also try a similar set up, where you can “race” block mining between two disconnected nodes to create a large fork in the block chain. Get Alice and Bob to mine 10 blocks each, then after you make them contact each other, you’ll see interesting errors when they synchronise. Even more interesting log entries show up after a fork split of 30 or more confirmations.
The Makefile also has alice_daemon and bob_daemon commands which runs the bitcoind daemon detached as RPC servers, so you can experiment with an RPC client too. Please note that it will listen to RPC on all ports, unencrypted, with the username test and password test. I highly recommend at least changing the username/password, and restricting remote access to the port.
The files used in this blog post are on github for your pleasure and I’m happy to accept pull requests for any issues or handy new features.