在以太坊私有鏈的開發(fā)或測試過程中,出于壓力測試、經(jīng)濟模型模擬或特定業(yè)務(wù)邏輯驗證的需求,我們可能需要修改礦工打包區(qū)塊所獲得的獎勵。

雖然以太坊主網(wǎng)目前已經(jīng)轉(zhuǎn)為 PoS(權(quán)益證明),且歷史上也曾經(jīng)歷過“拜占庭”、“君士坦丁堡”等硬分叉導(dǎo)致的挖礦獎勵衰減(從 5 ETH 降至 3 ETH 再降至 2 ETH),但在私鏈環(huán)境(通常基于 Geth 客戶端)中,我們可以通過修改底層代碼來實現(xiàn)自定義的出塊獎勵。

本文將以 Go-Ethereum (Geth) 的常見版本為例,詳細介紹如何通過修改源碼來調(diào)整私鏈的出塊獎勵。


為什么需要修改源碼

在 Geth 的默認配置中,出塊獎勵并不是在 genesis.json 文件中配置的,而是被硬編碼在共識引擎的代碼邏輯中。

如果你使用的是 ethash (PoW) 共識算法,獎勵邏輯位于 Geth 代碼庫的共識層中,簡單的配置文件修改無法生效,必須修改 Golang 源碼并重新編譯客戶端。

環(huán)境準備

  1. 操作系統(tǒng):Linux (Ubuntu/CentOS) 或 macOS。
  2. 依賴環(huán)境:Go 語言環(huán)境 (1.19+ 或根據(jù) Geth 版本要求)。
  3. 源碼:從 GitHub 克隆 Go-Ethereum 倉庫。
git clone https://github.com/ethereum/go-ethereum.git
cd go-ethereum

定位核心代碼

出塊獎勵的邏輯主要位于 consensus/ethash 目錄下,我們需要修改 consensus.go 文件。

文件路徑consensus/ethash/consensus.go

在該文件中,搜索關(guān)鍵字 FinalizeAndAssemble 或者直接查找數(shù)字(如當(dāng)前的獎勵基數(shù))。

在較新的 Geth 版本中,你會看到類似以下的邏輯(為了演示,代碼可能有簡略):

// consensus/ethash/consensus.go
// ...
// 計算區(qū)塊獎勵
var (
    blockReward *big.Int
)
// 這里的邏輯通常判斷區(qū)塊號,根據(jù)以太坊歷史上的硬分叉規(guī)則設(shè)定獎勵
// Byzantium, Constantinople 等分叉點
if chainConfig.IsByzantium(blockNumber) {
    blockReward = big.NewInt(3e+18) // 3 ETH (3 * 10^18 wei)
}
// ...

修改獎勵數(shù)值

假設(shè)我們需要將出塊獎勵修改為 100 ETH,我

隨機配圖
們需要修改上述代碼邏輯。

注意:以太坊的最小單位是 Wei,1 ETH = 10^18 Wei,100 ETH = 100 * 10^18。

修改方案 A:簡單暴力法(忽略分叉規(guī)則) 如果你希望無論區(qū)塊高度是多少,獎勵永遠是 100 ETH,可以直接注釋掉復(fù)雜的判斷邏輯,強制賦值:

// 修改前
// if chainConfig.IsByzantium(blockNumber) {
//     blockReward = big.NewInt(3e+18)
// }
// 修改后
// 強制設(shè)定獎勵為 100 ETH
blockReward = big.NewInt(100e+18) 

修改方案 B:保留邏輯法 如果你希望保留代碼結(jié)構(gòu),可以修改特定分叉的數(shù)值:

if chainConfig.IsByzantium(blockNumber) {
    // 修改這里,將 3e+18 改為你想要的數(shù)值,50 ETH
    blockReward = big.NewInt(50e+18) 
}

關(guān)于叔塊獎勵

如果你在私鏈中也會產(chǎn)生叔塊,并且希望修改叔塊的獎勵規(guī)則,同樣在這個文件中搜索 accumulateRewards 函數(shù)(視 Geth 版本而定,有些版本邏輯直接寫在 Finalize 中)。

通常代碼會包含計算叔塊獎勵的數(shù)學(xué)公式: numReward := new(big.Int).Div(blockReward, big.NewInt(8))

如果你完全不需要叔塊獎勵邏輯,或者想簡化它,也可以在此處調(diào)整。

編譯與部署

修改完代碼后,保存文件,執(zhí)行 Geth 的編譯命令。

  1. 編譯 Geth: 在項目根目錄下執(zhí)行:

    make geth

    編譯成功后,生成的二進制文件通常位于 build/bin/geth。

  2. 部署私鏈

    • 停止當(dāng)前運行的私鏈節(jié)點。
    • 備份并替換舊的 Geth 可執(zhí)行文件。
    • 使用修改后的 Geth 啟動你的私鏈節(jié)點。
    • 注意:如果是在已有的鏈上修改獎勵,建議清理舊數(shù)據(jù)(刪除 --datadir 目錄)并重新創(chuàng)世,因為修改獎勵屬于共識變更,舊節(jié)點可能會因為共識不匹配而無法同步,但在私鏈單節(jié)點或所有節(jié)點同步升級的情況下是可行的。

驗證結(jié)果

啟動節(jié)點并開始挖礦(miner.start())。

等待生成幾個區(qū)塊后,查詢當(dāng)前區(qū)塊的 Coinbase(礦工地址)余額:

// 在 Geth Console 中
eth.getBalance(eth.coinbase)

如果返回的余額增長速度符合你設(shè)定的 100 ETH/塊,說明修改成功。

修改以太坊私鏈的出塊獎勵本質(zhì)上是對 consensus/ethash/consensus.go 源碼的“Hack”,這對于以下場景非常有用:

  1. 測試環(huán)境搭建:快速生成大量代幣用于測試。
  2. 聯(lián)盟鏈開發(fā):根據(jù)聯(lián)盟內(nèi)部的激勵規(guī)則定制經(jīng)濟模型。

?? 風(fēng)險提示:請務(wù)必僅在私有鏈或開發(fā)環(huán)境中使用此修改版客戶端,切勿連接以太坊主網(wǎng)或公共測試網(wǎng),否則將因共識不匹配導(dǎo)致節(jié)點無法同步或分叉。