How to build a dapp on a private Ethereum network : Part — 3
This is a series of 5 articles for developing a decentralized application (dapp) on a network of 2 private Ethereum nodes without using any third-party APIs or apps (such as Infura, MetaMask, etc.). This tutorial covers the essential elements of what I learn during my research project at CSIR-CEERI.
I have covered sections I-IV in parts 1 and 2. If you feel lost, you can read through the previous 2 parts whose links are mentioned at the bottom of this article in the All series links section.
Recently released — “Part 5 : Section VIII-IX”
Table of Contents
Here, you can find a list of the sections and subsections that I have divided this tutorial into :
I. Creating the project
II. Installing prerequisites
III. Configuring the network
IV. Designing the smart contract
→ V. Setting-up the Truffle project
→ VI. Launching the network
VII. Building the web app
VIII. Testing the dapp
IX. Modifying the dapp
If you want to skip to a particular section, you can scroll down to the All series links section at the end of this article.
This part will cover sections V-VI, which introduces you to Truffle and shows how you can configure a private Ethereum network of 2 nodes. This are extremely important sections in dapp development, where many falter and tend to give up. Stay with me, and it’ll be a cakewalk for you.
V. Setting-up the Truffle Project
Truffle is a development environment and a testing framework for Ethereum dapps that enables easy integration of all components of a dapp. It acts as a wrapper and takes care of the background processes. This allows the developer to focus solely on implementing the use-case.
- Leave the
TruffleDapp
repository which we have been working in since Part-1. To navigate to home, open a terminal and run$ cd ~
or to navigate to the parent directory, run$ cd ./..
- The
truffle init
command requires that a repository be completely empty before this command is run. To create a Truffle project, run :
$ mkdir Temp
$ cd Temp
$ truffle init
- Move all files and folders from
Temp
and paste them toTruffleDapp
. TheTemp
directory can now be deleted. - In the
TruffeDapp
directory, run :
$ truffle create contract helloworld
- This creates a smart contract
helloworld.sol
in thecontracts
folder (created after runningtruffle init
). Replace the code in ithelloworld.sol
with the contract code created in the RemixIDE. - To compile the contract, run the following command. By default, the output of this process is the
build/contracts/helloworld.json
file :
$ truffle compile
- Create migration file using the following command :
$ truffle create migration HelloWorld
This will add xx_helloworld.js
file in the migrations
folder (xx
is some integer). Rename this file to 2_helloworld.js
. Then, open this file and update with the following content:
var hw = artifacts.require("HelloWorld");
module.exports = function(deployer) {
deployer.deploy(hw);
};
Yes, your projects represent you. They are a living memory of your work
“An abandoned project is but a lost opportunity”
You have come far. Trust me, you keep going and you will scale the peak that many others failed to reach.
VI. Launching the Network
This section illustrates the nodes that comprise the network on top of which the dapp executes. The network can be launched by using one of the following 3 modes :
- Default Truffle construct
- Modified Truffle set-up
- Manually configured private network (used here)
You can skip directly to subpart 3. I have provided the first two for the curious minds.
1. Default Truffle construct
Truffle provides an option to use an in-built development blockchain with a single command. This can be done by typing the following into a terminal:
$ truffle develop
This will run the client on http://127.0.0.1:9545. It will display the first 10 accounts and the mnemonic used to create those accounts.
2. Modified Truffle set-up
- To test the contract locally within the truffle environment, edit the
TruffleDapp/truffle-config.js
file to include :
module.exports = {
networks: {
"development": {
network_id: "*",
host: "127.0.0.1",
port: 9545
},
}
};
This configures the host and the port for the Truffle network (which runs in a sandboxed environment). It can be used to test whether or not the contract has been correctly deployed.
- When the contract is deployed to the Truffle “development” network,
1_initial_migration.js
is migrated first, followed by2_helloworld.js
. Open a new terminal and run in theTruffleDapp
directory :
$ truffle migrate
- To test the contract, open a console to interact with the Truffle network (via the deployed smart contract) and run in a new terminal :
$ truffle console
You can now run commands in this console to interact with the Truffle network.
3. Manually configured private network
This is the mode I’ll be using in this tutorial series.
1a) CREATING NODE-1
These instructions are only for creating the first node. The steps to create other nodes (in a multi-node network) are similar but have key differences.
- A repository is needed to store the public and private keys for the node and chain data. This node is initialized with the
./customGenesis.json
. Run in a new terminal window (T1) :
$ geth --datadir "./Node1" init ./customGenesis.json
- To connect this node various parameters for the network which this node will be a part of, run in T1 :
$ geth --datadir "./Node1" --networkid 1999 --identity "testNet" --rpc --rpcvhosts "*" --rpcport "8081" --rpccorsdomain "*" --rpcaddr 127.0.0.1 --rpcapi "db,eth,net,web3,personal,miner,admin" --port "30301"
Note : This spins off a node and displays node information in T1. One such attribute shown is self
. The string value of self
is used later to connect with Node-1.
- In a new terminal (T2), run
$ geth attach http://127.0.0.1:8081
to open a port to connect to Node-1. - For any node (user) to access and operate in the Ethereum environment, it is required that they contain some amount of Ether to pay for gas as a transaction cost. Hence, creating an account on the network to store the Ether is necessary. To create an account with the passphrase “seed 1”, run in T2 :
> personal.newAccount("seed 1")
- The Ethereum account for depositing the mining rewards (Ether) is termed as the
eth.coinbase
, whose default value iseth.accounts[0]
Note : This returns an account address ACCOUNT_ADDRESS
, which is later copied to truffle-config.js
.
- To use the account previously created, it needs to be unlocked with the same passphrase given as input during its creation (see image below).
> personal.unlockAccount(web3.eth.accounts[0], "seed 1", 15000)
> eth.defaultAccount = eth.accounts[0]
The eth.defaultAccount
is the default account input to the from
field when you send a transaction, i.e. if you send a transaction and do not specify the from
field, the value of eth.defaultAccount
will be used (if previously set).
- Here,
eth.coinbase
is set and the mining process is initiated on a single thread. Single thread mining is the safest option since you risk a system-wide freeze otherwise. We may use > 1 threads in a system with higher computing power (see image above).
> miner.setEtherbase(eth.accounts[0])
> miner.start(1)
- When the message
Commit new mining work
is displayed at T1, it implies that mining has been kickstarted at Node-1.
Note : These 3 instructions are common to all nodes created here :
- To stop the mining process at Node-1, type into T2 console
> miner.stop()
- To exit the console in T2, type into this console
> exit
- To exit the console in T1, navigate to the tab of T1 and press
Ctrl + C
1b) RESTARTING NODE-1
Once created, execute the following commands to restart Node-1 :
- Open a new terminal window (T1) and run :
$ geth --datadir "./Node1" --networkid 1999 --identity "testNet" --rpc --rpcvhosts "*" --rpcport "8081" --rpccorsdomain "*" --rpcaddr 127.0.0.1 --rpcapi "db,eth,net,web3,personal,miner,admin" --port "30301"
- In another terminal window (T2), run :
$ geth attach http://127.0.0.1:8081
- In the console opened at T2, type in :
> personal.unlockAccount(web3.eth.coinbase, "seed 1", 15000)
> eth.defaultAccount = eth.accounts[0]
> miner.start(1)
2a) CREATING NODE-2
For creating Node-2, follow the given steps :
- Open a new terminal window (T1) and run :
$ geth --datadir "./Node2" init ./customGenesis.json$ geth --datadir "./Node2" --networkid 1999 --identity "testNet" --rpc --rpcvhosts "*" --rpcport "8082" --rpccorsdomain "*" --rpcaddr 127.0.0.1 --rpcapi "db,eth,net,web3,personal,miner,admin" --port "30302"
- In another terminal window (T2), run :
$ geth attach http://127.0.0.1:8082
- In the console opened at T2, type in :
> personal.newAccount("seed 2")
> personal.unlockAccount(web3.eth.coinbase, "seed 2", 15000)
> eth.defaultAccount = eth.accounts[0]
>
> miner.setEtherbase(eth.accounts[0])
> miner.start(1)
- Up to this step, a node (Node-2) has been created with the same network configurations as that of Node-1 but a connection has yet to be established between the 2 nodes. Unless this is done, this setup will only consist of 2 individual nodes and not a network, as is desired.
> admin.addPeer("self of Node-1")
The "self of Node-1"
is the string value of the self
property of Node-1 which is shown in the console after executing the two commands in T1 (when creating/restarting Node-1). Copy and paste this self
value here.
2b) RESTARTING NODE-2
Once Node-2 is created, the steps to restart it are practically the same as that for Node-1, with a few minor edits.
- Open a new terminal window (T1) and run :
$ geth --datadir "./Node2" --networkid 1999 --identity "testNet" --rpc --rpcvhosts "*" --rpcport "8082" --rpccorsdomain "*" --rpcaddr 127.0.0.1 --rpcapi "db,eth,net,web3,personal,miner,admin" --port "30302"
- In another terminal window (T2), run :
$ geth attach http://127.0.0.1:8082
- In the console opened at T2, run :
> personal.unlockAccount(web3.eth.coinbase, "seed 2", 15000)
> eth.defaultAccount = eth.accounts[0]
> miner.start(1)
Pro-tip : To create/restart a Node-n, execute the same commands as mentioned in 2a/2b after performing the given steps :
- Replace the
--rpcport "8082"
and--port "30302"
with--rpcport "808n"
and--port "3030n"
, i.e. an RPC port number that is unique to the Node-n. - Replace the
http://127.0.0.1:8082
with the respectivehttp://127.0.0.1:808n
, where808n
is the value passed to the--rpcport
flag (in the previous step). - Replace
"seed 2"
with"seed n"
, i.e. a phrase that is unique to the account created at Node-n. - For the Node-n,
admin.addPeer("self of Node-i")
commands corresponding to every Node-i need to be executed individually in the Node-n console, where i = 1, 2, 3, ..., n-1
Note : There is an alternate way to create an n-node network by using the concept of a bootnode
as given here. However, since our network only consists of 2 nodes, the method used here is simpler.
3) LINKING WITH THE NETWORK
To link the Truffle dapp to the launched network and its nodes, open truffle-config.js
in an editor and modify it to have the following code, which lists the configurations necessary to establish a connection to a network node (in this case Node-1) :
module.exports = {
rpc: {
host: "127.0.0.1",
port: 8081
},networks: {
development: {
host: "127.0.0.1",
port: 8081,
network_id: "1999",
from: "ACCOUNT_ADDRESS",
gas: 20000000
},
}
}
Note : The ACCOUNT_ADDRESS
pasted here is the hexadecimal value from the steps mentioned under 1a) CREATING NODE-1.
4) DEPLOYING THE SMART CONTRACT
When the private Ethereum network has been launched, the smart contract needs to be deployed onto the network. Open a new terminal and run in the TruffleDapp
directory :
$ truffle migrate
The file 1_initial_migration.js
is migrated first, followed by 2_helloworld.js
.
With this, we conclude an integral part of this tutorial to launch a private Ethereum network of 2 nodes and deploy our helloworld.sol
smart contract on top of this network.
All series links
In case you want to skip ahead and jump onto a specific section, you can use the links below for reference. Refer to the Table of Contents below to match a section with its corresponding topic.