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

ยท

Introduction to Private Blockchain Development

Creating a private blockchain is essential for developers looking to test decentralized applications (DApps) in a controlled environment. This guide demonstrates how to establish a Proof-of-Authority (PoA) private chain using Geth (Go Ethereum) and puppeth, followed by deploying a voting smart contract.

Key Tools and Technologies

  1. Geth: The official Go implementation of the Ethereum protocol
  2. Puppeth: Ethereum's network manager for genesis block configuration
  3. Truffle Suite: Development framework for Ethereum smart contracts
  4. Solidity: Ethereum's smart contract programming language

Step 1: Installing Geth

For macOS Users:

brew tap ethereum/ethereum
brew install ethereum

Verification:

geth version

Step 2: Setting Up Proof-of-Authority Nodes

Directory Structure

mkdir private-chain-node1 private-chain-node2

Account Creation

Execute these commands separately for each node:

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

Note: Record the generated addresses for later use.


Step 3: Configuring Genesis Block with Puppeth

  1. Launch puppeth:

    puppeth
  2. Follow the interactive setup:

    • Select "Configure new genesis"
    • Choose "Clique - proof-of-authority"
    • Set block time (default: 15 seconds)
    • Input authorized sealing addresses
    • Specify pre-funded accounts
    • Define chainID (e.g., 123456)
    • Export configuration as genesis.json

Step 4: Initializing Nodes with Genesis Block

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

Step 5: Launching and Connecting Nodes

Node 1 Configuration:

geth --datadir ./ --networkid 123456 --port 8000 --nodiscover console

Node 2 Configuration:

geth --datadir ./ --networkid 123456 --port 8001 --authrpc.port=8546 --nodiscover console

Peer Connection:

  1. Retrieve Node 1's enode:

    admin.nodeInfo.enode
  2. In Node 2's console:

    admin.addPeer("enode://[email protected]:8000?discport=0")

Verify connection with:

admin.peers

Step 6: Smart Contract Development

Truffle Installation:

yarn global add truffle

Project Setup:

mkdir vote_dapp && cd vote_dapp
truffle unbox webpack

Voting Contract (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;
    }
}

Step 7: Contract Deployment

Migration Script (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')
    ]);
};

Network Configuration:

Update truffle-config.js:

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

Deployment Command:

truffle migrate --network development

Step 8: Building the DApp Interface

Frontend Implementation:

import { default as Web3 } from 'web3';
import { default as contract } from 'truffle-contract';
import voting_artifacts from '../../build/contracts/Voting.json';

const Voting = contract(voting_artifacts);
const candidates = {
    "Rama": "candidate-1", 
    "Nick": "candidate-2", 
    "Jose": "candidate-3"
};

window.voteForCandidate = async function() {
    const candidateName = $("#candidate").val();
    try {
        $("#msg").html("Processing vote...");
        const contractInstance = await Voting.deployed();
        const accounts = await web3.eth.getAccounts();
        
        await contractInstance.voteForCandidate(
            Web3.utils.asciiToHex(candidateName), 
            {gas: 140000, from: accounts[0]}
        );
        
        const votes = await contractInstance.totalVotesFor.call(
            Web3.utils.asciiToHex(candidateName)
        );
        
        $(`#${candidates[candidateName]}`).html(votes.toString());
        $("#msg").html("");
    } catch (err) {
        console.error(err);
    }
};

Frequently Asked Questions (FAQ)

Q1: Why use Proof-of-Authority instead of Proof-of-Work?

PoA is more efficient for private blockchains as it eliminates computational waste while maintaining decentralization through approved validators.

Q2: How can I add more nodes to this private network?

Simply repeat the node setup process and connect them using admin.addPeer() with the enode URL.

Q3: What's the gas limit recommendation for voting transactions?

For simple voting operations, 140,000 gas (as used in the example) is typically sufficient.

Q4: Can I deploy this on a public testnet?

Absolutely! Just modify the network configuration in truffle-config.js to target Ropsten, Rinkeby, or other testnets.

๐Ÿ‘‰ Explore advanced blockchain development tools


Conclusion

This implementation demonstrates core Web3 concepts through a practical voting application. Future enhancements could include:

For further learning, check out ๐Ÿ‘‰ Ethereum's official documentation.