1. 程式人生 > >比特幣網路架構及節點發現分析

比特幣網路架構及節點發現分析

一、P2P網路架構

比特幣採用了基於網際網路的點對點(P2P:peer-to-peer)分散式網路架構。

比特幣網路可以認為是按照比特幣P2P協議執行的一系列節點的集合。

本文來分析下比特幣網路,瞭解它跟傳統中心化網路的區別,以及比特幣網路是如何發現相鄰節點的。

 

二、節點型別及分工

儘管比特幣P2P網路中的各個節點相互對等,但是根據所提供的功能不同,各節點可能具有不同的分工。每個比特幣節點都是路由、區塊鏈資料庫、挖礦、錢包服務的功能集合。一個全節點(full node)包括下圖所示的四個功能:

下圖為一個包含四個完整功能的比特幣網路節點:錢包、礦工、完整區塊鏈、網路路由節點。每個節點都參與全網路的路由功能,同時也可能包含其他功能。每個節點都參與驗證並傳播交易及區塊資訊,發現並維持與對等節點的連線。名為“網路路由節點”的橙色圓圈即表示該路由功能。

一些節點保有一份完整的、最新的區塊鏈拷貝,這樣的節點被稱為“全節點”。全節點能夠獨立自主地校驗所有交易,而不需藉由任何外部參照。

另外還有一些節點只保留了區塊鏈的一部分,它們通過一種名為“簡易支付驗證(SPV)”的方式來完成交易驗證。這樣的節點被稱為“SPV節點”,又叫“輕量級節點”。

 

三、對等節點發現

為了能夠加入到比特幣網路,比特幣客戶端會做一下幾件事情:

a、節點會記住它最近成功連線的網路節點,當重新啟動後它可以迅速與先前的對等節點網路重新建立連線。

b、節點會在失去已有連線時嘗試發現新節點。

c、當建立一個或多個連線後,節點將一條包含自身IP地址訊息傳送給其相鄰節點。相鄰節點再將此訊息依次轉發給它們各自的相鄰節點,從而保證節點資訊被多個節點所接收、保證連線更穩定。

d、新接入的節點可以向它的相鄰節點發送獲取地址getaddr訊息,要求它們返回其已知對等節點的IP地址列表。節點可以找到需連線到的對等節點。

e、在節點啟動時,可以給節點指定一個正活躍節點IP, 如果沒有,客戶端也維持一個列表,列出了那些長期穩定執行的節點。這樣的節點也被稱為種子節點(其實和BT下載的種子檔案道理是一樣的),就可以通過種子節點來快速發現網路中的其他節點。

1、比特幣的核心部分維護一個在啟動時可以連線的對等節點列表。當一個完整的節點第一次啟動時,它必須被自舉(bootstrapped)到網路。這個過程如今在比特幣的核心部分通過一個短名單上的DNS種子自動執行。選項-dnsseed可以被用來定義這種行為,預設的設定是1。DNS請求返回一個可連線的IP地址列表。比特幣客戶端從那裡可以連線到整個比特幣網路。

2、自舉的另外一種方法是使用引數-seednode=<ip>。通過這個引數,使用者可以預先定義連線到哪個伺服器,並在建立對等節點列表之後斷開連線。另外一個方法是在啟動比特幣核心時配置-connect=<ip>引數來選擇連線到哪些對等節點(未被配置的IP將不會被連線)。新增對等節點的最後一種方法是通過引數-addnode=<ip>新增一個單獨的節點到對等節點列表中。

自舉過程完成後,節點向其對等節點發送一個包含其自身IP地址的addr訊息。其對等的每個節點向它們自己的對等節點轉發這個資訊,以便進一步擴大連線池。

通過getpeerinfo命令可以檢視某個節點所連線的對等節點及相關的資料。

3、連線到對等節點

節點通過傳送version訊息連線到一個對等節點。訊息version 包含了節點的版本資訊、塊資訊和距離遠端節點的時間。一旦這個訊息被對等節點收到,它必須回覆一個verack。如果它願意建立對等關係,它將傳送自己的version訊息。

一旦建立對等關係,節點可以向遠端節點發送getaddr和addr訊息來獲得其它的對等節點資訊。為了維持與對等節點的連線,節點預設情況下每30分鐘內會給對等節點至少傳送一次資訊。如果超過90分鐘沒有收到回覆,節點會認為連線已經斷開。

4、塊廣播

在與對等節點建立連線後,雙方互發包含最新塊雜湊值的getblocks訊息。如果某個節點堅信其擁有最新的塊資訊或者有更長的鏈,它將傳送一個inv訊息,其中包含至多500個最新塊的雜湊值,以此來表明它的鏈更長。收到的節點使用getdata來請求塊的詳細資訊,而遠端的節點通過命令block來發送這些資訊。在500個塊的資訊被處理完之後,節點可以通過getblocks請求更多的塊資訊。這些塊在被接收節點認證之後得到確認。

新塊的確認也可通過礦工挖到併發布的塊來發現。其擴散過程和上述類似。通過之前的連線,新塊以inv訊息釋出出去,而接收節點可以通過getdata請求這些塊的詳細資訊。

5、交易的廣播

和對等節點的交易通過inv訊息來實現。如果收到了getdata資訊,那麼交易通過傳送tx實現。對等節點收到有效的交易的資訊後會通過類似的方式將其擴散。如果交易的資訊在一段時間內沒有被放進塊中,那麼交易將被從記憶體池中清除,而原節點將重新發送交易資訊。

6、行為不端的節點

對於所有的廣播,那些行為不端的節點(佔用頻寬和通過釋出錯誤資訊來浪費計算資源)將收到懲罰。如果一個節點懲罰分數超過門限值-banscore=<n>,它將被禁止加入網路若干秒。這個時間由引數-bantime=<n>定義,預設值是86400秒,即24小時。

7、警告

為了應對可能出現的bug和攻擊,比特幣開發者提供了比特幣警告服務RSS。比特幣使用者通過命令getinfo可以檢視針對其特定客戶端版本的錯誤資訊。

這些資訊通過allert訊息儘可能多擴散出去給每一個連線的對等節點。

錯誤資訊採用特定的ECDSA私有金鑰簽名,只被極少數的開發者控制。

補充資源:如果你想了解各種訊息的詳細結構和所有的訊息類別,可以參考比特幣Wiki上的協議說明。

四、通過dns seeds獲取節點列表資料

1、dns seed是什麼

返回比特幣網路上完整節點IP地址的DNS伺服器,用於協助發現節點。

2、哪裡可以檢視到

我們在bitcoin原始碼中,搜尋關鍵詞“seed.bitcoin.sipa.be”,目前最新的程式碼位置在chainparams.cpp中。

3、怎麼得到節點列表

這裡需要用到一個開源專案,專案地址

下面開始進行具體操作。

我們用的dns是seed.bitcoin.sipa.be

[email protected]:~/bitcoin-seeder$ dig -t NS testnet-seed.bitcoin.jonasschnelli.ch

再次檢視專案資料夾,發現多了兩個檔案

dnsseed.dat

dnsseed.dump

檢視dnsseed.dump檔案,這樣就得到了節點列表。

4、總結

dns seed資料是硬編碼到專案中,這也就解決了分散式系統的關於雞生蛋還是蛋生雞的問題。

五、節點通訊簡述

比特幣節點通常採用TCP協議、使用8333埠與相鄰節點建立連線, 建立連線時也會有認證“握手”的通訊過程,用來確定協議版本,軟體版本,節點IP,區塊高度等。

當節點連線到相鄰節點後,接著就開始跟相鄰節點同步區塊鏈資料(輕量級錢包應用其實不會同步所有區塊資料),節點們會交換一個getblocks訊息,它包含本地區塊鏈最頂端的雜湊值。如果某個節點識別出它接收到的雜湊值並不屬於頂端區塊,而是屬於一個非頂端區塊的舊區塊,就說其自身的本地區塊鏈比其他節點的區塊鏈更長,並告訴其他節點需要補充區塊,其他節點發送getdata訊息來請求區塊,驗證後更新到本地區塊鏈中。

參考文章: