In order to test the bloXroute BDN in realistic circumstances, it wasn’t enough to pump artificial transactions through the network. Instead, we wanted to connect it to real functioning networks to see how it would do under everyday conditions, which may include misbehaving peers, corrupted or invalid blocks, and so on.
bloXroute’s mission is to serve any blockchain, so we set out to test a variety of existing clients in real world conditions. Each node contains a dockerized version of the client in question, alongside a bloXroute Gateway client. The bloXoute Gateway acts as a standard peer to that blockchain node (the node doesn’t know it’s talking to something special). The gateway relays transactions and blocks to and from each node, using the bloXroute BDN to transmit this information.
Today, we run real blockchain nodes of the following flavors: Bitcoin Core Testnet, Bitcoin Core Mainnet, Bitcoin Cash Testnet, Bitcoin Cash Mainnet, Ethereum Mainnet, Ethereum Ropsten, Ethereum Rinkeby, with plans to expand to lots more. This article will focus on how we automate the creation of Ethereum nodes, though the same idea applies to Bitcoin nodes, or any other nodes we create in the future.
The problems we needed to solve are:
- The ability for developers to specify which docker container they wanted to run, so they could easily inject any version of the blockchain client they were interested in
- Management of backups, so that we could quickly spin up nodes that were close to synced to chain tips and avoid long startup times
- Injection of runtime params specific to the blockchains under test
We start with a terraform file for creating the ethereum node. For more details on how this works, we recommend reading the three-part series (https://medium.com/bloxroute/terraforming-bitcoin-testnets-part-1-3-40460946d4ef) on how we terraformed bitcoin testnets. Although the code has changed a bit since then, the basic idea remains the same.
In this terraform file, we create an ethereum instance. A few important things to note are the injection of eth_network and geth_docker_image, which will allow us to configure the node to connect to the net we want. We also boot that node from a pre-existing ami, which we specify through a variable (ami_name). This allows us to fuzzily match to the latest backup we have of the chain state. Finally, we figure out what difficulty to use, since each chain requires its own starting difficulty param. Let’s take a look at the boot script:
The boot script takes care of figuring out which chain we want to launch, injecting those params from terraform tags, and launching the docker container in question. Because the container is injectable, it makes it easy for us to launch different versions of geth. The simplified instantiation of this module looks something like this:
Notice the wildcard specification of ami_name. This allows us to take nightly snapshots of our blockchain nodes and store them as amis. Then, by simply launching a new node, you boot an instance that is already synced to close to the chain tip. Assuming it’s only about a day out of date, it will take a few minutes to sync and run properly.
That’s it! This is the general technique we use to spin up nodes from all flavors of ethereum and bitcoin clients, with minor modifications for the blockchain in question. In reality, since we want to test real world conditions, we actually have to run nodes in every geographical region of the world. Because of this, our terraform is actually significantly more complicated than the above, and involves the specification of per-region node deployments. Stay tuned for a future post discussing multi-region networking and deployments with terraform.