Setting up an Ethereum private chain and deploying smart contracts is a foundational skill for blockchain developers, researchers, and enterprises exploring decentralized applications (dApps). This comprehensive guide walks you through the entire process—from environment preparation to deploying and interacting with a smart contract—using industry-standard tools like Geth, Solidity, and Remix. Whether you're building a testnet for development or simulating a consortium blockchain, this tutorial provides practical, step-by-step instructions.
Prerequisites and Environment Setup
Before diving into blockchain creation, ensure your system meets the necessary requirements. This guide uses CentOS 7 in a VMware virtual machine with essential development tools.
Install Required Dependencies
To avoid installation errors later, pre-install commonly used packages:
yum update -y && yum install git wget bzip2 vim gcc-c++ ntp epel-release nodejs cmake -yEach component serves a specific purpose:
- Git: Version control for cloning the Go-Ethereum (Geth) repository.
- Wget: Command-line downloader for retrieving external files like CMake.
- Bzip2: Compression utility for handling
.tar.gzarchives. - Vim: Text editor for modifying configuration files.
- GCC-C++: Compiler suite needed to build Geth from source.
- NTP: Network Time Protocol ensures clock synchronization across nodes.
- Node.js: JavaScript runtime useful for frontend tooling and scripting.
- EPEL: Extra Packages for Enterprise Linux expands available software.
👉 Get started with blockchain development tools today.
Installing and Configuring Ethereum (Geth)
Clone and Compile Geth
The Go implementation of Ethereum (Geth) powers your private network.
Clone the official repository:
git clone https://github.com/ethereum/go-ethereum.gitNavigate into the directory and compile:
cd go-ethereum && make allAdd Geth to your system path:
echo 'export PATH=$PATH:$GOPATH/bin:$HOME/go-ethereum/build/bin' >> ~/.profile source ~/.profileVerify installation:
geth -hIf help output appears, Geth is correctly installed.
Upgrade CMake for Smart Contract Compilation
The default CMake version via yum may be outdated. Download and compile the latest version:
cd && wget https://cmake.org/files/v3.12/cmake-3.12.3.tar.gz
tar -xzvf cmake-3.12.3.tar.gz
cd cmake-3.12.3
./bootstrap && make && sudo make installUpdate your PATH:
echo 'export PATH=$PATH:$HOME/cmake/bin' >> ~/.profile
source ~/.profileVerify with cmake --version.
Configure System Services
Enable NTP for accurate timekeeping—critical in blockchain consensus:
systemctl enable ntpd
systemctl start ntpdFor firewall settings, either disable it (for testing):
systemctl stop firewalld
systemctl disable firewalldOr allow specific ports:
firewall-cmd --zone=public --add-port=8087/tcp --permanent
firewall-cmd --zone=public --add-port=30303/tcp --permanent
firewall-cmd --reloadCreating the Genesis Block
The genesis block defines your private blockchain’s initial state.
Create genesis.json:
{
"nonce": "0x0000000000000042",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x00",
"gasLimit": "0x80000000",
"difficulty": "0x400",
"mixhash": "0x000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x2D356ee3F5b8718d8690AFCD31Fe2CB5E612677e",
"alloc": {},
"config": {
"chainId": 15,
"homesteadBlock": 1,
"eip155Block": 2,
"eip158Block": 3
}
}Initialize the first node:
geth --datadir node1 init genesis.jsonStart the node console:
geth --datadir node1 console 2>> geth.logMonitor logs in another terminal:
tail -f geth.logAdding Multiple Nodes to the Network
To simulate a distributed network, add a second node.
Initialize a new node:
geth --datadir node2 init genesis.jsonLaunch the first node with RPC enabled:
geth --datadir node1 --networkid 23456 --rpc --rpcaddr "127.68.1.1" console 2>> geth.logLaunch the second node with unique ports:
geth --datadir node2 --networkid 23456 --rpc --rpcport 8546 --port 31314 console 2>> geth.logIn the second node’s console, retrieve its enode URL:
admin.nodeInfo.enodeAdd it to the first node:
admin.addPeer("enode://<your-enode-url-here>@127.68.1.1:31314")You’ll see peer connection logs confirming successful integration.
👉 Explore secure blockchain deployment practices now.
Understanding Block and Transaction Fields
Key Block Attributes
Each block contains metadata crucial for network integrity:
- difficulty: Mining difficulty of the current block.
- gasLimit: Maximum gas allowed per block.
- gasUsed: Actual gas consumed by transactions.
- hash: Unique identifier of the block.
- miner: Address of the mining node.
- nonce: Proof-of-Work solution value.
- number: Block height in the chain.
- parentHash: Reference to the previous block.
- timestamp: Unix timestamp when mined.
The mixHash proves computational effort, while the extraData field can store arbitrary information.
Transaction Breakdown
Every transaction includes:
- from/to: Sender and recipient addresses.
- value: Amount transferred in Wei.
- gas/gasPrice: Max gas limit and price per unit (in Wei).
- nonce: Sequence number per sender (prevents replay attacks).
- input: Data payload (used in contract calls).
- hash: Unique transaction ID.
Note: Actual fee = gasUsed * gasPrice. Unused gas is refunded.Deploying a Smart Contract
Write a Simple Solidity Contract
Using Remix IDE, create a basic contract:
pragma solidity ^v.4.18;
contract Test {
string public name;
function Test() public {
name = "xietao";
}
function getName() public view returns (string) {
return name;
}
function setName(string _name) public {
name = _name;
}
}Compile and Deploy via Geth Console
After compiling in Remix, copy the Web3 deploy snippet into your Geth console.
Unlock your account first:
personal.unlockAccount(eth.accounts[9])Deploy using:
var test = testContract.new({from: eth.accounts[9], data: '...', gas: '476543'}, function(e, contract) {
if (typeof contract.address !== 'undefined') {
console.log("Contract mined at:", contract.address);
}
});Start mining to confirm deployment:
miner.start(); admin.sleepBlocks(1); miner.stop();Upon success, you’ll see:
Contract mined! address: 6x7e8169387a54814fcc61a48729b7a891f24cd291 ...Interacting With Your Contract
Read operations are free:
test.getName()
// Returns: "xietao"Write operations require gas:
eth.defaultAccount = eth.accounts[9]
test.setName("newName")Or specify sender explicitly:
test.setName("updated", {from: eth.accounts[9]})Always mine after write transactions:
miner.start(1); miner.stop()Reading doesn’t alter state; writing does—and costs gas due to network computation and storage.
Frequently Asked Questions
What is a genesis block?
The genesis block is the first block in a blockchain, defining initial parameters like difficulty, gas limits, and chain ID. It anchors the entire network and must be identical across all nodes.
Why do I need to mine after deploying a contract?
Mining confirms transactions on Proof-of-Work chains. Without mining, contract deployment remains pending and unconfirmed in the mempool.
How do I prevent my private chain from connecting to public nodes?
Use the --nodiscover flag when launching Geth. Otherwise, nodes may sync with the mainnet if they share common network IDs like 1.
Can I change the gas limit of a block?
Yes—modify the "gasLimit" field in genesis.json. For example, "gasLimit": "6B2F" sets a higher cap suitable for complex contracts.
What happens if I run out of gas during a transaction?
The transaction fails, changes are reverted, but gas used is not refunded since miners performed computational work.
Is it safe to expose RPC ports?
Only in trusted environments. In production, restrict access via firewalls or use secure tunneling (e.g., HTTPS + authentication).