比特幣是建構在網際網路之上的點對點網路體系結構。術語點對點(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池只包含確認的輸出。