Public chain/private chain + block explorer development source code full analysis
BlockchainIt is a distributed ledger technology that realizes decentralized data storage and verification through cryptography, consensus algorithms, and P2P networks. The public chain is open to the world, and anyone can participate. Private chains serve within enterprises or alliance scenarios. Block explorers are visual query tools for on-chain data and are the standard infrastructure for every chain. This article will provide an in-depth analysis of the underlying implementation of public chains/private chains and the complete development process of block explorers from the source code level.
What is a public/private chain?
Public BlockchainIt is a fully open blockchain network where anyone can participate in node operation, transaction submission, and data verification, representing projects including Bitcoin, Ethereum, Solana, Avalanche, and more. Its core features are permissionless, decentralized, and censorship-resistant.
Private BlockchainIt is a permissioned blockchain network, and the joining and exiting of nodes is controlled by the manager, which is suitable for scenarios such as internal data sharing, supply chain traceability, and financial clearing and settlement. Representative frameworks include Hyperledger Fabric, Quorum, FISCO BCOS, and more.
Comparison of core features
🌐 Public chain — decentralized
Nodes are globally distributed, permissionless to participate, network security is maintained through economic incentives (mining/staking), and the code is fully open-source.
🏢 Private Chain — High performance
The number of nodes is controllable, the consensus efficiency is high, and the TPS can reach thousands to tens of thousands, making it suitable for enterprise-level high-frequency trading scenarios.
🔐 Public chain — censorship resistant
Any transaction is irreversible once confirmed, and no entity can alone prevent the execution of a legitimate transaction.
📋 Private Chain — Compliant and controllable
Meet regulatory requirements such as KYC/AML, and support permission hierarchy, data privacy protection, and audit traceability.
Comparison of public and private chain technology
| Contrast dimensions | Public Chain | Private Chain | Consortium |
|---|---|---|---|
| How to participate | Anyone can join without permission | Requires authorization, single organization management | Multi-organization co-governance |
| Consensus mechanism | PoW / PoS / DPoS | PBFT / Raft / PoA | PBFT / HotStuff |
| TPS | 15-65000 (depending on the chain) | 1000-100000+ | 1000-10000 |
| Confirmation time | Seconds to minutes | Milliseconds to seconds | seconds |
| Data visibility | Completely transparent | Visible only with authorization | Members are visible |
| Incentive mechanism | Token rewards | No token incentives required | Optional tokens |
| Typical representative | Ethereum, Solana | Hyperledger Fabric | FISCO BCOS, R3 Corda |
Detailed explanation of the consensus mechanism
The consensus mechanism is the core engine of blockchain, determining how the network agrees on the state of the ledger. Different scenarios require different consensus algorithm trade-offs.
Mainstream consensus algorithms
⛏️ PoW (Proof of Work)
Computational hashing challenges compete for block power, which is the most secure but consumes a lot of energy. Bitcoin, Ethereum Classic adopted. Block time: ~10 minutes (BTC) / ~13 seconds (ETH old).
🥩 PoS (Proof of Stake)
The block probability is allocated according to the number of staked tokens and time, with low energy consumption and high efficiency. Ethereum 2.0, Cardano adopted. Minimum stake of 32 ETH to become a validator.
🗳️ DPoS (Delegated Proof of Stake)
Coin holders vote for supernodes to produce blocks on their behalf, with high TPS but low decentralization. EOS (21 nodes), TRON adopted.
🤝 PBFT (Byzantine Fault Tolerance)
Multiple rounds of voting among nodes to reach consensus, tolerating 1/3 of malicious nodes. Suitable for consortium chains, Hyperledger Fabric adoption. Low latency but limited number of nodes.
Consensus algorithm source code structure (PoS example)
// validator_set.go - 验证者集合管理
type ValidatorSet struct {
Validators []*Validator
TotalStake uint64
}
type Validator struct {
Address common.Address
Stake uint64
Commission float64
Active bool
}
// 按权重选择出块者(加权随机)
func (vs *ValidatorSet) SelectProposer(seed []byte) *Validator {
hash := crypto.Keccak256(seed)
target := new(big.Int).SetBytes(hash)
target.Mod(target, big.NewInt(int64(vs.TotalStake)))
cumulative := uint64(0)
for _, v := range vs.Validators {
if !v.Active { continue }
cumulative += v.Stake
if cumulative > target.Uint64() {
return v
}
}
return vs.Validators[0]
}
// 验证区块签名
func (vs *ValidatorSet) VerifyBlockSignature(block *Block) error {
proposer := vs.GetValidator(block.ProposerAddress)
if proposer == nil {
return ErrUnknownValidator
}
if !crypto.VerifySignature(proposer.PublicKey, block.Hash(), block.Signature) {
return ErrInvalidSignature
}
return nil
}
Chain architecture design
A complete blockchain can be divided into the following technical levels from the bottom to the top:
node development core modules
Blockchain nodes are the fundamental building blocks of the network, responsible for receiving transactions, validating blocks, maintaining state, and participating in consensus. The following is the source code structure of the node core module:
Block and transaction data structures
// block.go - 区块结构定义
type BlockHeader struct {
ParentHash common.Hash `json:"parentHash"`
StateRoot common.Hash `json:"stateRoot"`
TxRoot common.Hash `json:"transactionsRoot"`
ReceiptRoot common.Hash `json:"receiptsRoot"`
Coinbase common.Address `json:"miner"`
Difficulty *big.Int `json:"difficulty"`
Number *big.Int `json:"number"`
GasLimit uint64 `json:"gasLimit"`
GasUsed uint64 `json:"gasUsed"`
Timestamp uint64 `json:"timestamp"`
Nonce [8]byte `json:"nonce"`
}
type Block struct {
Header *BlockHeader
Transactions []*Transaction
Uncles []*BlockHeader
}
type Transaction struct {
Nonce uint64 `json:"nonce"`
GasPrice *big.Int `json:"gasPrice"`
Gas uint64 `json:"gas"`
To *common.Address `json:"to"`
Value *big.Int `json:"value"`
Data []byte `json:"input"`
V, R, S *big.Int // 签名数据
}
// 计算区块哈希
func (b *Block) Hash() common.Hash {
return crypto.Keccak256Hash(rlp.Encode(b.Header))
}
// 验证区块有效性
func (b *Block) Validate(parent *Block) error {
if b.Header.ParentHash != parent.Hash() {
return ErrInvalidParentHash
}
if b.Header.Number.Uint64() != parent.Header.Number.Uint64()+1 {
return ErrInvalidBlockNumber
}
if b.Header.Timestamp <= parent.Header.Timestamp {
return ErrInvalidTimestamp
}
return nil
}
Trading Pool (TxPool)
// txpool.go - 交易池管理
type TxPool struct {
pending map[common.Address]*txList // 可执行交易
queue map[common.Address]*txList // 等待 nonce 连续
mu sync.RWMutex
maxSize int
}
func (pool *TxPool) AddTransaction(tx *Transaction) error {
pool.mu.Lock()
defer pool.mu.Unlock()
// 1. 验证签名
sender, err := tx.RecoverSender()
if err != nil { return ErrInvalidSignature }
// 2. 验证 nonce
currentNonce := pool.stateDB.GetNonce(sender)
if tx.Nonce < currentNonce { return ErrNonceTooLow }
// 3. 验证余额
cost := new(big.Int).Mul(tx.GasPrice, new(big.Int).SetUint64(tx.Gas))
cost.Add(cost, tx.Value)
if pool.stateDB.GetBalance(sender).Cmp(cost) < 0 {
return ErrInsufficientFunds
}
// 4. 加入交易池
if tx.Nonce == currentNonce {
pool.pending[sender].Add(tx)
} else {
pool.queue[sender].Add(tx)
}
return nil
}
Smart contract virtual machines
Smart contract virtual machines (VMs) are the execution environment for on-chain code. EVM (Ethereum Virtual Machine) is the most mainstream implementation, with almost all EVM-compatible chains based on the same bytecode specification.
EVM execution model
- Stacked architecture: Maximum operand stack depth of 1024, 256 bits (32 bytes) per element
- Deterministic execution: The same input must produce the same output to ensure the same state of the whole network
- gas mechanism: Each instruction consumes fixed gas to prevent infinite loops and resource abuse
- State isolation: Each contract has independent storage space, read and write through SSTORE/SLOAD
EVM core instruction set implementation
// evm/interpreter.go - EVM 解释器核心循环
func (evm *EVM) Execute(contract *Contract, input []byte) ([]byte, error) {
var (
stack = newStack()
memory = newMemory()
pc uint64 = 0
gas uint64 = contract.Gas
)
code := contract.Code
for pc < uint64(len(code)) {
op := OpCode(code[pc])
operation := evm.jumpTable[op]
// Gas 扣费
if gas < operation.gasCost {
return nil, ErrOutOfGas
}
gas -= operation.gasCost
// 执行指令
switch op {
case ADD:
a, b := stack.Pop(), stack.Pop()
stack.Push(new(big.Int).Add(a, b))
case SSTORE:
key, value := stack.Pop(), stack.Pop()
evm.StateDB.SetState(contract.Address, key, value)
case CALL:
// 跨合约调用
addr, value, inOffset, inSize := stack.Pop4()
ret, err := evm.Call(contract, addr, input[inOffset:inOffset+inSize], gas/64, value)
stack.Push(ret)
case RETURN:
offset, size := stack.Pop(), stack.Pop()
return memory.GetSlice(offset, size), nil
}
pc++
}
return nil, nil
}
Custom precompiled contracts
Precompiled contracts are high-performance contracts built into nodes for cryptographic operations, cross-chain bridging, and more:
// precompiles.go - 自定义预编译合约注册
var PrecompiledContracts = map[common.Address]PrecompiledContract{
common.HexToAddress("0x01"): &ecRecover{}, // 签名恢复
common.HexToAddress("0x02"): &sha256hash{}, // SHA256
common.HexToAddress("0x03"): &ripemd160hash{}, // RIPEMD160
common.HexToAddress("0x09"): &blake2F{}, // Blake2
// 自定义:跨链验证
common.HexToAddress("0x20"): &crossChainVerifier{},
}
P2P network layer
P2P networks are the communication foundation of blockchain, responsible for node discovery, block broadcasting, transaction propagation, and state synchronization.
Node Discovery Protocol (Kademlia DHT)
// p2p/discovery.go - 节点发现
type DiscoveryProtocol struct {
table *KademliaTable
udpConn *net.UDPConn
bootNodes []*Node
}
func (d *DiscoveryProtocol) FindNeighbors(target NodeID) []*Node {
closest := d.table.FindClosest(target, 16)
var results []*Node
for _, node := range closest {
// 发送 FindNode 请求
resp, err := d.sendFindNode(node, target)
if err != nil { continue }
results = append(results, resp.Nodes...)
}
// 更新路由表
for _, n := range results {
d.table.AddNode(n)
}
return d.table.FindClosest(target, 16)
}
// 区块广播
func (srv *Server) BroadcastBlock(block *Block) {
peers := srv.GetPeers()
// 对 sqrt(N) 个节点发送完整区块
fullBroadcast := int(math.Sqrt(float64(len(peers))))
for i, peer := range peers {
if i < fullBroadcast {
peer.SendBlock(block)
} else {
// 其余节点仅发送区块哈希
peer.SendBlockHash(block.Hash())
}
}
}
Block explorer overview
Block ExplorerIt is the "search engine" of the blockchain network, providing users with visual query capabilities for on-chain data. It is the infrastructure that must be supported by every public/private chain after it is launched.
Core features:
🔍 Block query
Query block information by block height/hash: timestamp, number of transactions, gas consumption, block reward, validator, etc.
💳 Transaction tracking
Query the complete execution details of any transaction: sender, receiver, gas usage, contract call chain, event log.
📊 Address portrait
Display the address's balance, transaction history, token holdings, and contract interaction records, and support the tag system to mark known addresses.
📝 Contract validation
Submit the contract source code for bytecode matching verification, and after verification, the source code and ABI will be disclosed to support online interaction.
📈 Network statistics
Macro indicators such as network TPS, number of active addresses, gas price trends, token distribution, and DeFi TVL are displayed in real time.
🔔 Address monitoring
Users can subscribe to transaction notifications at specified addresses, and support email/webhook push, which is suitable for whale monitoring and security alerts.
Block explorer system architecture
Block explorer source code implementation
Block synchronization engine
// indexer/sync_engine.go - 区块同步核心
type SyncEngine struct {
rpcClient *ethclient.Client
db *gorm.DB
redis *redis.Client
currentHead uint64
batchSize int
}
func (s *SyncEngine) Start(ctx context.Context) error {
// 获取已索引的最新高度
s.currentHead = s.db.GetLatestBlockNumber()
log.Info("Starting sync from block", "number", s.currentHead)
for {
select {
case <-ctx.Done():
return nil
default:
chainHead, _ := s.rpcClient.BlockNumber(ctx)
if s.currentHead >= chainHead {
// 已追上最新区块,切换为实时模式
s.subscribeNewBlocks(ctx)
continue
}
// 批量同步历史区块
s.syncBatch(ctx, s.currentHead+1, min(s.currentHead+uint64(s.batchSize), chainHead))
}
}
}
func (s *SyncEngine) syncBatch(ctx context.Context, from, to uint64) {
var wg sync.WaitGroup
blocks := make([]*BlockData, to-from+1)
for i := from; i <= to; i++ {
wg.Add(1)
go func(num uint64) {
defer wg.Done()
block, _ := s.rpcClient.BlockByNumber(ctx, big.NewInt(int64(num)))
receipts, _ := s.rpcClient.BatchGetReceipts(ctx, block.Transactions())
blocks[num-from] = &BlockData{Block: block, Receipts: receipts}
}(i)
}
wg.Wait()
// 批量写入数据库
s.db.BatchInsertBlocks(blocks)
s.currentHead = to
}
Transaction parser
// indexer/tx_parser.go - 交易解析与分类
type TxParser struct {
abiRegistry map[common.Address]*abi.ABI
}
func (p *TxParser) ParseTransaction(tx *types.Transaction, receipt *types.Receipt) *ParsedTx {
result := &ParsedTx{
Hash: tx.Hash(),
From: getSender(tx),
To: tx.To(),
Value: tx.Value(),
GasUsed: receipt.GasUsed,
Status: receipt.Status == 1,
Timestamp: time.Now(),
}
// 识别交易类型
if tx.To() == nil {
result.Type = "contract_creation"
result.ContractAddress = receipt.ContractAddress
} else if len(tx.Data()) >= 4 {
result.Type = "contract_call"
methodID := tx.Data()[:4]
// 解码合约方法
if abi, ok := p.abiRegistry[*tx.To()]; ok {
method, _ := abi.MethodById(methodID)
result.MethodName = method.Name
result.DecodedInput, _ = method.Inputs.Unpack(tx.Data()[4:])
}
} else {
result.Type = "transfer"
}
// 解析事件日志
for _, log := range receipt.Logs {
event := p.decodeEvent(log)
result.Events = append(result.Events, event)
}
return result
}
Front-end data presentation (React component)
// components/BlockList.tsx - 实时区块列表
export function BlockList() {
const [blocks, setBlocks] = useState<Block[]>([]);
useEffect(() => {
// WebSocket 实时推送新区块
const ws = new WebSocket('wss://explorer-api.example.com/ws');
ws.onmessage = (event) => {
const newBlock = JSON.parse(event.data);
setBlocks(prev => [newBlock, ...prev.slice(0, 19)]);
};
return () => ws.close();
}, []);
return (
<div className="block-list">
{blocks.map(block => (
<div key={block.number} className="block-card">
<span className="block-number">#{block.number}</span>
<span className="block-txs">{block.txCount} txs</span>
<span className="block-time">{timeAgo(block.timestamp)}</span>
<span className="block-validator">{shortAddr(block.validator)}</span>
</div>
))}
</div>
);
}
RPC interface design
RPC (Remote Procedure Call) interfaces serve as a bridge for external applications to interact with blockchain nodes. The standard JSON-RPC 2.0 protocol is the industry's common solution.
Core RPC method
| Method name | Function | Parameters |
|---|---|---|
eth_blockNumber | Get the latest block height | None |
eth_getBlockByNumber | Get blocks by height | blockNumber, fullTx |
eth_getTransactionByHash | Press the hash to get the transaction | txHash |
eth_getBalance | Check the address balance | address, blockNumber |
eth_call | Read-only call contract | callData, blockNumber |
eth_sendRawTransaction | Broadcast signature transactions | signedTxData |
eth_getLogs | Query the event log | filter (address, topics, range) |
eth_subscribe | Subscribe to live events | type (newHeads, logs, pendingTx) |
Custom extended RPC
// rpc/custom_api.go - 自定义浏览器专用 RPC
type ExplorerAPI struct {
db *gorm.DB
cache *redis.Client
}
// 获取地址完整画像
func (api *ExplorerAPI) GetAddressProfile(address common.Address) (*AddressProfile, error) {
profile := &AddressProfile{
Address: address,
Balance: api.getBalance(address),
TxCount: api.db.CountTransactions(address),
TokenHoldings: api.getTokenBalances(address),
IsContract: api.isContract(address),
}
if profile.IsContract {
profile.ContractInfo = api.getContractMeta(address)
profile.Creator = api.getContractCreator(address)
}
return profile, nil
}
// 获取网络实时统计
func (api *ExplorerAPI) GetNetworkStats() *NetworkStats {
return &NetworkStats{
TPS: api.cache.Get("current_tps"),
ActiveAddresses: api.cache.Get("daily_active_addresses"),
TotalTx: api.db.CountAllTransactions(),
GasPrice: api.getAvgGasPrice(),
ValidatorCount: api.getActiveValidators(),
}
}
Deployment and Operations
Node deployment architecture
- Full Node: Stores complete blockchain data, verifies all transactions and blocks, and participates in P2P networks
- Archive Node: Preserves all historical states, supports status queries at any block height, and is a must-have for browsers
- Light Node: Only store block headers, verify data through Merkle Proof, suitable for mobile wallets
- Validator Node: Participating in consensus block production requires high availability and security
O&M monitoring points
📡 Node health monitoring
Block synchronization latency, number of peers, memory/disk usage, RPC response time. Visualize with Prometheus + Grafana.
🔄 Automatic failover
Node crashes are automatically restarted, snapshot resumed, and standby nodes are switched. Docker + Kubernetes orchestration.
💾 Data backup strategy
Regular snapshots, incremental backups, and off-site disaster recovery. If the data volume of the archive node is large (TB), you need to plan storage expansion.
🔒 Safety reinforcement
RPC port restricted access, DDoS protection, key HSM hosting, signature service isolation.
Recommended technology stack
| module | Technical selection | Description |
|---|---|---|
| Chain core | Go / Rust | Go ecosystem maturity (Geth), Rust high performance (Substrate/Reth) |
| Consensus engine | Tendermint / HotStuff | BFT is similar to consensus and has a strong endgame |
| Virtual machines | EVM / WASM | EVM compatibility is the largest, and WASM performance is better |
| P2P networking | libp2p / devp2p | libp2p is modular, devp2p is native to Ethereum |
| storage engine | LevelDB / RocksDB / Pebble | The LSM-Tree structure is suitable for write-intensive scenarios |
| Browser backend | Go / Node.js + PostgreSQL | High concurrency index + relational query |
| Browser front-end | Next.js + TailwindCSS | SSR boosts SEO, Tailwind develops quickly |
| Search engine | Elasticsearch | Transaction/address/contract full text search |
| Monitoring | Prometheus + Grafana + PagerDuty | Metric collection + visualization + alarm |
| deployment | Docker + Kubernetes + Terraform | Containerization + Orchestration + Infrastructure as Code |
Development process
Based on the NovaLinkR team's experience in delivering public chain and browser projects, the complete development process is as follows:
Requirements definition and technology selection
Determine the chain type (public/private/consortium chain), consensus mechanism, VM type, target TPS, tokenomics model. Output technical white paper.
Core protocol development
Implement underlying modules such as block structure, transaction processing, consensus engine, P2P network, and state storage to build a testnet.
Smart contract VM integration
Integrate EVM or WASM virtual machines for gas metering, precompiled contracts, cross-contract calls, and state management.
Block explorer development
Build data indexing services, API gateways, and front-end interfaces to achieve a complete query experience for blocks, transactions, addresses, and contracts.
Safety audit and stress testing
Formal verification of consensus security, smart contract auditing, P2P network attack simulation, and high concurrency stress testing.
Mainnet launch and ecological construction
Mainnet deployment, browser launch, wallet adaptation, developer documentation, faucet (Faucet) construction, community operation.
The NovaLinkR team has full-stack development capabilities from the underlying protocol to the block explorer and has successfully delivered multiple mainnet projects.Contact us todayGet free technical consultation and customized solutions.