作者:Jameson Lopp
來源:https://blog.lopp.net/running-bitcoin-core-v0-7-and-earlier/
本文是我對所有 Bitcoin Core 發行版本的歷史同步性能的研究的其中一個結果,也是構建真正老舊的版本的挑戰(難以找到編譯好的二進制文件)的成果。
注意,如果你計劃使用這些版本的 Bitcoin Core 來同步區塊鏈,你會用得很艱難。我不是第一個探究這件事情的人:在研究期間,我發現,Sjors Provoost 曾在 2017 年運行類似的實驗,也有文字記錄。
舊版 Bitcoin Core 客戶端的性能 – Sjors Provoost
探究同步過程中的錯誤
沒有一個 v0.8.0 以前的版本可以同步到現在的鏈頂端,裡面的原因多種多樣。
v 0.3:在區塊高度 12 4275 處停止同步,傳出這個錯誤:
ERROR: ConnectInputs() : fb0a1d8d34 VerifySignature failedInvalidChainFound: invalid block=0000000000004939267fheight=124276 work=6613870563198902508
乍一看,這並不是一筆特別奇怪的交易。但是,如果我們檢查這個比特幣地址的花費歷史,我們可以看到花費者構造過好幾筆奇怪的交易,有幾百個 “0 價值” 的輸出。可以不誇張地假設,這是一個技術人員在嘗試破壞網絡。
最後,讓我驚訝的是這個輸入的簽名的大小。75 字節是簽名的最大上限,大部分 P2PKH 的交易的簽名都是 71 ~ 73 字節。
你可以通過下面這篇文章來了解比特幣交易簽名的歷史;要指出的是,如果你嘗試使用更新版本的 OpenSSL(1.0.0p / 1.0.1k)來沿著早期鏈上出現的簽名,你會遇到錯誤,因為 DER 驗證更加嚴格而且會拒絕特定類型的編碼。
解決方法是:要麼使用一個更舊版本的 OpenSSL 來構建 Bitcoin Core,要麼在開始構建之間手動應用這個代碼補丁。一開始我有些困惑,因為 gitian builder 使用 Ubuntu 10.04 虛擬機作為構建環境,我以為應該是搭配了較老的(兼容)版本的 OpenSSL 的 …… 但是,Andrew Chow 指出,他們在 2015 年向後移植(backport)了這個 OpenSSL 補丁。
v0.4 和 v0.5 都在區塊高度 25 8354 處停止了同步,傳出錯誤:
EXCEPTION: 11DbExceptionDb::put: Cannot allocate memorybitcoin in ProcessMessage()ProcessMessage(block, 901212 bytes) FAILEDreceived block 0000000000000023e872REORGANIZE
這是值得注意的,因為看起來 25 8355 是第一個達到 900 KB 大小的區塊;在此之前,幾乎所有挖出的區塊都只達到 250KB 的默認 “軟頂”。
v0.6 在區塊高度 36 4670 處停止同步,並傳出錯誤:
EXCEPTION: 11DbExceptionDb::put: Cannot allocate memorybitcoin in ProcessMessages()ProcessMessage(block, 999787 bytes) FAILEDreceived block 000000000000000001d3
這也有類似的地方,因為看起來區塊 36 4671 是第一個達到 1MB 的區塊。
v0.7 在同一區塊停止同步,但報錯日誌不同:
received block 00000000000000000221ERROR: ConnectBlock() : UpdateTxIndex failedInvalidChainFound: invalid block=00000000000000000221 height=364671ERROR: SetBestChain() : SetBestChainInner failedERROR: AcceptBlock() : AddToBlockIndex failedERROR: ProcessBlock() : AcceptBlock FAILED
我猜測 v0.4 ~ v0.7 都是因為相同的原因而停止的,但那是什麼原因呢?是 “BDB 鎖問題”嗎(該問題導致 2013 年出現了一次意料之外的鏈分裂)?根據這些指令,我嘗試創建一個文件 ~/.bitcoin/DB_CONFIG
:
set_lg_dir databaseset_lk_max_locks 537000
但每個版本都依然卡在相同的區塊高度。事實證明,你還需要配置 set_lk_max_objects
,而且,最初的推薦數值(537000)還不夠高(如果你想同步到區塊 70 0000 的話)。下面的 ~/.bitcoin/DB_CONFIG
數值對我的機器奏效了:
set_lg_dir databaseset_lk_max_locks 1000000set_lk_max_objects 1000000
性能結果
你可以看我的粗糙同步結果。
你幾乎看不見關於 v0.3 的數據,因為它跟 v0.4 和 v0.5 幾乎一模一樣,最終都在區塊高度 12 4000 處崩潰。下面是一個對數版本,可以看得更清楚一些。
值得一提的是,在區塊 19 0000 處有一個轉折點,從此處開始,v0.4 的性能開始好於 v0.5。我把握最大的猜測是,這是 “檢查點” 的結果。Bitcoin 0.3.2 引入了一種叫做 “檢查點” 的機制來保證新的全節點不會在初期區塊下載期間花費大量時間來驗證不在已知最佳鏈上的競爭區塊,從而阻止拒絕服務式攻擊。
Bitcoin 0.5.0 基於這些檢查點來加速同步,辦法是跳過最近的檢查點以前的區塊鏈上的簽名驗證。你可能會說,“你沒搞錯吧?你不是可以通過配置 assumevalid=0
來強迫節點驗證所有簽名嗎?”確實可以,但這個設定對早於 v0.14 的 Bitcoin Core 沒有任何作用。(v0.14 是這個配置參數第一次引入。)
因此,我認為,v0.5 整體上比 v0.4 要更慢,而且,早期的同步性能測試實際上是 作弊/不公平的比較。
老版本 vs. 新版本
那麼,最新的 v22 版本與這些老版本相比,性能上有多大提升呢?
同步到區塊 12 4000:
- v22 比 v0.3 快 17 倍
這些區塊都是空的,所以性能上的差別不是那麼明顯,但若同步了更多區塊鏈,就會顯著起來。
同步到區塊高度 25 8000:
- v22 比 v0.4 快 77 倍
- v22 比 v0.5 快 83 倍
同步到區塊 36 4000:
- v22 比 v0.6 快 40 倍
- v22 比 v0.7 快 38 倍
前向兼容性很難
你可能經常聽到一種說法:你可以運行非常老舊版本的比特幣軟件,它依然能跟現在的網絡兼容。當然,真正的答案要複雜得多、微妙得多。為了讓很老版本的比特幣軟件同步到現在的鏈頂端,你需要對軟件作一些變更。另一個棘手的地方是,如你縮減,並非所有在共識上重要的代碼都是由比特幣開發者編寫的 —— 有些時候是第三方的庫,而且這些庫也會隨時間變更,從而讓軟件構建的流程自身變成可能導致共識失敗的原因!
(完)