Supercharged Ethereum Main Net Testing on your own Node with Brownie.

matnad
4 min readMay 12, 2020

If you are working with smart contracts and haven’t heard of Brownie yet, do yourself a favor! In Ben’s latest article he talks about why and how you can test your smart contracts on a forked main net. Before you continue here, make sure you followed along that article since we will be going a bit more in-depth here and find out just how far we can push it.

There is one minor downside in using the built-in --fork main-net network. While it is easy to set-up and use, it relies on Infura as RPC provider. This will work perfectly fine for smaller projects, but eventually you will notice that Infura is significantly slower at processing transactions than a local RPC and/or you will start to hit the limit of 100'000 requests/day. Before you decide to pay money and upgrade your Infura account, consider another option:

Run your own Ethereum node and use it as a lightning fast RPC!

Setting up your own node

For this example, we will be setting up a full Ethereum node with geth on a Debian based OS. If you already have a full node ready or would like to follow a more detailed tutorial, feel free to skip ahead!

A note on hardware for your own Ethereum node:
You need an SSD with at least 300 GB of space. This is the most common bottleneck for sync speed and it pays off to go for an M.2 NVMe SSD with an r/w speed of 3000 MB/s or more.
The CPU will generally be the next bottleneck for sync speed and if you don’t mind the sync taking a bit longer, almost any old hardware you have lying around will do.

Let’s get to setting up our node.

  1. Install geth your preferred way
  2. Create the file /etc/systemd/system/geth.service and set it up like this:
[Unit]
Description=Geth Node
After=network.target auditd.service
Wants=network.target
[Service]
WorkingDirectory=<geth user WD>
ExecStart=/usr/bin/geth --syncmode fast --cache 4048
User=<geth user>
Group=<geth group>
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
RequiredBy=swarm.service
Alias=geth.service

3. Start the service withsudo systemctl start geth.service and see if it started syncing with less +F /var/log/syslog . Alternatively you can geth attach the geth console and check with eth.syncing .

4. Wait for the node to sync. Depending on your setup this can take anywhere from a day to a week. Unfortunately we have to wait for the sync to complete before we can use the node in Brownie.

Preparing the node for use in Brownie

Once your node is fully synced, eth.syncing shows false , open your geth.service file and modify the ExecStart line as follows:

ExecStart=/usr/bin/geth --syncmode full --cache 4048 --rpc --rpcport "9545" --rpcaddr "127.0.0.1"

If you are running the node on another machine in the same local network, instead set --rpcaddr to the local IP of the node. In my case that is --rpcaddr "192.168.1.16" .

Update and restart the service:

sudo systemctl daemon-reload
sudo systemctl restart geth.service

Preparing Brownie to use the node

To use this node in Brownie, we first Install Brownie and then add our node as a new network:

brownie networks add development geth-node host="http://127.0.0.1" name="Ganache-CLI (Geth Mainnet Fork)" cmd="ganache-cli" port=8545 gas_limit=10000000 mnemonic="brownie" fork="http://127.0.0.1:9545"

Make sure the url and port of the fork parameter correspond to the --rpcaddr and --rpcport settings above. For me that would be fork="http://192.168.1.16:9545" .

Alternatively, you can open ~/.brownie/network-config.yaml and add the network manually:

- name: Ganache-CLI (Geth Mainnet Fork)
id: geth-node
host: http://127.0.0.1
cmd: ganache-cli
cmd_settings:
fork: http://192.168.1.16:9545
gas_limit: 10000000
port: 8545
accounts: 10
mnemonic: brownie

Note: The port numbers for the fork and the ganache-cli parameters need to be distinct, even when connecting to a node in the local network.

Fork the node and start testing!

Finally, all the setup is done and we can launch the Brownie console and see if everything worked!

brownie console --network geth-node
>>> rpc.mine()
'Block height at 10053255'

Sweet!

I’ve promised you our node will be faster than Infura… lets put that to the test. Assume we want to set up our test environment by minting 300 GasToken2. Create the file tests/test_gst2.py:

And run it with:

brownie test --network geth-node

Nice, that runs in seconds. Now compare that with Infura (make sure to set your Infura environment variable):

> brownie test --network mainnet-forkFAILED tests/test_gst2.py::test_mint_gst2 - requests.exceptions.ReadTimeout: HTTPConnectionPool(host='127.0.0.1', port=8545): Read timed out. (read timeout=30)

Oops… Infura timed out.

Let’s split it up into minting ten times 30 GST2. Replace the test with:

Again, run it with brownie test --network geth-node and brownie test --network mainnet-fork . On my setup that is a difference between 20 seconds and over 2 minutes! If we account for the roughly 15 seconds overhead to start and terminate pytest and ganache-cli and only look at the test execution time, our local geth-node is more than 20 times faster!

If you like what you are reading…

To learn more about Brownie and keep up to date with all the new features in development, please follow their Twitter account and read Ben’s other Medium articles. You can also say hi on Gitter if you have any questions about using pytest, working in fork mode, or anything else related to Ethereum or Python development.

--

--