So you’ve started developing an Ethereum project and TestRPC has worked wonderfully. Now you’re ready to set up a CI/CD pipeline as you onboard more team members or get ready for your first public network deployment. Or maybe you want to start testing some more advanced features that aren’t available without a full-fledged test network. This post will walk you through the initial steps required to deploy a private blockchain development environment using Docker.
There are a few options for running your own Ethereum test network for local development. This tutorial uses Geth, but it’s not the only option. Geth is our preferred Ethereum implementation. It’s the most widely-used client and is well supported.
The goal here is to be able to test your applications locally without the use of the public Ethereum network. Transactions on the public network include a monetary cost, and the public test network can cause proprietary business logic to leak due to bugs. So the more you can do in your own environment to validate your smart contracts and DApps before deploying to a public network, the better. Also, the closer you can get to a public network, the less likely you’ll run into issues later. It’s important to note that while this tutorial focuses on deploying a private network, it does not adequately implement the best practices required for a production-level private network. With that in mind, this tutorial should be used for development only.
If this is your first experience with smart contracts and Ethereum in general, we highly recommend reading the Ethereum White Paper for an overview (and the Yellow Paper for extra credit). We also suggest doing a few smart contract tutorials offered by the Ethereum Foundation before proceeding.
To begin, there are some prerequisites that must be installed.
- Truffle Framework
In this example, we will be using the Truffle Framework for testing and deploying our smart contracts. For more information, check out Truffle’s official tutorial. For simplicity, we’ll use the default Truffle example generated by running truffle init, but feel free to use your existing Truffle project if you have one.
First, we’ll clone the Github repo for this post:
From here, you’ll see two directories, Geth and Truffle. First, we’ll focus on getting our network up. We’ve created a simple Dockerfile that inherits the official Geth container, does some bootstrapping and launches Geth with a single threaded miner. The idea here is to create a bootstrapped Docker image containing predefined information, making it easily reusable in CI/CD pipelines. There are two options for creating this image. The current defaults will generate a new account with the password of ‘test’ and output the address. You should provide a PASSWORD build argument to change this default password:
docker-compose build –build-arg PASSWORD=$PASSWORD geth
However, if you plan to rebuild this image often, you may want to consider providing the account information yourself. To do this, copy an Ethereum UTC JSON Keystore file into the images keystore folder, as well as providing the ADDRESS as a build arg. You can add as many UTC JSON files as you want. The ADDRESS build argument is used to set the address used for mining proceeds:
cp <UTC JSON Keystore file> geth/data/keystore
export ADDRESS=<The address from your UTC file>
export PASSWORD=<The password for your wallet>
docker-compose build –build-arg ADDRESS=$ADDRESS geth
For more advanced settings, you can alter the values in the geth/data/config.toml file. Please note that Docker build will overwrite the Etherbase setting in config.toml. The image build will take ~2 minutes to complete. This is largely due to generating the initial DAG to prevent having to do it when we deploy containers.
That’s it! Now you can create a container from your image:
You’ll notice that the container will immediately start mining blocks and the proceeds will be given to your account.
Truffle makes developing Ethereum contracts and DApps exceptionally easy. However, it generally assumes that the address being used is already unlocked. This isn’t usually an issue when you are doing local development. Especially if you are using TestRPC or another test network that automatically unlocks accounts. Yet, if you want to deploy to a custom private network, public test network, or even the real deal, you may not want to have to manually unlock your account before deploying.
We’ve made some simple changes to the truffle config file in truffle/truffle.js to accept TRUFFLE_ACCOUNT and TRUFFLE_ACCOUNT_PASSWORD environment variables, which will be used during contract migrations. These should match what you provided to the Docker image or a different address you’ve added to the network. We’ve also added a small library that will unlock an account and wait to proceed until the account has some ether available. You can find it in truffle/unlock.js. This is especially useful if you attempt to deploy truffle contracts before mining the first block. You can see how we utilize this library in the truffle/migrations/ files. Feel free to adapt this to meet your needs.
Here is an example of using our modified truffle project:
The biggest benefit of using the above approach is allowing you to use predictable account addresses in your dapps while still allowing full testing of unlocking existing accounts. Also note that this is a lightweight way to test WebSocket support, which isn’t yet supported by TestRPC.