Understanding Web3 Concepts Through the Ethereum Whitepaper: Building a Private Blockchain with Geth and Puppeth

·

Web3 represents a paradigm shift in how we interact with the internet—moving from centralized platforms to decentralized, trustless systems powered by blockchain technology. At the heart of this transformation lies Ethereum, a platform that enables smart contracts and decentralized applications (dApps). To truly grasp Web3 fundamentals, there's no better exercise than building your own private Ethereum blockchain.

In this hands-on guide, you'll learn how to set up a private Proof-of-Authority (PoA) Ethereum network using Geth and puppeth, deploy a voting dApp with Truffle, and interact with it via a simple frontend interface—all while gaining practical insight into core Web3 concepts like consensus mechanisms, account management, smart contract deployment, and node communication.


Setting Up Geth for Local Blockchain Development

The first step in exploring Ethereum-based Web3 development is installing Geth, the official Go implementation of the Ethereum protocol. Geth allows you to run a full Ethereum node, interact with the network, mine blocks, and deploy smart contracts.

To install Geth on macOS using Homebrew:

brew tap ethereum/ethereum
brew install ethereum

Verify the installation:

geth version

Once installed, you're ready to create your own private blockchain—perfect for testing dApps without incurring gas fees or exposing code to public networks.

👉 Discover how blockchain developers test dApps securely before launch.


Creating a Proof-of-Authority (PoA) Private Network

For development and enterprise use cases, Proof-of-Authority (PoA) is ideal because it offers fast transaction finality and low overhead. Unlike Proof-of-Work, PoA relies on approved validators (authorities) to produce blocks.

Step 1: Initialize Node Directories

Create two separate directories for two nodes:

mkdir private-chain-node1 private-chain-node2

Step 2: Generate Ethereum Accounts

Each node needs an account. Create them using:

geth --datadir private-chain-node1 account new
geth --datadir private-chain-node2 account new

Record the generated addresses—they’ll be used to define sealers (block producers) and pre-funded accounts.

Step 3: Configure Genesis Block with Puppeth

Use puppeth to generate a custom genesis configuration:

puppeth

Follow the prompts:

Step 4: Initialize Nodes with Genesis File

Apply the genesis block to both nodes:

geth --datadir private-chain-node1 init genesis.json
geth --datadir private-chain-node2 init genesis.json

Step 5: Launch Both Nodes

Start each node with unique ports:

Node 1:

geth --datadir ./ --networkid 123456 --port 8000 --rpc.allow-unprotected-txs --http --http.crossdomain="*" --allow-insecure-unlock --nodiscover console

Node 2:

geth --datadir ./ --networkid 123456 --port 8001 --http.port=8547 --authrpc.port=8546 --rpc.allow-unprotected-txs --http --http.crossdomain="*" --allow-insecure-unlock --nodiscover console
Note: The --http flag enables JSON-RPC access, crucial for dApp interaction.

Step 6: Connect Nodes Peering

Retrieve Node 1’s enode URL:

admin.nodeInfo.enode

On Node 2, add Node 1 as a peer:

admin.addPeer("enode://<node1-enode-url>@127.0.0.1:8000?discport=0")

Confirm connection:

admin.peers

You now have a two-node PoA blockchain—laying the foundation for secure, scalable Web3 application testing.


Deploying a Voting Smart Contract Using Truffle

With the blockchain running, let’s deploy a simple voting dApp using Truffle Suite, a popular development framework for Ethereum.

Install Truffle

yarn global add truffle

Create Project

mkdir vote_dapp && cd vote_dapp
truffle unbox webpack

Write the Smart Contract (contracts/Vote.sol)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Voting {
    mapping(bytes32 => uint8) public votesReceived;
    bytes32[] public candidateList;

    constructor(bytes32[] memory candidateNames) {
        candidateList = candidateNames;
    }

    function totalVotesFor(bytes32 candidate) public view returns (uint8) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

    function validCandidate(bytes32 candidate) public view returns (bool) {
        for (uint i = 0; i < candidateList.length; i++) {
            if (candidateList[i] == candidate) {
                return true;
            }
        }
        return false;
    }
}

Configure Deployment Script (migrations/2_deploy_contract.js)

var Voting = artifacts.require("Voting");
const web3 = require("web3");

module.exports = function(deployer) {
    deployer.deploy(Voting, [
        web3.utils.asciiToHex('Rama'),
        web3.utils.asciiToHex('Nick'),
        web3.utils.asciiToHex('Jose')
    ]);
};

Update truffle-config.js

Add development network settings:

development: {
    host: "127.0.0.1",
    port: 8545,
    network_id: "123456"
}

Set Solidity compiler version:

compilers: {
    solc: {
        version: "0.8.0"
    }
}

Deploy the contract:

truffle migrate --network development

👉 See how real-world dApps are deployed and audited on Ethereum.


Building a Frontend Interface for User Interaction

Now that the contract is live, build a simple HTML/JS frontend to interact with it.

Include Web3.js and connect to your local node:

<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

Initialize Web3 provider:

window.web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));

Load the deployed contract and enable voting:

Voting.setProvider(web3.currentProvider);

window.voteForCandidate = async function() {
    const candidateName = document.getElementById("candidate").value;
    const accounts = await web3.eth.getAccounts();
    
    Voting.deployed().then(async function(contractInstance) {
        contractInstance.voteForCandidate(web3.utils.asciiToHex(candidateName), { from: accounts[0] });
        
        // Update vote count after transaction
        const voteCount = await contractInstance.totalVotesFor(web3.utils.asciiToHex(candidateName));
        document.getElementById(candidates[candidateName]).textContent = voteCount.toString();
    });
};

This creates a functional dApp where users can cast votes recorded immutably on your private chain.


Frequently Asked Questions (FAQ)

Q: Why use Proof-of-Authority instead of Proof-of-Work?
A: PoA is faster, energy-efficient, and ideal for private or test networks where trust among participants exists. It’s widely used in enterprise blockchain solutions.

Q: Can I connect MetaMask to my private chain?
A: Yes! Add a custom RPC network in MetaMask with Chain ID 123456, RPC URL http://127.0.0.1:8545, then import accounts using their private keys.

Q: What is the purpose of the genesis.json file?
A: It defines the initial state of the blockchain, including consensus rules, block time, pre-funded accounts, and chain ID—essential for network consistency.

Q: How do nodes discover each other in a private network?
A: Since --nodiscover disables automatic discovery, you must manually connect nodes using admin.addPeer() with enode URLs.

Q: Is it safe to use --allow-insecure-unlock in production?
A: No. This flag is only for local development. In production, use secure key management tools like Hashicorp Vault or hardware wallets.

Q: How can I prevent duplicate voting?
A: Extend the contract to track voter addresses using a mapping(address => bool) to ensure one vote per account.


Conclusion

By building a private Ethereum blockchain and deploying a working dApp, you've taken a significant step toward mastering Web3 development. You now understand key components such as node setup, consensus mechanisms, smart contract lifecycle, and frontend integration—all essential skills for modern decentralized application engineers.

As Web3 continues to evolve, hands-on experience like this becomes increasingly valuable. Whether you're exploring decentralized identity, tokenomics, or layer-2 scaling solutions, starting with a private chain offers a safe sandbox to innovate.

👉 Start experimenting with blockchain tools used by top developers worldwide.