Setting up an EVM compatible blockchain on Cosmos
Using Evmos to stand up a private blockchain network with EVM compatibility
If you haven’t heard about it already, Cosmos is a decentralized network that aims to bridge independent blockchains together to easily allow horizontal scaling.
To create a test EVM compatible private blockchain on top of Cosmos, currently the best option is to use Evmos, a proof-of-stake blockchain that is EVM compatible and built on Cosmos SDK.
This post will go over step-by-step on how to set up Evmos on a Ubuntu host. While the Evmos website does provide a quick start on how to run a Evmos testnet, many of the commands in the website were broken or uninformative during the time of my experimentation. Until the Evmos website and setup code is fixed, I hope this post will help those struggling to run a test blockchain on Cosmos.
Standing up the blockchain
Preparing the host
SSH into the host. If you are using AWS EC2, make sure to select Ubuntu when selecting the platform.
Setup golang
Install golang
wget -c https://golang.org/dl/go1.17.5.linux-amd64.tar.gzsudo tar -C /usr/local -xvzf go1.17.5.linux-amd64.tar.gzmkdir -p ~/go_projects/{bin,src,pkg}
Set go environment variables
Add the following lines to
$HOME/.profile
export PATH=$PATH:/usr/local/go/binexport GOPATH="$HOME/go_projects"export GOBIN="$GOPATH/bin"export PATH=$PATH:$GOPATH/bin
Don’t forget to
source ~/.profile
Check go version
go version # Output should be: "go version go1.17.5 linux/amd64"
Setup
gcc
,jq
, andmake
sudo apt install gcc sudo apt-get update sudo apt-get install jq sudo apt install make # To install docker (since the Evmos tutorial has examples on docker), follow steps in: # * https://docs.docker.com/engine/install/ubuntu # * https://docs.docker.com/compose/install # If you are going to run docker with the sudo command, # modify or comment out the "env_reset" and "secure_path" lines # in the /etc/sudoers file.
Steps on running Evmos on a single node
Install Evmos
Install the latest Ethermint repository
git clone https://github.com/tharsis/ethermint.git cd ethermint make install
Check installation
ethermintd -h
Run a local node for Evmos
./init.sh
The console output should look like the following:
5:54PM INF received proposal module=consensus proposal=... {truncated} 5:54PM INF received complete proposal block hash=127C91E3EFFE5B992874280EE140E448F38D42DA6D1E243895BCA996D2214F2D height=17 module=consensus server=node 5:54PM INF finalizing commit of block hash=127C91E3EFFE5B992874280EE140E448F38D42DA6D1E243895BCA996D2214F2D height=17 module=consensus num_txs=0 root=3F30260CA9E5F2F7F7C49F8D9DB5ED723E2AF70D856AD34E66E446E1ED915F24 server=node 5:54PM INF minted coins from module account amount=2059731934472497943aphoton from=mint module=x/bank
Single machine RPC call access test
ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key mykey --chain-id ethermint-1
Running JSON-RPC server on Evmos
Enable server
ethermintd start # in a different terminal: ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key mykey --chain-id 8
Return current ethereum protocol version
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_protocolVersion","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 {"jsonrpc":"2.0","id":1,"result":"0x41"}
Steps on running Ethermint on multiple nodes
Automated testnet
Clone the old Evmos repository (the latest repository commands are broken)
# To create the automated testnet, we must use the old repository git clone https://github.com/cosmos/ethermint.git cd ethermint make install
Follow steps in the old Evmos website, or create an automated testnet through Docker with the commands below:
Start the localnet through Docker
make localnet-start
Verification
# It should look something like this: Creating network "ethermint_localnet" with the default driver Creating ethermintdnode3 ... done Creating ethermintdnode0 ... done Creating ethermintdnode1 ... done Creating ethermintdnode2 ... done # To see files created in each node, check the build folder. # Check logs through: docker exec ethermintdnode0 tail ethermintd.log # daemon logs docker exec ethermintdnode0 tail ethermintcli.log # REST & RPC logs # Following logs: docker logs -f ethermintdnode0
Stop the local net by using the command
make localnet-stop
Manual testnet: Option #1
Clone the old Evmos repository
# To create the automated testnet, we must use the old repository git clone https://github.com/cosmos/ethermint.git cd ethermint make install
Create a single node
Create a single node, node 1, with
init.sh
Deploy other nodes
Create another node, node 2, on another instance with with
init.sh
.Copy the
~/.ethermintd/config/genesis.json
file from node 1 and paste it over to node 2.
Set seeds
Get node ID of node 1 using
ethermintd tendermint show-node-id
.Construct the seed of node 1 using the format
${nodeID}@${IP address}:26656
Add the seed of node 1 to the file
~/.ethermintd/config/config.toml
of node 2, by inserting the seed intoseeds
.
Allow nodes to talk to each other
Modify the firewall (for AWS, modify the EC2 security group) of node 1 to allow traffic from node 2.
Start the nodes
Start node 1 first, then start node 2.
Use command
ethermintd start —pruning=nothing —rpc.unsafe —log_level “main:info,state:info,mempool:info” --trace
The two nodes should be synchronized. Synchronization can be verified when the app hashes for committed states will be equal to each other.
Manual testnet: Option #2
Clone the old Evmos repository
# To create the automated testnet, we must use the old repository git clone https://github.com/cosmos/ethermint.git cd ethermint make install
Create the Ethermint configuration and genesis file for each node using the
ethermintd
command, which can take in a list of addresses (--ip-addrs
), number of nodes (-v
), and type of keyring (--keyring-backend
).Run the
ethermintd
commandethermintd testnet --ip-addrs=172.31.5.94,172.31.12.215,172.31.1.32,172.31.7.5,172.31.7.53 --v 5 --keyring-backend=file
The generated files should be in the
build
directory of where you ran the command.
Make the following directories in each instance:
mkdir /home/ubuntu/.ethermintd/ mkdir /home/ubuntu/.ethermintd/config/ mkdir /home/ubuntu/.ethermintd/config/gentxs/ mkdir /home/ubuntu/.ethermintd/data/ mkdir /home/ubuntu/.ethermintcli
scp the generated file to each instance (add the
-i /home/ubuntu/ubuntu.pem
flag for EC2 instances):sudo scp -r /home/ubuntu/testnet/build/node4/ethermintd/config/* ${hostname}:/home/ubuntu/.ethermintd/config/ sudo scp -r /home/ubuntu/testnet/build/node4/ethermintd/data/* ${hostname}:/home/ubuntu/.ethermintd/data/ sudo scp -r /home/ubuntu/testnet/build/gentxs/node4.json ${hostname}:/home/ubuntu/.ethermintd/config/gentxs/ sudo scp -r /home/ubuntu/testnet/build/node4/ethermintcli/keyring-test-ethermint/ ${hostname}:/home/ubuntu/.ethermintcli/
Run the nodes for each instance with
ethermintd start
If the nodes tries to connect to itself and fails, remove itself from
~/.ethermintd/config/address.json
Final notes
Evmos has moved from https://github.com/cosmos/ethermint to https://github.com/tharsis/ethermint. However, the official website’s tutorial corresponds to the the old version of Evmos, and so there will be conflicts/command that will not work.
Looking at Tendermint docs may be more useful than Ethermint’s. There isn’t a 1:1 correlation in the commands/settings, but they are quite similar.
Tendermint docs on adding non-validator vs validator: https://docs.tendermint.com/master/tendermint-core/using-tendermint.html
Adding a non-validator is simple. Just copy the original
genesis.json
to~/.tendermint/config
on the new machine and start the node, specifying seeds or persistent peers as necessary.The easiest way to add new validators is to do it in the
genesis.json
, before starting the network.
node_key.json
node_key.json is used to store the node's key. The node-id queried by
ethermintd tendermint show-node-id
is derived by the key, which is used to indicate the unique identity of the node. It is used in p2p connection.
priv_validator.json
pri_validator.json
is the Tendermint Key file that the validator will use to sign Pre-vote/Pre-commit in each round of consensus voting. As the consensus progresses, the tendermint consensus engine will continuously updatelast_height
/last_round
/last_step
values.Query the associated public key prefixed with
icp
:ethermintd tendermint show-validator
Query the associated bech32 address prefixed with
ica
:ethermintd tendermint show-address
I am a senior developer for one of the fastest growing blockchain protocols and I have been struggling to set up our private blockchain on Cosmos for a month now due to outdated documentations. After reading this 5 minute long Substack, I have finally been unblocked. Looking forward to your future articles!
👍👍 Great job on the post! The step-by-step guideline is super clean and easy to understand. Thanks!