精通比特幣(第八章)【比特幣網路】

風靈使發表於2018-10-09

8.1 P2P網路架構

比特幣採用了基於國際網際網路(Internet)的P2P(peer-to-peer)網路架構。P2P是指位於同一網路中的每臺計算機都彼此對等,各個節點共同提供網路服務,不存在任何“特殊”節點。每個網路節點以“扁平(flat)”的拓撲結構相互連通。 在P2P網路中不存在任何服務端(server)、中央化的服務、以及層級結構。P2P網路的節點之間互動運作、協同處理:每個節點在對外提供服務的同時也使用網路中其他節點所提供的服務。P2P網路也因此具有可靠性、去中心化,以 及開放性。早期的國際網際網路就是P2P網路架構的一個典型用例:IP網路中的各個節點完全平等。當今的網際網路架構具有分層架構,但是IP協議仍然保留了扁平拓撲的結構。在比特幣之外,規模最大也最成功的P2P技術應用是在檔案分享 領域:Napster是該領域的先鋒,BitTorrent是其架構的最新演變。

比特幣所採用的P2P網路架構不僅僅是選擇拓撲結構這樣簡單。比特幣被設計為一種點對點的數字現金系統,它的網路架構既是這種核心特性的反映,也是該特性的基石。去中心化控制是設計時的核心原則,它只能通過維持一種扁平化、 去中心化的P2P共識網路來實現。

“比特幣網路”是按照比特幣P2P協議執行的一系列節點的集合。除了比特幣P2P協議之外,比特幣網路中也包含其他協議。例如Stratum協議就被應用於挖礦、以及輕量級或移動端比特幣錢包之中。閘道器(gateway)路由伺服器提供這些協 議,使用比特幣P2P協議接入比特幣網路,並把網路擴充到執行其他協議的各個節點。例如,Stratum伺服器通過 Stratum協議將所有的Stratum挖礦節點連線至比特幣主網路、並將Stratum協議橋接(bridge)至比特幣P2P協議之 上。我們使用“擴充套件比特幣網路(extended bitcoin network)”指代所有包含比特幣P2P協議、礦池挖礦協議、Stratum 協議以及其他連線比特幣系統元件相關協議的整體網路結構。

8.2 節點型別及角色

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

圖8-1一個包含四個完整功能的比特幣網路節點:錢包、礦工、完整區塊鏈、網路路由節點

圖8-1比特幣網路節點,具有所有四個功能:錢包,礦工,完整的區塊鏈資料庫和網路路由

每個節點都參與全網路的路由功能,同時也可能包含其他功能。每個節點都參與驗證並傳播交易及區塊資訊,發現並維持與對等節點的連線。在圖8-1所示的全節點用例中,名為“網路路由節點”的橙色圓圈字母‘N’即表示該路由功能。

一些節點保有一份完整的、最新的區塊鏈拷貝,這樣的節點被稱為“全節點”。全節點能夠獨立自主地校驗所有交易,而不需藉由任何外部參照。另外還有一些節點只保留了區塊鏈的一部分,它們通過一種名為“簡易支付驗證(SPV)”的方 式來完成交易驗證。這樣的節點被稱為“SPV節點”,又叫“輕量級節點”。在如上圖所示的全節點用例中,名為完整區塊鏈的藍色圓圈字母“B”即表示了全節點區塊鏈資料庫功能。在圖8-3中,SPV節點沒有此藍色圓圈,以示它們沒有區塊鏈的完整拷貝。

挖礦節點通過執行在特殊硬體裝置上的工作量證明(proof-of-work)演算法,以相互競爭的方式建立新的區塊。一些挖礦 節點同時也是全節點,保有區塊鏈的完整拷貝;還有一些參與礦池挖礦的節點是輕量級節點,它們必須依賴礦池伺服器維護的全節點進行工作。在全節點用例中,挖礦功能如圖中名為“礦工”的黑色圓圈字母“M”所示。

使用者錢包也可以作為全節點的一部分,這在桌面比特幣客戶端中比較常見。當前,越來越多的使用者錢包都是SPV節點, 尤其是執行於諸如智慧手機等資源受限裝置上的比特幣錢包應用;而這正變得越來越普遍。在圖8-1中,名為“錢包”的綠色圓圈字母“W”代表錢包功能。

在比特幣P2P協議中,除了這些主要的節點型別之外,還有一些伺服器及節點也在執行著其他協議,例如特殊礦池挖礦 協議、輕量級客戶端訪問協議等。

圖8-2描述了擴充套件比特幣網路中最為常見的節點型別。

圖8-2描述了擴充套件比特幣網路中最為常見的節點型別

圖8-2描述了擴充套件比特幣網路中最為常見的節點型別。

8.3 擴充套件比特幣網路

執行比特幣P2P協議的比特幣主網路由大約5000-8000個執行著不同版本比特幣核心客戶端(Bitcoin Core)的監聽節 點、以及幾百個執行著各類比特幣P2P協議的應用(例如Bitcoin Classic, Bitcoin Unlimited, BitcoinJ, Libbitcoin, btcd, and bcoin等)的節點組成。比特幣P2P網路中的一小部分節點也是挖礦節點,它們競爭挖礦、驗證交易、並建立新的區塊。許多連線到比特幣網路的大型公司執行 著基於Bitcoin核心客戶端的全節點客戶端,它們具有區塊鏈的完整拷貝及網路節點,但不具備挖礦及錢包功能。這些節點是網路中的邊緣路由器(edge routers),通過它們可以搭建其他服務,例如交易所、錢包、區塊瀏覽器、商家支付處理(merchant payment processing)等。

如前文所述,擴充套件比特幣網路既包括了執行比特幣P2P協議的網路,又包含執行特殊協議的網路節點。比特幣P2P主網路上連線著許多礦池伺服器以及協議閘道器,它們把執行其他協議的節點連線起來。這些節點通常都是礦池挖礦節點(參見挖礦章節)以及輕量級錢包客戶端,它們通常不具備區塊鏈的完整備份。

圖8-3描述了擴充套件比特幣網路,它包括了多種型別的節點、閘道器伺服器、邊緣路由器、錢包客戶端以及它們相互連線所 需的各類協議。

圖8-3 具有多種節點型別、閘道器及協議的擴充套件比特幣網路

圖8-3 顯示各種節點型別,閘道器和協議的擴充套件比特幣網路

8.4比特幣傳播網路

雖然比特幣P2P網路服務於各種各樣的節點型別的一般需求,但是對於比特幣挖掘節點的專門需求,它顯示出太高的網路延遲。

比特幣礦業公司正在進行時間敏感的競爭,以解決工作證明問題,並擴大區塊鏈(參見[挖礦]章節)。在參加比賽時,比特幣礦工必須最大限度地縮短獲勝塊的傳播與下一輪比賽開始之間的時間。在採礦方面,網路延遲與利潤率直接相關。

比特幣傳播網路是一種嘗試最小化礦工之間傳輸塊的延遲的網路。原始的比特幣傳播網路是由核心開發商Matt Corallo於2015年建立的,以便能夠以非常低的延遲在礦工之間快速同步塊。該網路由世界各地的亞馬遜Web服務基礎架構上託管的幾個專門的節點組成,並且連線大多數礦工和採礦池。

原始的比特幣傳播網路在2016年被替換為Fast Internet Bitcoin Relay Engine or FIBRE,也由核心開發商Matt Corallo建立。 FIBER是一種基於UDP的中繼網路,可以中繼節點網路內的塊。 FIBER實現了compact block,以進一步減少傳輸的資料量和網路延遲。

康奈爾大學研究的另一箇中繼網路(仍在提案階段)是 Falcon。 Falcon使用“直通路由”而不是“儲存轉發”來減少延遲,通過傳播塊的部分,而不是等待直到接收到完整的塊。

傳播網路不是比特幣的P2P網路的替代品。相反,它們是覆蓋網路,在具有特殊需求的節點之間提供額外的連線像高速公路不是農村道路的替代品,而是交通繁忙的兩點之間的快捷方式,您仍然需要小路連線高速公路。

8.5 網路發現

當新的網路節點啟動後,為了能夠參與協同運作,它必須發現網路中的其他比特幣節點。新的網路節點必須發現至少一個網路中存在的節點並建立連線。由於比特幣網路的拓撲結構並不基於節點間的地理位置,因此各個節點之間的地理資訊完全無關。在新節點連線時,可以隨機選擇網路中存在的比特幣節點與之相連。

節點通常採用TCP協議、使用8333埠(該埠號通常是比特幣所使用的,除8333埠外也可以指定使用其他埠) 與已知的對等節點建立連線。在建立連線時,該節點會通過傳送一條包含基本認證內容的version訊息開始“握手”通訊過 程(見圖8-4)。這一過程包括如下內容:

▷ nVersion

定義了客戶端所“說出”的比特幣P2P協議所採用的版本(例如:70002)。

▷ nLocalServices

一組該節點支援的本地服務列表,當前僅支援NODE_NETWORK

▷ nTime

當前時間

▷ addrYou

當前節點可見的遠端節點的IP地址

▷ addrMe

本地節點所發現的本機IP地址

▷ subver

指示當前節點執行的軟體型別的子版本號(例如:”/Satoshi:0.9.2.1/”)

▷ BaseHeight

當前節點區塊鏈的區塊高度 (version網路訊息的具體用例請參見GitHub

版本訊息始終是任何對等體傳送給另一個對等體的第一條訊息。 接收版本訊息的本地對等體將檢查遠端對等體報告的nVersion,並確定遠端對等體是否相容。 如果遠端對等體相容,則本地對等體將確認版本訊息,並通過傳送一個verack建立連線。

新節點如何找到對等體? 第一種方法是使用多個“DNS種子”來查詢DNS,這些DNS伺服器提供比特幣節點的IP地址列表。 其中一些DNS種子提供了穩定的比特幣偵聽節點的靜態IP地址列表。 一些DNS種子是BIND(Berkeley Internet Name Daemon)的自定義實現,它從搜尋器或長時間執行的比特幣節點收集的比特幣節點地址列表中返回一個隨機子集。 Bitcoin Core客戶端包含五種不同DNS種子的名稱。 不同DNS種子的所有權和多樣性的多樣性為初始引導過程提供了高水平的可靠性。 在Bitcoin Core客戶端中,使用DNS種子的選項由選項switch -dnsseed控制(預設設定為1,以使用DNS種子)。

或者,不知道網路的引導節點必須被給予至少一個比特幣節點的IP地址,之後可以通過進一步介紹來建立連線。 命令列引數-seednode可用於連線到一個節點,僅用於將其用作種子。 在使用初始種子節點形成介紹後,客戶端將斷開連線並使用新發現的對等體。

圖8-4對等節點之間的初始握手

圖8-4 對等體之間的初始握手

當建立一個或多個連線後,新節點將一條包含自身IP地址的addr訊息傳送給其相鄰節點。相鄰節點再將此條addr訊息依 次轉發給它們各自的相鄰節點,從而保證新節點資訊被多個節點所接收、保證連線更穩定。另外,新接入的節點可以向 它的相鄰節點傳送getaddr訊息,要求它們返回其已知對等節點的IP地址列表。通過這種方式,節點可以找到需連線到 的對等節點,並向網路釋出它的訊息以便其他節點查詢。圖8-5描述了這種地址發現協議。

圖8-5地址廣播及發現

圖8-5 地址傳播和發現

節點必須連線到若干不同的對等節點才能在比特幣網路中建立通向比特幣網路的種類各異的路徑(path)。由於節點可以隨時加入和離開,通訊路徑是不可靠的。因此,節點必須持續進行兩項工作:在失去已有連線時發現新節點,並在其他節點啟動時為其提供幫助。節點啟動時只需要一個連線,因為第一個節點可以將它引薦給它的對等節點,而這些節點又會進一步提供引薦。一個節點,如果連線到大量的其他對等節點,這既沒必要,也是對網路資源的浪費。在啟動完成 後,節點會記住它最近成功連線的對等節點;因此,當重新啟動後它可以迅速與先前的對等節點網路重新建立連線。如果先前的網路的對等節點對連線請求無應答,該節點可以使用種子節點進行重啟動。

在執行比特幣核心客戶端的節點上,您可以使用 getpeerinfo 命令列出對等節點連線資訊:

$ bitcoin-cli getpeerinfo

{
    "addr" : "85.213.199.39:8333",
    "services" : "00000001",
    "lastsend" : 1405634126,
    "lastrecv" : 1405634127,
    "bytessent" : 23487651,
    "bytesrecv" : 138679099,
    "conntime" : 1405021768,
    "pingtime" : 0.00000000,
    "version" : 70002,
    "subver" : "/Satoshi:0.9.2.1/",
    "inbound" : false,
    "startingheight" : 310131,
    "banscore" : 0,
    "syncnode" : true
},
{
    "addr" : "58.23.244.20:8333",
    "services" : "00000001",
    "lastsend" : 1405634127,
    "lastrecv" : 1405634124,
    "bytessent" : 4460918,
    "bytesrecv" : 8903575,
    "conntime" : 1405559628,
    "pingtime" : 0.00000000,
    "version" : 70001,
    "subver" : "/Satoshi:0.8.6/",
    "inbound" : false,
    "startingheight" : 311074,
    "banscore" : 0,
    "syncnode" : false
}

使用者可以通過提供 -connect=<IP地址> 選項來指定一個或多個IP地址,從而達到覆蓋自動節點管理功能並指定IP地址列表的目的。如果採用此選項,節點只連線到這些選定的節點IP地址,而不會自動發現並維護對等節點之間的連線。

如果已建立的連線沒有資料通訊,所在的節點會定期傳送資訊以維持連線。如果節點持續某個連線長達90分鐘沒有任何通訊,它會被認為已經從網路中斷開,網路將開始查詢一個新的對等節點。因此,比特幣網路會隨時根據變化的節點及網路問題進行動態調整,不需經過中心化的控制即可進行規模增減的有機調整。

8.6 全節點

全節點是指維持包含全部交易資訊的完整區塊鏈的節點。更加準確地說,這樣的節點應當被稱為完整區塊鏈節點”。在比特幣發展的早期,所有節點都是全節點;當前的比特幣核心客戶端也是完整區塊鏈節點。但在過去的兩年中出現了許多 新型客戶端,它們不需要維持完整的區塊鏈,而是作為輕量級客戶端執行。在下面的章節裡我們會對這些輕量級客戶端進行詳細介紹。

完整區塊鏈節點保有完整的、最新的包含全部交易資訊的比特幣區塊鏈拷貝,這樣的節點可以獨立地進行建立並校驗區塊鏈,從第一區塊(創世區塊)一直建立到網路中最新的區塊。完整區塊鏈節點可以獨立自主地校驗任何交易資訊,而不需要藉助任何其他節點或其他資訊來源。完整區塊節點通過比特幣網路獲取包含交易資訊的新區塊更新,在驗證無誤後將此更新合併至本地的區塊鏈拷貝之中。

執行完整區塊鏈節點可以給您一種純粹的比特幣體驗:不需藉助或信任其他系統即可獨立地對所有交易資訊進行驗證。 辨別您是否在執行全節點是十分容易的:只需要檢視您的永久性儲存裝置(如硬碟)是否有超過20GB的空間被用來儲存完整區塊鏈即可。如果您需要很大的磁碟空間、並且同步比特幣網路耗時2至3天,那麼您使用的正是全節點。這就是擺脫中心化管理、獲得完全的獨立自由所要付出的代價。

儘管目前還有一些使用不同程式語言及軟體架構的其他的完整區塊鏈客戶端存在,但是最常用的仍然是比特幣核心客戶 端,它也被稱為“Satoshi客戶端”。比特幣網路中超過90%的節點執行著各個版本的比特幣核心客戶端。如前文所述,它 可以通過節點間傳送的version訊息或通過getpeerinfo命令所得到的子版本字串“Satoshi”加以辨識,例如 /Satoshi: 0.8.6/。

8.7 交換“庫存清單”

一個全節點連線到對等節點之後,第一件要做的事情就是構建完整的區塊鏈。如果該節點是一個全新節點,那麼它就不包含任何區塊鏈資訊,它只知道一個區塊——靜態植入在客戶端軟體中的創世區塊。新節點需要下載從0號區塊(創世區塊)開始的數十萬區塊的全部內容,才能跟網路同步、並重建全區塊鏈。

同步區塊鏈的過程從傳送version訊息開始,這是因為該訊息中含有的BestHeight欄位標示了一個節點當前的區塊鏈高度(區塊數量)。節點可以從它的對等節點中得到版本訊息,瞭解雙方各自有多少區塊,從而可以與其自身區塊鏈所擁 有的區塊數量進行比較。對等節點們會交換一個getblocks訊息,其中包含他們本地區塊鏈的頂端區塊雜湊值(指紋)。如果某個對等節點識別出它接收到的雜湊值並不屬於頂端區塊,而是屬於一個非頂端區塊的舊區塊,那麼它就能推斷出:其自身的本地區塊鏈比其他對等節點的區塊鏈更長。

擁有更長區塊鏈的對等節點比其他節點有更多的區塊,可以識別出哪些區塊們是其他節點需要“補充”的。它會識別出第 一批可供分享的500個區塊,通過使用inv(inventory)訊息把這些區塊的雜湊值傳播出去。缺少這些區塊的節點便可以 通過各自傳送的getdata訊息來請求得到全區塊資訊,用包含在inv訊息中的雜湊值來確認是否為正確的被請求的區塊, 從而讀取這些缺失的區塊。

在下例中,我們假設某節點只含有創世區塊。它收到了來自對等節點的inv訊息,其中包含了區塊鏈中後500個區塊的雜湊值。於是它開始向所有與之相連的對等節點請求區塊,並通過分攤工作量的方式防止單一對等節點被批量請求所壓垮。該節點會追蹤記錄其每個對等節點連線上“正在傳輸”(指那些它已經發出了請求但還沒有接收到)的區塊數量,並且檢查該數量有沒有超過上限( MAX_BLOCKS_IN_TRANSIT_PER_PEER )。用這種辦法,如果一個節點需要更新大量區塊,它會在上一請求完成後才傳送對新區塊的請求,從而允許對等節點控制更新速度,不至於壓垮網路。每一個區塊在被接收後就會被新增至區塊鏈中,這一過程詳見挖礦一章。隨著本地區塊鏈的逐步建立,越來越多的區塊被請求和接收,整個過程將一直持續到該節點與全網路完成同步為止。

每當一個節點離線,不管離線時間有多長,這個與對等節點比較本地區塊鏈並恢復缺失區塊的過程就會被觸發。如果一 個節點只離線幾分鐘,可能只會缺失幾個區塊;當它離線長達一個月,可能會缺失上千個區塊。但無論哪種情況,它都 會從傳送 getblocks 訊息開始,收到一個inv響應,接著開始下載缺失的區塊。庫存清單和區塊廣播協議如圖8-6所示。

節點通過從對等節點讀取區塊來同步區塊鏈圖8-6

圖8-6節點通過從對等體檢索區塊同步區塊鏈

8.8 簡易支付驗證 (Simplified Payment Verification (SPV) )節點

並非所有的節點都有能力儲存完整的區塊鏈。許多比特幣客戶端被設計成執行在空間和功率受限的裝置上,如智慧電話、平板電腦、嵌入式系統等。對於這樣的裝置,通過簡化的支付驗證(SPV)的方式可以使它們在不必儲存完整區塊鏈的情況下進行工作。這種型別的客端被稱為SPV客戶端或輕量級客戶端。隨著比特幣的使用熱潮,SPV節點逐漸變成比特幣節點(尤其是比特幣錢包)所採用的最常見的形式。

SPV節點只需下載區塊頭,而不用下載包含在每個區塊中的交易資訊。由此產生的不含交易資訊的區塊鏈,大小隻有完整區塊鏈的1/1000。SPV節點不能構建所有可用於消費的UTXO的全貌,這是由於它們並不知道網路上所有交易的完整資訊。SPV節點驗證交易時所使用的方法略有不同,這個方法需依賴對等節點“按需”提供區塊鏈相關部分的區域性檢視。

打個比方來說,每個全節點就像是一個在陌生城市裡的遊客,他帶著一張包含每條街道、每個地址的詳細地圖。相比之 下,SPV節點就像是這名陌生城市裡的遊客只知道一條主幹道的名字,通過隨機詢問該城市的陌生人來獲取分段道路指示。雖然兩種遊客都可以通過實地考察來驗證一條街是否存在,但沒有地圖的遊客不知道每個小巷中有哪些街道,也不知道附近還有什麼其他街道。沒有地圖的遊客在“教堂街23號”的前面,並不知道這個城市裡是否還有其他若干條“教堂街 23號”,也不知道面前的這個是否是要找的那個。對他來說,最好的方式就是向足夠多的人問路,並且希望其中一部分人不是要試圖搶劫他。

簡易支付驗證是通過參考交易在區塊鏈中的深度,而不是高度,來驗證它們。一個擁有完整區塊鏈的節點會構造一條驗證鏈,這條鏈是由沿著區塊鏈按時間倒序一直追溯到創世區塊的數千區塊及交易組成。而一個SPV節點會驗證所有區塊的鏈(但不是所有的交易),並且把區塊鏈和有關交易連結起來。

例如,一個全節點要檢查第300,000號區塊中的某個交易,它會把從該區塊開始一直回溯到創世區塊的300,000個區塊全部都連結起來,並建立一個完整的UTXO資料庫,通過確認該UTXO是否還未被支付來證實交易的有效性。SPV節點則不能驗證UTXO是否還未被支付。相反地,SPV節點會在該交易資訊和它所在區塊之間用merkle路徑(見“ Merkle 樹”章節)建立一條連結。然後SPV節點一直等待,直到序號從300,001到300,006的六個區塊堆疊在該交易所在的區塊之上,並通過確立交易的深度是在第300,006區塊~第300,001區塊之下來驗證交易的有效性。事實上,如果網路中的其他節點都接受了第300,000區塊,並通過足夠的工作在該塊之上又生成了六個區塊,根據代理閘道器協議,就可以證明該交易不是雙重支付。

如果一個交易實際上不存在,SPV節點不會誤認為該交易存在於某區塊中。SPV節點會通過請求merkle路徑證明以及驗證區塊鏈中的工作量證明,來證實交易的存在性。可是,一個交易的存在是可能對SPV節點“隱藏”的。SPV節點毫無疑問可以證實某個交易的存在性,但它不能驗證某個交易(譬如同一個UTXO的雙重支付)不存在,這是因為SPV節點沒有一份關於所有交易的記錄。這個漏洞會被針對SPV節點的拒絕服務攻擊或雙重支付型攻擊所利用。為了防禦這些攻擊,SPV節點需要隨機連線到多個節點,以增加與至少一個可靠節點相連線的概率。這種隨機連線的需求意味著SPV節 點也容易受到網路分割槽攻擊或Sybil攻擊。在後者情況中,SPV節點被連線到虛假節點或虛假網路中,沒有通向可靠節點或真正的比特幣網路的連線。

在絕大多數的實際情況中,具有良好連線的SPV節點是足夠安全的,它在資源需求、實用性和安全性之間維持恰當的平衡。當然,如果要保證萬無一失的安全性,最可靠的方法還是執行完整區塊鏈的節點。

提示 完整的區塊鏈節點是通過檢查整個鏈中在它之下的數千個區塊來保證這個UTXO沒有被支付,從而驗證交易。而 SPV節點是通過檢查在其上面的區塊將它壓在下面的深度來驗證交易。

SPV節點使用的是一條getheaders訊息,而不是getblocks訊息來獲得區塊頭。發出響應的對等節點將用一條headers 訊息傳送多達2000個區塊頭。這一過程和全節點獲取所有區塊的過程沒什麼區別。SPV節點還在與對等節點的連線上設定了過濾器,用以過濾從對等節點發來的未來區塊和交易資料流。任何目標交易都是通過一條getdata的請求來讀取的。對等節點生成一條包含交易資訊的tx訊息作為響應。區塊頭的同步過程如圖8-7所示。

圖8-7 SPV節點同步區塊頭

圖8-7SPV節點同步區塊頭

由於SPV節點需要讀取特定交易從而選擇性地驗證交易,這樣就又產生了隱私風險。與全區塊鏈節點收集每一個區塊內的全部交易所不同的是,SPV節點對特定資料的請求可能無意中透露了錢包裡的地址資訊。例如,監控網路的第三方可以跟蹤某個SPV節點上的錢包所請求的全部交易資訊,並且利用這些交易資訊把比特幣地址和錢包的使用者關聯起來,從而損害了使用者的隱私。

在引入SPV節點/輕量級節點後不久,比特幣開發人員就新增了一個新功能:Bloom過濾器,用以解決SPV節點的隱私風 險問題。Bloom過濾器通過一個採用概率而不是固定模式的過濾機制,允許SPV節點只接收交易資訊的子集,同時不會精確洩露哪些是它們感興趣的地址。

在引入SPV /輕量級節點後不久,比特幣開發人員新增了一個名為bloom過濾器的功能來解決SPV節點的隱私風險。 Bloom過濾器允許SPV節點接收交易的一個子集,通過使用概率而不是固定模式的過濾機制無需精確地揭示他們感興趣的地址。

8.9 Bloom過濾器

Bloom過濾器是一個允許使用者描述特定的關鍵片語合而不必精確表述的基於概率的過濾方法。它能讓使用者在有效搜尋關鍵詞的同時保護他們的隱私。在SPV節點裡,這一方法被用來向對等節點傳送交易資訊查詢請求,同時交易地址不會被 暴露。

用我們之前的例子,一位手中沒有地圖的遊客需要詢問去特定地方的路線。如果他向陌生人詢問“教堂街23號在哪裡”, 不經意之間,他就暴露了自己的目的地。Bloom過濾器則會這樣問,“附近有帶‘堂’字的街道嗎?”這樣的問法包含了比之前略少的關鍵詞。這位遊客可以自己選擇包含資訊的多少,比如“以‘堂街’結尾”或者“‘教’字開頭的街道”。如果他問得越少,得到了更多可能的地址,隱私得到了保護,但這些地址裡面不乏無關的結果;如果他問得非常具體,他在得到較準確的結果的同時也暴露了自己的隱私。

Bloom過濾器可以讓SPV節點指定交易的搜尋模式,該搜尋模式可以基於準確性或私密性的考慮被調節。一個非常具體的Bloom過濾器會生成更準確的結果,但也會顯示該使用者錢包裡的使用的地址;反之,如果過濾器只包含簡單的關鍵詞,更多相應的交易會被搜尋出來,在包含若干無關交易的同時有著更高的私密性。

8.9.1 Bloom過濾器如何工作

Bloom過濾器的實現是由一個可變長度(N)的二進位制陣列(N位二進位制數構成一個位域)和數量可變(M)的一組雜湊函式組成。這些雜湊函式的輸出值始終在1和N之間,該數值與二進位制陣列相對應。並且該函式為確定性函式,也就是說任何一個使用相同Bloom過濾器的節點通過該函式都能對特定輸入得到同一個的結果。Bloom過濾器的準確性和私密效能通過改變長度(N)和雜湊函式的數量(M)來調節。

在圖8-8中,我們用一個小型的十六位陣列和三個雜湊函式來演示Bloom過濾器的應用原理。

圖8-8 一個由16位陣列和三個雜湊函式組成的簡易Bloom過濾

圖8-8一個簡單的Bloom過濾器的例子,有一個16位的欄位和三個雜湊函式

Bloom過濾器陣列裡的每一個數的初始值為零。關鍵詞被加到Bloom過濾器中之前,會依次通過每一個雜湊函式運算一 次。該輸入經第一個雜湊函式運算後得到了一個在1和N之間的數,它在該陣列(編號依次為1至N)中所對應的位被置 為1,從而把雜湊函式的輸出記錄下來。接著再進行下一個雜湊函式的運算,把另外一位置為1;以此類推。當全部M個 雜湊函式都運算過之後,一共有M個位的值從0變成了1,這個關鍵詞也被“記錄”在了Bloom過濾器裡。

圖8-9顯示了向圖8-8裡的簡易Bloom過濾器新增關鍵詞“A”。

圖8-9向簡易Bloom過濾器新增關鍵詞“A”

圖8-9向簡易Bloom過濾器新增關鍵詞“A”

增加第二個關鍵是就是簡單地重複之前的步驟。關鍵詞依次通過各雜湊函式運算之後,相應的位變為1,Bloom過濾器 則記錄下該關鍵詞。需要注意的是,當Bloom過濾器裡的關鍵詞增加時,它對應的某個雜湊函式的輸出值的位可能已經 是1了,這種情況下,該位不會再次改變。也就是說,隨著更多的關鍵詞指向了重複的位,Bloom過濾器隨著位1的增加 而飽和,準確性也因此降低了。該過濾器之所以是基於概率的資料結構,就是因為關鍵詞的增加會導致準確性的降低。 準確性取決於關鍵字的數量以及陣列大小(N)和雜湊函式的多少(M)。更大的陣列和更多的雜湊函式會記錄更多的 關鍵詞以提高準確性。而小的陣列及有限的雜湊函式只能記錄有限的關鍵詞從而降低準確性。

圖8-10顯示了向該簡易Bloom過濾器裡增加第二個關鍵詞“B”。

圖8-10向簡易Bloom過濾器裡增加第二個關鍵詞“B”

圖8-10向該簡易Bloom過濾器裡增加第二個關鍵詞“B”

為測試某一關鍵詞是否被記錄在某個Bloom過濾器中,我們將該關鍵詞逐一代入各雜湊函式中運算,並將所得的結果與原陣列進行對比。如果所有的結果對應的位都變為了1,則表示這個關鍵詞有可能已被該過濾器記錄。之所以這一結論並不確定,是因為這些位元組1也有可能是其他關鍵詞運算的重疊結果。簡單來說,Bloom過濾器正匹配代表著“可能是”。
圖8-11是一個驗證關鍵詞“X”是否在前述Bloom過濾器中的圖例。相應的位元位都被置為1,所以這個關鍵詞很有可能是匹配的。

圖8-11 驗證關鍵詞“X”是否存在於Bloom過濾器中。若結果為或然正匹配,則表示“可能是”

圖8-11在bloom過濾器中測試模式“X”的存在。 結果是一個概率正匹配,意思是“也許”

另一方面,如果我們代入關鍵詞計算後的結果某位為0,說明該關鍵詞並沒有被記錄在過濾器裡。負匹配的結果不是可能,而是一定。也就是說,負匹配代表著“一定不是”。
圖8-12是一個驗證關鍵詞“Y”是否存在於簡易Bloom過濾器中的圖例。圖中某個結果欄位為0,該欄位一定沒有被匹配。

圖8-12 驗證關鍵詞“Y”是否存在於Bloom過濾器中。若結果為必然負匹配,則表示“一定不是”

圖8-12在bloom過濾器中測試模式“Y”的存在。 結果是一個明確的否定匹配,意思是“絕對不!”

8.10 SPV節點如何使用Bloom過濾器

Bloom過濾器用於過濾SPV節點從其對等體接收的交易(和包含它們的塊),僅選擇SPV節點感興趣的交易,而不會洩露其感興趣的地址或金鑰。

SPV節點將初始化“過濾器”為“空”;在該狀態下,bloom過濾器將不匹配任何模式。然後,SPV節點將列出所有感興趣的地址,金鑰和雜湊,它將通過從其錢包控制的任何UTXO中提取公鑰雜湊和指令碼雜湊和交易ID來實現。 SPV節點然後將其中的每一個新增到Bloom過濾器,以便如果這些模式存在於交易中,則Bloom過濾器將“匹配”,而不會自動顯示模式。

然後,SPV節點將向對等體傳送一個過濾器載入訊息,其中包含在連線上使用的bloom過濾器。在對等體上,針對每個傳入交易檢查Bloom過濾器。完整節點根據bloom過濾器檢查交易的幾個部分,尋找匹配,包括:

交易ID

每個交易輸出的鎖定指令碼的資料元件(指令碼中的每個鍵和雜湊)

每個交易輸入

每個輸入簽名資料元件(或見證指令碼)

通過檢查所有這些元件,可以使用Bloom過濾器來匹配公鑰雜湊,指令碼,OP_RETURN值,簽名中的公鑰或智慧合同或複雜指令碼的任何未來元件。

在建立過濾器之後,對等體然後將針對bloom過濾器測試每個交易的輸出。只有與過濾器匹配的交易才會傳送到節點。

響應於來自節點的getdata訊息,對等體將傳送一個merkleblock訊息,該訊息僅包含與過濾器匹配的塊和每個匹配交易的merkle路徑(參見[merkle_trees])的塊頭。然後,對等體還將傳送包含由過濾器匹配的交易的tx訊息。

由於完整節點向SPV節點傳送交易,SPV節點丟棄任何誤報,並使用正確匹配的交易來更新其UTXO集和錢包餘額。隨著它更新自己的UTXO集檢視,它還會修改bloom過濾器,以匹配任何引用其剛剛發現的UTXO的交易。然後,完整節點使用新的bloom過濾器來匹配新交易,並重復整個過程。

設定bloom過濾器的節點可以通過傳送filteradd訊息將模式互動式新增到過濾器。要清除bloom過濾器,節點可以傳送一個過濾清除訊息。因為不可能從佈局過濾器中刪除模式,所以如果不再需要模式,則節點必須清除並重新傳送新的布隆過濾器。

BIP-37 (Peer Services)中定義了SPV節點的網路協議和布隆過濾機制。

8.11 SPV節點和隱私

實現SPV的節點的隱私比整個節點更弱。完整節點接收所有交易,因此不會顯示關於它的錢包中是否使用某個地址的資訊。 SPV節點接收與其錢包中的地址相關的經過過濾的列表。結果,它減少了所有者的隱私。

bloom過濾器是減少隱私損失的一種方式。沒有它們,SPV節點將不得不明確地列出它感興趣的地址,造成嚴重的隱私違規。然而,即使使用過濾器,對手監控SPV客戶端的流量或直接連線到它的P2P網路中的節點可以隨時隨地收集足夠的資訊來了解SPV客戶端的錢包中的地址。

8.12加密和認證連線

比特幣的大多數新使用者假設比特幣節點的網路通訊是加密的。其實,比特幣的原始實現就很明顯地完成了。雖然這不是完整節點的主要隱私問題,但SPV節點是一個很大的問題。

作為增加比特幣P2P網路隱私和安全性的一種方法,有兩種解決方案可以通過BIP-150/151提供通訊加密:Tor傳輸和P2P認證和加密。

8.12.1Tor網路傳輸

Tor代表洋蔥路由網路,是一個軟體專案和網路,通過提供匿名,不可追蹤和隱私的隨機網路路徑提供資料的加密和封裝。

Bitcoin Core提供了多種配置選項,允許您執行通過Tor網路傳輸的流量的比特幣節點。此外,Bitcoin Core還可以提供Tor隱藏服務,允許其他Tor節點通過Tor直接連線到您的節點。

從Bitcoin Core版本0.12開始,如果能夠連線到本地Tor服務,節點將自動提供隱藏的Tor服務。如果您安裝Tor並且Bitcoin Core程式作為具有足夠許可權的使用者訪問Tor認證cookie的使用者執行,則應自動執行。使用debug標誌開啟Bitcoin Core對於Tor服務的除錯,如下所示:

$ bitcoind --daemon --debug=tor

你應該在日誌中看到“tor:ADD_ONION success”,表示Bitcoin Core已經向Tor網路新增了隱藏的服務。

您可以在Bitcoin Core文件(docs / tor.md)和各種線上教程中找到有關執行Bitcoin Core作為Tor隱藏服務的更多說明。

8.12.2對等認證和加密

BIP-150和BIP-151兩種比特幣改進方案在比特幣P2P網路中增加了對P2P認證和加密的支援。這兩個BIP定義了可由相容的比特幣節點提供的可選服務。 BIP-151啟用了支援BIP-151的兩個節點之間的所有通訊的協商加密。 BIP-150提供可選的對等認證,允許節點使用ECDSA和私鑰對對方的身份進行身份驗證。 BIP-150要求在認證之前,兩個節點按照BIP-151建立了加密通訊。

截至2017年1月,BIP-150和BIP-151未在Bitcoin Core中實施。但是,這兩個提案已由至少一個名為bcoin的替代比特幣客戶端實施。

BIP-150和BIP-151允許使用者執行連線到受信任的完整節點的SPV客戶端,使用加密和身份驗證來保護SPV客戶端的隱私。

此外,可以使用身份驗證來建立可信比特幣節點的網路,並防止中間人攻擊。最後,P2P加密(如果廣泛部署)將加強比特幣對流量分析和隱私侵權監控的阻力,特別是在網際網路使用受到嚴格控制和監控的極權主義國家。

標準定義在BIP-150 (Peer Authentication) and BIP-151 (Peer-to-Peer Communication Encryption).

8.13交易池

比特幣網路中幾乎每個節點都會維護一份未確認交易的臨時列表,被稱為記憶體池或交易池。節點們利用這個池來追蹤記錄那些被網路所知曉、但還未被區塊鏈所包含的交易。例如,儲存使用者錢包的節點會利用這個交易池來記錄那些網路已經接收但還未被確認的、屬於該使用者錢包的預支付資訊。

隨著交易被接收和驗證,它們被新增到交易池並通知到相鄰節點處,從而傳播到網路中。

有些節點的實現還維護一個單獨的孤立交易池。如果一個交易的輸入與某未知的交易有關,如與缺失的父交易相關,該孤立交易就會被暫時儲存在孤立交易池中直到父交易的資訊到達。

當一個交易被新增到交易池中,會同時檢查孤立交易池,看是否有某個孤立交易引用了此交易的輸出(子交易)。任何匹配的孤立交易會被進行驗證。如果驗證有效,它們會從孤立交易池中刪除,並新增到交易池中,使以其父交易開始的鏈變得完整。對新加入交易池的交易來說,它不再是孤立交易。前述過程重複遞迴尋找進一步的後代,直至所有的後代都被找到。通過這一過程,一個父交易的到達把整條鏈中的孤立交易和它們的父級交易重新結合在一起,從而觸發了整條獨立交易鏈進行級聯重構。

交易池和孤立交易池(如有實施)都是儲存在本地記憶體中,並不是儲存在永久性儲存裝置(如硬碟)裡。更準確的說,它們是隨網路傳入的訊息動態填充的。節點啟動時,兩個池都是空閒的;隨著網路中新交易不斷被接收,兩個池逐漸被填充。

有些比特幣客戶端的實現還維護一個UTXO資料庫,也稱UTXO池,是區塊鏈中所有未支付交易輸出的集合。“UTXO 池”的名字聽上去與交易池相似,但它代表了不同的資料集。UTXO池不同於交易池和孤立交易池的地方在於,它在初始化時不為空,而是包含了數以百萬計的未支付交易輸出條目,有些條目的歷史甚至可以追溯至2009年。UTXO池可能會被安置在本地記憶體,或者作為一個包含索引的資料庫表安置在永久性儲存裝置中。

交易池和孤立交易池代表的是單個節點的本地視角。取決於節點的啟動時間或重啟時間,不同節點的兩池內容可能有很大差別。相反地,UTXO池代表的是網路的突顯共識,因此,不同節點間UTXO池的內容差別不大。此外,交易池和孤立交易池只包含未確認交易,而UTXO池之只包含已確認交易。

相關文章