在区块链的世界里,以太坊(Ethereum)无疑是最具影响力的平台之一,它不仅仅是一个加密货币,更是一个全球性的、去中心化的计算机,要真正理解以太坊的运作机制,深入其技术核心是必不可少的途径,本文将带您踏上一段探索之旅,从构建一个以太坊全节点开始,逐步揭开其挖矿机制背后的源码奥秘,揭示新区块是如何被创造并添加到区块链上的。
在讨论挖矿之前,我们必须先理解以太坊节点(ETH Node)的重要性,以太坊网络并非由单一服务器控制,而是由成千上万个分布在全球的节点共同维护的,每个节点都保存着一份完整的以太坊区块链副本,并参与网络的共识过程。

节点类型:
为什么运行一个全节点?
构建一个以太坊全节点:
最常用的方式是通过运行以太坊官方客户端,目前最主流的是基于Go语言开发的 Geth (Go-Ethereum)。
apt, brew)进行安装。geth --datadir ./myethchain init genesis.json,这里的 genesis.json 是创世块配置文件,定义了链的初始参数。geth --datadir ./myethchain --syncmode snap --http --http.addr "0.0.0.0" --http.port "8545" --http.api "personal,eth,net,web3"。
--syncmode snap: 使用快速同步模式,可以快速同步最近的区块状态,而不是从创世块开始。--http: 启动HTTP-RPC服务,允许其他应用(如MetaMask、Remix)连接到您的节点。--http.api: 暴露给HTTP API的模块列表。启动后,您的节点就会开始连接到以太坊网络,下载并验证区块,成为这个去中心化网络中的一份子。
挖矿是以太坊从工作量证明走向权益证明之前,其共识机制的核心,在PoW中,矿工们通过强大的计算能力来解决一个复杂的数学难题,第一个解决问题的矿工将获得创建新区块的权利,并获得相应的以太币作为奖励。

挖矿的基本流程:
nonce(数字),矿工的目标是找到一个合适的nonce值,使得整个区块头的哈希值小于一个目标值。nonce值,并对区块头进行哈希运算(通常是Keccak-256算法)。nonce值,矿工立即将这个新区块广播到整个网络。了解了理论,我们再来看看在Geth的源码中,这个过程是如何被实现的,Geth的挖矿功能主要集中在 miner 包中。
挖矿的入口
在Geth的命令行或API中,启动挖矿通常通过 miner.start() 命令,在源码中,这个命令会调用 miner.go 文件中的 Start() 方法。
// miner.go
func (m *Miner) Start() {
// ... 一些前置检查 ...
m.mu.Lock()
defer m.mu.Unlock()
if m.thread != nil {
return // 挖矿已经在运行
}
// 创建一个用于接收挖矿结果的通道
if m.pending != nil {
m.pending.Subscribe(m.newTxsCh)
}
// 创建一个worker,它是实际执行挖矿任务的实体
m.worker = newWorker(m.config, m.chainConfig, m.engine, m.coinbase, m, m.eux, m.pow)
// 启动一个goroutine来运行挖矿循环
m.thread = gofunc() {
// ... 挖矿主循环 ...
}
}
核心是 worker 对象。 它负责管理整个挖矿过程,包括获取交易、构建候选区块、以及与共识引擎(PoW)的交互。
核心挖矿循环

在 worker 的 loop() 方法中,有一个核心的循环,它不断地执行以下操作:
worker.commitNewWork(),将交易和最新的状态信息打包成一个候选区块。ethash 共识引擎(PoW的实现)。共识引擎——ethash
以太坊的PoW算法是 ethash,它的核心特点是“内存硬性”(Memory Hardness),即它需要大量的内存来进行计算,这使得在专用硬件(如ASIC矿机)上获得巨大优势变得困难,从而鼓励了CPU和GPU挖矿。
在 miner.go 中,我们看到了 m.pow,这个对象就是 ethash 引擎的实例,当 worker 将一个候选区块提交给它后,ethash 引擎会启动计算过程。
ethash 的核心实现在 ethash 包中,特别是 search 函数,这个函数接收候选区块的哈希和难度,然后开始暴力计算 nonce。
// ethash/ethash.go 中的核心逻辑简化
func (ethash *Ethash) Search(block *types.Block, stop <-chan struct{}) (uint64, []byte, error) {
// 获取区块头
header := block.Header()
// 获取当前难度
number := header.Number.Uint64()
difficulty := header.Difficulty
// 循环尝试不同的nonce
for nonce := uint64(0); ; nonce {
// 设置区块头的nonce
header.Nonce = nonce
// 计算哈希
hash := header.Hash()
// 检查哈希是否满足难度要求
if new(big.Int).Div(difficulty, big.NewInt(1)).Cmp(hash.Big()) > 0 {
// 找到了!返回nonce和哈希
return nonce, hash.Bytes(), nil
}
// 检查是否收到停止信号
select {
case <-stop:
return 0, nil, nil
default:
// 继续下一次循环
}
}
}
这个 Search 函数就是挖矿“暴力计算”的直接体现,它会一直运行,直到找到一个满足条件的 nonce,或者收到外部停止的信号。
奖励与交易
当一个区块被成功挖出后,worker 会通过 chain.InsertChain() 方法将区块提交给区块链,之后,它会执行区块中的所有交易,并将挖矿奖励(由区块的 coinbase 地址接收)写入状态数据库,这部分逻辑在 worker 的 update() 方法中处理。