比特幣是構建在互聯網之上的點對點網路體系結構。術語點對點(P2P)意味著參與網路的電腦是彼此對等的,它們都是平等的,沒有"特殊"節點,並且所有節點都分攤提供網路服務的負擔。網路節點以"扁平"拓撲互連在網狀網路中。網路中沒有中央伺服器,沒有集中化服務,也沒有層次結構。 P2P網路中的節點同時提供和消費服務,彼此互惠。P2P網路具有天然的彈性,去中心性和開放性。P2P網路架構的一個卓越例子就是早期的互聯網本身,IP網路上的節點是平等的。如今,互聯網結構更有層次,但互聯網協議仍然保留了其扁平拓撲的本質。除比特幣之外,P2P技術最大最成功的應用是檔案共享,Napster為先鋒,BitTorrent是該架構的最新演變。
比特幣的P2P網路架構不只是一種拓撲選擇。比特幣是一種P2P設計的數字現金系統,網路架構既是該核心特徵的反映,也是其基礎。控制權的去中心化是一個核心設計原則,只能通過一個扁平的,去中心化的P2P共識網路來實現和維護。
術語"比特幣網路"是指運行比特幣P2P協議的節點的集合。除比特幣P2P協議外,還有其他一些協議,如Stratum,用於挖礦和輕量級或行動錢包。這些附加協議由閘道路由伺服器提供,閘道路由伺服器使用比特幣P2P協議訪問比特幣網路,然後將該網路擴展到運行其他協議的節點。例如,Stratum伺服器通過Stratum協議將Stratum挖礦節點連接到比特幣主網,並將Stratum協議連接到比特幣P2P協議。我們使用術語"擴展比特幣網路"來指包括比特幣P2P協議、礦池協議、Stratum協議以及連接比特幣系統組件的任何其他相關協議的整體網路。
儘管比特幣P2P網路中的節點是對等的,但根據其支援的功能不同,它們承擔的角色可能不同。比特幣節點是一組功能的集合:路由、區塊鏈資料庫、挖礦和錢包服務。具有全部四個功能的完整節點顯示在 A bitcoin network node with all four functions: wallet, miner, full blockchain database, and network routing 中。
所有節點都包含用於參與網路的路由功能,可能包含其他功能。所有節點都會驗證並傳播交易和區塊,並發現和維護與其他節點的連接。在 A bitcoin network node with all four functions: wallet, miner, full blockchain database, and network routing 的完整節點示例中,路由功能由名為"Network Routing Node"的橙色圓圈或字母"N"表示。
一些稱為完整節點的節點也保留區塊鏈的完整和最新的副本。完整的節點可以自主和權威地驗證任何交易,無需外部參考。 一些節點只維護區塊鏈的一個子集,並使用稱為 simplified payment verification 或SPV的方法驗證交易,這些節點被稱為SPV節點或輕量級節點。在圖中的完整節點示例中,完整節點區塊鏈資料庫功能由稱為"Full Blockchain"或字母"B"的圓圈表示。在 The extended bitcoin network showing various node types, gateways, and protocols 中,SPV節點被繪製時沒有"B",表明它們沒有完整的區塊鏈副本。
挖礦節點通過運行專門的硬體解決Proof-of-Work演算法來競爭創建新區塊。一些挖礦節點也是完整節點,維護區塊鏈的完整副本,而另一些節點是加入礦池的輕量級節點,並且依賴於池伺服器維護完整節點。挖礦功能在完整節點中顯示為一個稱為"Miner"或字母"M"的黑色圓圈。
用戶錢包可能是完整節點的一部分,通常與桌面比特幣客戶端情況相同。越來越多的用戶錢包,尤其是那些運行在資源受限設備(如智慧型手機)上的用戶錢包是SPV節點。錢包功能在 A bitcoin network node with all four functions: wallet, miner, full blockchain database, and network routing 中顯示為稱為"Wallet"或字母"W"的綠色圓圈。
除了比特幣P2P協議的主要節點類型外,還有運行其他協議的伺服器和節點,例如專門的礦池協議和輕量級客戶端訪問協議。
Different types of nodes on the extended bitcoin network 展示了擴展比特幣網路中的多數普通節點類型
運行比特幣P2P協議的主要比特幣網路由5000到8000個運行各種版本比特幣參考客戶端(Bitcoin Core)的監聽節點,和幾百個運行比特幣P2P協議的各種其他實現的節點組成,例如Bitcoin Classic 、Bitcoin Unlimited、BitcoinJ、Libbitcoin、btcd和bcoin。比特幣P2P網路中的一小部分節點也是挖礦節點,在挖礦過程中競爭、驗證交易並創建新區塊。各種大公司通過運行基於Bitcoin Core客戶端的全節點客戶端與比特幣網路進行連接,具有完整的區塊鏈副本和網路節點,但沒有挖礦或錢包功能。這些節點充當網路邊緣路由器,允許將各種其他服務(交易所、錢包、區塊瀏覽器、商家支付處理)其上構建。
擴展比特幣網路包括運行比特幣P2P協議的網路,以及運行特殊協議的節點。連接到主比特幣P2P網路的是許多礦池伺服器和連接運行其他協議的節點的協議閘道。這些其他協議節點主要是礦池節點( 請參閱 [mining] )和輕量級錢包客戶端,它們不包含區塊鏈的完整副本。
The extended bitcoin network showing various node types, gateways, and protocols 顯示了擴展比特幣網路,其中包括各種類型的節點、閘道伺服器、邊緣路由器和錢包客戶端以及它們用於彼此連接的各種協議。
雖然比特幣P2P網路服務於各種節點類型的普遍需求,但它為比特幣挖礦節點的特殊需求呈現出過高的網路延遲。
比特幣礦工們進行時間敏感的競爭,解決工作量證明問題來擴展區塊鏈(參見[mining])。參加這場比賽時,比特幣礦工必須儘量縮短傳播獲勝區塊和下一輪比賽開始之間的時間。在挖礦中,網路延遲與利潤空間直接相關。
比特幣中繼網路 Bitcoin Relay Network 是旨在儘量減少礦工之間區塊傳輸延遲的網路。最初的 Bitcoin Relay Network 由核心開發者 Matt Corallo 在 2015 年創建,使礦工之間以極小的延遲快速同步區塊。該網路由幾個專門的節點組成,這些節點位於世界各地的亞馬遜網路服務基礎設施上,用於連接大多數礦工和礦池。
最初的比特幣中繼網路在2016年被 Fast Internet Bitcoin Relay Engine(http://bitcoinfibre.org [FIBRE])替代,這也是由核心開發人員Matt Corallo創建的。FIBER是一個基於UDP的中繼網路,用於中繼節點網路中的區塊。FIBER實現了 緊湊的區塊 compact block 優化以進一步減少傳輸的數據量和網路延遲。
另一箇中繼網路(仍處於提案階段)是http://www.falcon-net.org/about[Falcon],是基於康奈爾大學的研究的。 Falcon使用"直通式路由"(cut-through-routing)而不是"儲存轉發"(store-and-forward)來減少等待時間,方法是傳輸部分數據區塊,而不是等待接收完整數據區塊。
中繼網路並不是比特幣P2P網路的替代品。相反,它們是覆蓋網路,為具有特殊需求的節點之間提供附加連接。像高速公路不是農村公路的替代品,而是交通繁忙的兩個點之間的捷徑,你仍然需要小路連接到高速公路。
當新節點啟動時,它必須發現網路上的其他比特幣節點才能加入。要啟動此過程,新節點必須發現網路上至少一個現有節點並連接到該節點。地理位置不重要,比特幣網路拓撲結構沒有地理上的定義。因此,任何現有的比特幣節點都可以被隨機選擇。
要連接到一個已知的節點,節點建立一個TCP連接,通常連接到端口8333(比特幣通常使用的端口),或者提供一個替代端口。在建立連接後,節點將通過發送包含基本標識訊息的 版本( version )訊息開始"握手"(請參見 The initial handshake between peers),其中包括:
- nVersion
-
客戶端使用的比特幣P2P協議版本(例如, 70002)
- nLocalServices
-
一個本節點支援的本地服務列表,現在只是 NODE_NETWORK
- nTime
-
當前時間
- addrYou
-
遠程節點的IP地址
- addrMe
-
本地節點的IP地址
- subver
-
體現在此節點上運行的軟體類型的子版本 (例如,
/Satoshi:0.9.2.1/
) - BestHeight
-
本節點的區塊鏈的區塊高度
(查看 GitHub 上的 version 網路訊息示例。)
version 訊息通常是節點發送給另一個對等節點的第一條訊息。接收到 version 訊息的本地節點將檢查遠程節點報告的 nVersion 然後決定是否兼容遠程節點。如果是兼容的,本地節點將認可 version 訊息並通過 verack 訊息建立鏈接。
新節點如何查找對等節點?第一種方法是使用許多"DNS種子"來查詢DNS,這些DNS伺服器提供比特幣節點的IP地址列表。其中一些DNS種子提供穩定的比特幣偵聽節點的IP地址的靜態列表。一些DNS種子是BIND (Berkeley Internet Name守護進程)的自定義實現,它從一個爬蟲或一個長時間運行的比特幣節點收集的比特幣節點地址列表中返回一個隨機子集。Bitcoin Core客戶端包含五個不同DNS種子的名稱。不同DNS種子的所有權和實現的多樣性為初始引導過程提供了高度的可靠性。在Bitcoin Core客戶端中,使用DNS種子的選項由選項開關 -dnsseed (預設設置為1,以使用DNS種子)控制。
或者,一個對網路一無所知的啟動節點必須被給予至少一個比特幣節點的IP地址,之後它可以通過進一步的介紹建立連接。命令行參數 -seednode 可以用於連接到一個節點,只是為了將其作為種子使用。在使用初始種子節點進行介紹之後,客戶端將與其斷開並使用新發現的對等節點。
一旦建立了一個或多個連接,新節點將向其鄰居發送一個包含自己IP地址的 addr 訊息。鄰居將依次將 addr 訊息轉發給它們的鄰居,以確保新連接的節點變得眾所周知並且更好地連接。另外,新連接的節點可以向鄰居發送 getaddr,要求他們返回其他對等節點的IP地址列表。這樣,一個節點能找到可以連接的對等節點,並在網路上通告其存在以供其他節點找到它。 Address propagation and discovery 展示了地址發現協議。
一個節點必須連接到幾個不同的對等節點,以便建立到比特幣網路的不同路徑。路徑不是可靠的 -節點隨時可以加入或離開- 所以節點必須在丟失舊鏈接時持續發現新節點,並在啟動時幫助(通知)其他節點。啟動時只需要一個連接,因為第一個節點可以向他的對等節點介紹本節點,這些節點又可以提供進一步的介紹。連接到過多的節點也是不必要和浪費網路資源的。啟動之後,節點將記住其最近成功的對等連接,如果重新啟動,它可以快速重新建立與其以前的對等網路的連接。如果以前的對等節點都沒有響應其連接請求,則該節點可以使用種子節點重新引導。
在運行Bitcoin Core客戶端的節點上,你可以使用命令 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
}
]
要覆蓋對等節點的自動管理並指定IP地址列表,用戶可以提供選項 -connect = <IPAddress> 指定一個或多個IP地址。如果使用此選項,節點將只連接到選定的IP地址,而不是自動發現和維護對等連接。
如果連接上沒有流量,節點將定期發送訊息來維護連接。如果一個節點在連接上超過90分鐘沒有進行通信,則認為它斷開連接並尋找新的對等節點。因此,網路可以動態適應瞬態節點和網路問題,並且可以根據需要進行有機增長和收縮,而無需任何中央控制。
完整的節點是維護所有交易完整區塊鏈的節點。更準確地說,應該是"完整區塊鏈節點"。在比特幣早期,所有節點都是完整節點,目前Bitcoin Core客戶端是完整區塊鏈節點。然而,在過去的兩年裡,產生了不能維護完整區塊鏈的新的比特幣客戶端,以輕量級客戶端運行。我們將在下一節詳細介紹這些內容。
完整區塊鏈節點保存完整和最新的,包含所有交易的比特幣區塊鏈副本,它們獨立構建和驗證,從第一個區塊(創世區塊)開始,構建到網路中最新的已知區塊。完整區塊鏈節點可獨立並權威地驗證任何交易,無需依賴任何其他節點或訊息來源。完整區塊鏈節點依靠網路接收有關交易的新區塊的更新,然後驗證並將其合併到本地區塊鏈副本中。
運行完整區塊鏈節點為你提供純粹的比特幣體驗:獨立驗證所有交易,無需依賴或信任任何其他系統。很容易判斷你是否運行完整節點,因為它需要超過100 GB的硬碟空間來儲存完整的區塊鏈。如果你需要大量硬碟並且需要兩到三天才能與網路同步,則你正在運行完整節點。這是完全獨立和不依賴中央權威機構的代價。
完整區塊鏈比特幣客戶端有幾種可選的實現,它們使用不同的程式語言和軟體體系結構構建。然而,最常見的實現方式是Bitcoin Core參考實現,也稱為Satoshi客戶端。比特幣網路上超過75%的節點運行各種版本的Bitcoin Core。它在 version 訊息中發送的子版本字串中被標識為"Satoshi",如我們前面看到的那樣,由命令 getpeerinfo 顯示,例如,/Satoshi:0.8.6/。
完整節點連接到對等節點之後的第一件事就是嘗試構建一個完整的區塊鏈。如果它是一個全新的節點,並且根本沒有區塊鏈,它只會知道一個區塊,創世區塊,這個區塊是靜態嵌入到客戶端軟體中的。從區塊#0(創世區塊)開始,新節點將下載數十萬個區塊來與網路同步並重新建立完整的區塊鏈。
同步區塊鏈的過程從 version 訊息開始,因為它包含 BestHeight,節點當前的區塊鏈高度(區塊數)。一個節點會看到來自對等節點的 version 訊息,知道它們各自擁有多少區塊,與它自己的區塊鏈中的區塊數進行比較。對等節點將交換 getblocks 訊息,其中包含本地區塊鏈上頂部區塊的雜湊(指紋)。另一個對等節點會識別出接收到的雜湊不是頂部的區塊,而是較舊的區塊,由此推斷其自身的本地區塊鏈比其對等節點更長。
具有較長區塊鏈的對等體比另一個節點具有更多的區塊,並且可以識別出另一個節點需要"趕上"哪些區塊。它將識別前500個區塊,使用 inv(庫存)訊息來共享和傳輸雜湊。缺少這些區塊的節點將通過發出一系列 getdata 訊息來請求完整區塊數據並使用 inv 訊息中的雜湊標識請求的區塊。
例如,假設一個節點只有創世區塊。然後它會收到來自對等節點的包含鏈中未來500個區塊的雜湊的 inv 訊息。它將開始從所有連接的對等節點請求數據區塊,分散負載,確保它不會用請求淹沒任何對等節點。該節點記錄每個對等連接"正在傳輸"的區塊數,即它已請求但未收到的區塊,並檢查它未超過限制( MAX_BLOCKS_IN_TRANSIT_PER_PEER )。這樣,如果需要很多區塊,它只會在先前的請求得到滿足後才請求新區塊,從而使對等節點能夠控制更新的速度並且不會壓倒網路。每個區塊被接收後,將被添加到區塊鏈中,我們將在 [blockchain] 中看到。隨著本地區塊鏈逐漸建立,更多的區塊被請求和接收,並且該過程繼續,直到節點趕上網路的其餘部分。
節點只要離線任意時間,就會將本地區塊鏈與對等節點進行比較,並獲取任何缺失的區塊。無論節點離線幾分鐘,缺少幾個區塊,或離線一個月,缺少幾千個區塊,它都會首先發送 getblocks,獲取 inv 響應,並開始下載缺失的區塊。 Node synchronizing the blockchain by retrieving blocks from a peer 展示了庫存和區塊傳播協議。
並非所有節點都有能力儲存完整的區塊鏈。許多比特幣客戶端被設計用於在空間和功耗受限的設備上運行,如智慧型手機,平板電腦或嵌入式系統。對於此類設備,使用 simplified payment_verification(SPV)方法可以在不儲存完整區塊鏈的情況下進行操作。這些類型的客戶端稱為SPV客戶端或輕量級客戶端。隨著比特幣的普及,SPV節點正成為比特幣節點的最常見形式,特別是比特幣錢包。
SPV節點僅下載區塊頭,而不下載每個區塊中包含的交易。由此產生的區塊鏈,比完整區塊鏈小1000倍。 SPV節點無法構建可用於支出的所有UTXO的完整畫面,因為他們不知道網路上的所有交易。 SPV節點使用一種不同的方法驗證交易,這種方法依賴對等節點按需提供區塊鏈相關部分的部分視圖。
作為一個比喻,一個完整節點就像一個配備了每條街道和每個地址的詳細地圖的陌生城市遊客。相比之下,一個SPV節點就像是一個只知道一條主幹道,隨機向陌生人打聽路線的陌生城市遊客。儘管兩位遊客都可以通過訪問來驗證街道的存在,但沒有地圖的遊客並不知道任何一條小街道的位置,也不知道其他街道是否存在。位於教堂街23號的前面,沒有地圖的旅遊者無法知道該市是否有其他"教堂街23號"地址,以及這是否是正確的。沒有地圖的遊客最好的機會是問足夠多的人,並期望他們中的一些人不會毆打他。
SPV通過交易在區塊鏈中的 深度 而不是 高度 來驗證。而一個完整的區塊鏈節點將構建一個完全驗證的鏈,有成千上萬的區塊和交易,一直鏈接到創世區塊。一個SPV節點將驗證所有區塊鏈(但不是所有交易)並將該鏈鏈接到感興趣的交易。
例如,當檢查第300,000區塊中的交易時,一個將所有300,000個區塊連接起來,並建立了一個完整UTXO資料庫的完整節點,通過確認UTXO的未花費狀態來確定交易的有效性。SPV節點無法驗證UTXO是否已花費。相反,SPV節點將使用 merkle path(參見 [merkle_trees] )在交易和包含它的區塊之間建立鏈接。然後,SPV節點等待,直到它看到在包含該交易的區塊的頂部的六個區塊300,001至300,006,並通過在區塊300,006至300,001之下建立的深度來驗證它。事實上,網路上的其他節點接受了300,000區塊,做了必要的工作,並在其上生成了六區塊以上的區塊,這代理地(間接地)證明交易不是雙重花費的事實。
當交易實際上不存在時,不能說服SPV節點在區塊中存在交易。 SPV節點通過請求merkle路徑證明,並驗證區塊鏈中的工作量證明,來建立交易存在於區塊中的證明。但是,交易的存在可以從SPV節點"隱藏"。 SPV節點可以明確證明交易存在,但無法驗證交易(例如同一個UTXO的雙重花費)不存在,因為它沒有所有交易的記錄。此漏洞可用於拒絕服務攻擊或針對SPV節點的雙重支出攻擊。為了防止這種情況發生,SPV節點需要隨機地連接到多個節點,以增加與至少一個誠實節點接觸的概率。這種隨機連接的需要意味著SPV節點也容易遭受網路分區攻擊或Sybil攻擊,即它們連接到了假節點或假網路,並且無法訪問誠實節點或真正的比特幣網路。
對於大多數實際的目的,連接良好的SPV節點足夠安全,在資源需求、實用性和安全性之間取得平衡。然而,對於絕對可靠的安全性,沒有什麼比運行一個完整的區塊鏈節點更好。
Tip
|
一個完整的區塊鏈節點通過檢查其下數千個區塊來驗證交易,以確保UTXO沒有被消耗,而SPV節點則檢查區塊在其上方的幾個區塊中埋藏的深度。 |
要獲取區塊頭,SPV節點使用 getheaders 訊息而不是 getblocks。響應端會使用一個 header 訊息發送至多2000個區塊頭。該過程與完整節點用於檢索完整區塊的過程相同。 SPV節點還在與對等節點的連接上設置過濾器,以過濾由對等節點發送的未來的區塊和交易。任何感興趣的交易都使用 getdata 請求來檢索。對等節點生成一個包含交易的 tx 訊息,作為響應。 SPV node synchronizing the block headers 展示了區塊頭的同步。
由於SPV節點需要檢索特定交易以選擇性地驗證它們,因此它們也會產生隱私風險。與收集每個區塊內所有交易的完整區塊鏈節點不同,SPV節點對特定數據的請求可能會無意中洩露其錢包中的地址。例如,監控網路的第三方可以跟蹤SPV節點上的錢包所請求的所有交易,並使用它們將比特幣地址與該錢包的用戶相關聯,從而破壞用戶的隱私。
在引入SPV/輕量級節點後不久,比特幣開發人員添加了一項名為 布林過濾器 布林_filters 的功能,以解決SPV節點的隱私風險。布林過濾器允許SPV節點通過使用概率而不是固定模式的過濾機制來接收交易子集,從而無需精確地揭示他們感興趣的地址。
布林過濾器是一種概率搜索過濾器,它是一種不必精確地描述所需模式的方法。布林過濾器提供了一種有效的方式來表達搜索模式,同時保護隱私。它們被SPV節點用來向他們的對等節點詢問符合特定模式的交易,而不會準確揭示他們正在搜索的地址,密鑰或交易。
在我們以前的比喻中,一個沒有地圖的遊客正在詢問指向特定地址的路線,"23 Church St."如果她向陌生人詢問這條街的路線,她會無意中透露她的目的地。布林過濾器就像是問:"這個街區有什麼街道名稱以R-C-H結尾?"像這樣的問題揭露的目的地訊息要少一些。使用這種技術,遊客可以更詳細地指定希望的地址,例如"以U-R-C-H結尾"或更少的細節,如"以H結尾"。通過改變搜索的精確度,遊客可以顯示或多或少的訊息,代價是獲得或多或少的具體結果。如果她提出一個不太具體的模式,她會得到更多可能的地址和更好的隱私,但是許多結果都是無關緊要的。如果她要求一個非常具體的模式,她會得到較少的結果,但會失去隱私。
布林過濾器通過允許SPV節點指定精度或隱私程度可調整的交易搜索模式來支援此功能。更具體的布林過濾器將產生準確的結果,但是以暴露SPV節點感興趣的模式為代價,從而揭示用戶錢包擁有的地址。一個不太具體的布林過濾器將產生更多關於更多交易的數據,許多數據與節點無關,但將使節點保持更好的隱私。
布林過濾器被實現為具有N個二進制數字(比特位)的可變大小陣列,和可變數量的M個雜湊函數。雜湊函數被設計為始終產生1到N之間的輸出,對應於二進制數字的陣列。雜湊函數是確定性地生成的,以便任何實現布林過濾器的節點將總是使用相同的雜湊函數,並且針對特定輸入獲得相同的結果。通過選擇不同長度(N)布林過濾器和不同數量(M)的雜湊函數,可以調整布林過濾器,從而改變準確性水平和隱私。
在 An example of a simplistic 布林 filter, with a 16-bit field and three hash functions 中, 我們使用非常小的16位陣列和三個雜湊函數來演示布林過濾器如何工作。
布林過濾器將位陣列全部初始化為零。要將模式添加到布林過濾器,依次由每個雜湊函數雜湊。將第一個雜湊函數應用於輸入會產生一個介於1和N之間的數字。找到陣列中的相應位(從1到N編號)並設置為 1 ,從而記錄雜湊函數的輸出。然後,下一個雜湊函數被用來設置另一個位等等。應用了所有M個雜湊函數之後,搜索模式將在布林過濾器中被"記錄"為從 0 變為 1 的M個位。
Adding a pattern "A" to our simple 布林 filter 是向 An example of a simplistic 布林 filter, with a 16-bit field and three hash functions 中所示的簡單布林過濾器添加模式"A"的示例。
添加第二個模式與重複此過程一樣簡單。該模式依次由每個雜湊函數進行雜湊,並通過對應的位設置為 1 來記錄結果。請注意,由於布林過濾器填充了更多模式,因此雜湊函數結果可能與已設置為 1 的位重合,在這種情況下該位不會更改。本質上,隨著更多模式記錄重疊位,布林過濾器開始變得飽和,更多位設置為 1 ,濾波器的準確性降低。這就是為什麼過濾器是一個概率資料結構 —— 隨著更多模式的添加,它變得不太準確。精確度取決於所添加的模式的數量與位陣列(N)的大小和雜湊函數(M)的數量。更大的位陣列和更多的雜湊函數可以以更高的準確度記錄更多的模式。較小的位陣列或更少的雜湊函數將記錄較少的模式併產生較低的準確性。
Adding a second pattern "B" to our simple 布林 filter 是向簡單布林過濾器添加第二個模式"B"的示例。
為了測試一個模式是否是布林過濾器的一部分,使用每個雜湊函數對模式進行雜湊處理,並根據比特陣列測試最終的位模式。如果由雜湊函數索引的所有位被設置為 1,則該模式 可能 在布林過濾器中記錄。因為這些比特可能因為多重模式的重疊而被設置,所以答案不確定,而是相當可能的。簡而言之,布林 Filter正面匹配是"可能是"。
Testing the existence of pattern "X" in the 布林 filter. The result is a probabilistic positive match, meaning "Maybe." 是在簡單布林過濾器中測試模式"X"的存在的示例。相應的位被設置為 1 ,所以模式可能是匹配的。
相反,如果模式針對布林過濾器進行測試,並且任意一個比特設置為 0 ,則這證明該模式沒有記錄在布林過濾器中。否定的結果不是概率,而是肯定的。簡而言之,布林過濾器上的負面匹配是"絕對不是!"
Testing the existence of pattern "Y" in the 布林 filter. The result is a definitive negative match, meaning "Definitely Not!" 是在簡單布林過濾器中測試模式"Y"的存在的一個例子。其中一個相應的位設置為 0,因此該模式絕對不匹配。
布林過濾器用於過濾SPV節點從其對等節點接收的交易(以及包含它們的區塊),僅選擇SPV節點感興趣的交易而不透露其感興趣的地址或密鑰。
SPV節點會將布林過濾器初始化為"空";在該狀態下,布林過濾器將不匹配任何模式。然後,SPV節點將列出它感興趣的所有地址,密鑰和雜湊。它將通過從其錢包控制的任何UTXO中提取公共密鑰雜湊和腳本雜湊和交易ID來完成此操作。 然後,SPV節點將這些模式中的每一個添加到布林過濾器,如果這些模式存在於交易中,布林過濾器將"匹配",而不顯示模式本身。
SPV節點將向對等節點發送 filterload 訊息,其中包含要在連接上使用的布林過濾器。在對等節點中,布林過濾器將針對每個傳入交易進行檢查。完整節點根據布林過濾器檢查交易的多個部分,查找包含以下內容的匹配項:
-
交易ID
-
交易的每個輸出(腳本中的每個密鑰和雜湊)的鎖定腳本數據部分
-
每個交易輸入
-
每個輸入簽名數據部分(或見證腳本)
通過檢查所有這些組件,布林過濾器可用於匹配公鑰雜湊,腳本,OP_RETURN 值,簽名中的公鑰或智慧合約或複雜腳本的任何未來組件。
在建立過濾器後,對等節點將用布林過濾器測試每個交易的輸出。只有匹配過濾器的交易才會發送到節點。
為響應來自節點的 getdata 訊息,對等節點將發送 merkleblock 訊息,其中每個匹配交易僅包含與過濾器和merkle路徑匹配的區塊的頭部(請參見 [merkle_trees] )。對等節點隨後還會發送包含由過濾器匹配的交易的 tx 訊息。
當完整節點向SPV節點發送交易時,SPV節點丟棄所有誤報,並使用正確匹配的交易更新其UTXO集和錢包餘額。當它更新自己的UTXO集合時,它也修改布林過濾器以匹配任何引用它剛剛找到的UTXO的未來交易。完整的節點然後使用新的布林過濾器來匹配新的交易並重復整個過程。
通過發送 filteradd 訊息,設置布林過濾器的節點可以交互式地向過濾器添加模式。要清空布林過濾器,節點可以發送 filterclear 訊息。由於無法從布林過濾器中刪除模式,因此如果不再需要模式,節點必須清空並重新發送新的布林過濾器。
SPV節點的網路協議和布林過濾器機制在 BIP-37 (Peer Services) 中定義。
實現SPV的節點比完整節點的隱私性更弱。一個完整節點接收所有交易,因此不會顯示它是否在錢包中使用某個地址。 SPV節點接收與其錢包中的地址相關的過濾列表。因此,它降低了所有者的隱私。
布林過濾器是一種減少隱私損失的方法。沒有它們,SPV節點將不得不明確列出它感興趣的地址,從而嚴重暴露隱私。然而,即使使用布林過濾器,監控SPV客戶端的流量或直接作為P2P網路中的節點連接到它的對等節點,也可以收集足夠的訊息來學習SPV客戶端的錢包中的地址。
大多數比特幣的新用戶都假定比特幣節點的網路通信是加密的。事實上,比特幣的原始實施完全是不加密的。雖然這不是完整節點的主要隱私問題,但對於SPV節點來說是一個大問題。
作為增加比特幣P2P網路隱私和安全性的一種方法,有兩種解決方案可以提供通信加密:Tor Transport(BIP-150) 和 P2P認證與加密 (BIP-151)。
Tor 代表 洋蔥路由網路 The Onion Routing network,是一個軟體項目,也是一種網路,通過具有匿名性,不可追蹤性和隱私性的隨機網路路徑,來提供數據加密和封裝。
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 successful",表明Bitcoin Core已經為Tor網路添加了隱藏服務。
你可以在Bitcoin Core文件( docs/tor.md )和各種在線教程中找到關於將Bitcoin Core作為Tor隱藏服務運行的更多說明。
兩項比特幣改進建議,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客戶端的隱私。
此外,身份驗證可用於創建可信的比特幣節點網路並防止中間人攻擊(Man-in-the-Middle attacks)。最後,如果廣泛部署P2P加密,將會加強比特幣對流量分析和隱私侵蝕監控的阻力,特別是在網路使用受到嚴格控制和監控的極權主義國家。
幾乎比特幣網路上的每個節點都維護一個名為 memory pool,mempool_或_transaction pool 的未確認交易的臨時列表。節點使用該池來跟蹤網路已知但尚未包含在區塊鏈中的交易。例如,錢包節點將使用交易池來追蹤已經在網路上接收但尚未確認的到用戶錢包的傳入支付。
交易被接收和驗證後,會被添加到交易池並被中繼到相鄰節點以在網路上傳播。
一些節點實現還維護一個單獨的孤兒交易池。如果交易的投入引用尚未知曉的交易,好像遺失了父母,那麼孤兒交易將臨時儲存在孤兒池中,直至父交易到達。
將交易添加到交易池時,將檢查孤兒交易池是否有任何引用此交易輸出的孤兒(後續交易)。然後驗證任何匹配的孤兒。如果有效,它們將從孤兒交易池中刪除並添加到交易池中,從而完成從父交易開始的鏈。鑑於不再是孤兒的新增交易,該過程重複遞歸地尋找更多後代,直到找不到更多的後代。通過這個過程,父交易的到來觸發了整個鏈條相互依賴的交易的級聯重建,將孤兒與他們的父母重新整合在一起。
交易池和孤兒交易池都儲存在本地內存中,不會保存在持久性儲存上;而且,它們是從傳入的網路訊息動態填充的。當一個節點啟動時,這兩個池都是空的,並且會逐漸使用網路上收到的新交易填充。
比特幣客戶端的一些實現還維護UTXO資料庫或池,這是區塊鏈上所有未使用輸出的集合。儘管名稱"UTXO池"聽起來與交易池相似,但它代表了一組不同的數據。與交易和孤兒交易池不同,UTXO池並未初始化為空,而是包含了追溯到創世區塊的,數百萬未使用的交易輸出條目。UTXO池可以放置在本地內存中,也可以作為持久儲存上的索引資料庫表。
交易池和孤兒交易池代表單個節點的本地視角,根據節點啟動或重新啟動的時間不同,節點之間可能會有很大差異;UTXO池表示網路的自發共識,因此節點之間的差異很小。此外,交易池和孤兒交易池只包含未確認的交易,而UTXO池只包含確認的輸出。