A short guide on how to instantiate a configurable local Ethereum testnet and use it for dApp prototyping and testing
This guide walks you through the process of instantiating a configurable local Ethereum testnet, deploying a smart contract to it, and using the testnet to run tests against your dApp. This guide is designed for dApp developers who want to develop and test their dApps locally against different network configurations before deploying to a live testnet or the mainnet.
In this guide, you will:
Kurtosis is a composable build system designed for configuring multi-container test environments. It specifically enables developers to create reproducible environments that require dynamic setup logic, such as blockchain testnets.
In this guide, the Kurtosis eth-network-package spins up a local Ethereum testnet with support for the geth Execution Layer (EL) client, as well as teku, lighthouse, and lodestar Consensus Layer (CL) clients. This package serves as a configurable and composable alternative to networks in frameworks like Hardhat Network, Ganache, and Anvil. Kurtosis offers developers greater control and flexibility over the testnets they use, which is a major reason why the Ethereum Foundation used Kurtosis to test the Merge and continues to use it for testing network upgrades.
Before you proceed, make sure you have:
To spin up a local Ethereum testnet, run:
Note: This command names your network: “local-eth-testnet” using the --enclave flag
Kurtosis will print the steps its taking under the hood as it works to interpret, validate, and then execute the instructions. At the end, you should see an output that resembles the following:
Congratulations! You used Kurtosis to instantiate a local Ethereum testnet, with a CL (lighthouse) and EL client (geth), over Docker.
In this section, you executed a command that directed Kurtosis to use the eth-network-package hosted remotely on GitHub to spin up a local Ethereum testnet within a Kurtosis Enclave. Inside your enclave, you will find both "file artifacts" and "user services".
The file artifacts in your enclave include all the data generated and utilized to bootstrap the EL and CL clients. The data was created using the prelaunch-data-generator service built from this Docker image
User services display all the containerized services operating in your enclave. You will notice that a single node, featuring both an EL client and a CL client, has been created.
Now that you have a running local testnet, you can connect your dApp development environment to use your local testnet. The Hardhat framework will be used in this guide to deploy a blackjack dApp to your local testnet.
To set up your dApp development environment, clone the repository that contains our sample dApp and install its dependencies, run:
The smart-contract-example folder used here contains the typical setup for a dApp developer using the Hardhat framework:
With your dApp development environment set up, you will now connect Hardhat to use the local Ethereum testnet generated using Kurtosis. To accomplish this, replace <PORT> in the localnet struct in your hardhat.config.ts config file with the port of the rpc uri output from any el-client-<num> service. In this sample case, the port would be 64248. Your port will be different.
Example in hardhat.config.ts:
Once you save your file, your Hardhat dApp development environment is now connected to your local Ethereum testnet! You can verify that your testnet is working by running:
The output should look something like this:
This confirms that Hardhat is using your local testnet and detects the pre-funded accounts created by the eth-network-package.
With your dApp development environment fully connected to the local Ethereum testnet, you can now run development and testing workflows against your dApp using the local testnet.
To compile and deploy the ChipToken.sol smart contract for local prototyping and development, run:
The output should look something like:
Now try running the simple.js test against your local dApp to confirm each player in our Blackjack dApp has 1000 minted for them:
The output should look something like this:
At this point, you’ve now set up a dApp development environment, connected it to a local Ethereum network created by Kurtosis, and have compiled, deployed, and ran a simple test against your dApp.
Now let’s explore how you can configure the underlying network for testing our dApps under varying network configurations.
Your local Ethereum testnet can be configured to use different EL and CL client pairs, as well as a varying number of nodes, depending on the scenario and specific network configuration you want to develop or test. This means that, once set up, you can spin up a customized local testnet and use it to run the same workflows (deployment, tests, etc.) under various network configurations to ensure everything works as expected. To learn more about the other parameters you can modify, visit this link.
Give it a try! You can pass various configuration options to the eth-network-package via a JSON file. This network params JSON file provides the specific configurations that Kurtosis will use to set up the local Ethereum network.
Take the default configuration file and edit it to spin up three nodes with different EL/CL pairs:
This configuration creates a heterogeneous network of Ethereum node implementations for testing your dApp. Your configuration file should now look like:
Each participants struct maps to a node in the network, so 3 participants structs will tell Kurtosis to spin up 3 nodes in your network. Each participant struct will allow you to specify the EL and CL pair used for that specific node.
The network_params struct configures the network settings that are used to create the genesis files for each node as well as other settings like the seconds per slot of the network.
Save your edited params file in any directory you wish (in the example below, it is saved to the desktop) and then use it to run your Kurtosis package by running:
TIP: Note that the kurtosis clean -a command is used here to instruct Kurtosis to destroy the old testnet and its contents before starting a new one up.
Again, Kurtosis will work for a bit and print out the individual steps that are taking place. Eventually, the output should look something like:
Congratulations! You’ve successfully configured your local testnet to have 3 nodes instead of 1. To run the same workflows you did before against your dApp (deploy & test), perform the same operations we did before by replacing the <PORT> in the localnet struct in your hardhat.config.ts config file with the port of the rpc uri output from any el-client-<num> service in your new, 3-node local testnet.
And that's it! To recap this short guide, you:
We’d love to hear from you on what went well for you, what could be improved, or to answer any of your questions. Don’t hesitate to reach out via Github or email us!
We encourage you to check out our quickstart (where you’ll build a Postgres database and API on top) and our other examples in our awesome-kurtosis repository where you’ll find examples, including packages for: