1. 程式人生 > >精通比特幣》解讀 第八章

精通比特幣》解讀 第八章

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

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

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

8.2 節點型別及角色  儘管比特幣P2P網路中的各個節點相互對等,但是根據所提供的功能不同,各節點可能具有不同的角色。一個比特幣節點是路由、區塊鏈資料庫、挖礦、錢包服務的功能集合。一個具有全部四個功能的全節點(full node)如圖8-1所示: 這裡寫圖片描述 Figure 8-1. A bitcoin network node with all four functions: wallet, miner, full blockchain database, and network routing

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

一些節點,被稱為全節點,它保持有一份完整的、最新的區塊鏈拷貝。全節點能夠獨立自主地可信地校驗任何交易,而不需要任何外部參照。另外還有一些節點只保持了區塊鏈的一個子集,它們通過一種名為“簡易支付驗證(SPV)”的方法來驗證交易。這樣的節點被稱為“SPV節點”或者“輕量級節點”。在如上圖所示的全節點例子中,全節點區塊鏈資料庫功能用一個名為“Full Blockchain”或帶有字母’B’的藍色圓圈表示。在圖8-3中,SPV節點沒有畫藍色圓圈,表示它們沒有區塊鏈的完整拷貝。

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

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

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

圖8-2描述了擴充套件比特幣網路中最為常見的節點型別。 這裡寫圖片描述 Figure 8-2. Different types of nodes on the extended bitcoin network

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主網路的是許多礦池伺服器以及連線著執行著其他協議的節點的協議閘道器。這些執行著其他協議的節點通常都是礦池挖礦節點(參見Chapter 10)以及輕量級錢包客戶端,它們通常不保持區塊鏈的完整備份。

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

這裡寫圖片描述 Figure 8-3. The extended bitcoin network showing various node types, gateways, and protocols

8.4比特幣中繼網路(Bitcoin Relay Networks)  雖然比特幣P2P網路服務於各種節點型別的普遍需求,但是對於比特幣挖掘節點的專門需求,它顯示出太高的網路延遲。

比特幣礦工進行著(are engaged in )時間敏感的競爭,以解決Proof-of-Work難題,並擴充套件延伸區塊鏈(參見Chapter 10)。在參加競爭時,比特幣礦工必須儘可能地縮短獲勝塊的傳播與下一輪比賽開始之間的時間。在採礦方面,網路延遲直接關係到利潤率。

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

初始的比特幣中繼網路在2016年被 Fast Internet Bitcoin Relay Engine(FIBRE) 取代了,同樣是由核心開發者Matt Corallo建立的。 FIBER是一種基於UDP的中繼網路,可以在節點網路裡中繼區塊。 FIBER實現了緻密區塊(compact block)的優化策略,以進一步減少傳輸的資料數量和網路延遲。

另一箇中繼網路(仍在提案階段)是 Falcon,這是基於康奈爾大學的研究。 Falcon使用“直通路由(cut-through-routing)”而不是“儲存轉發(store-and-forward)”來減少延遲,即接收到區塊的某些部分時就傳播,而不是等待直到接收到一個完整的區塊才傳播。

中繼網路不是比特幣P2P網路的替代品。相反,它們是覆蓋網路(overlay networks),在具有特殊需求的節點之間提供額外的連線。就像高速公路不是農村道路的替代品,而是交通繁忙的兩點之間的捷徑,您仍然需要小路連線到高速公路。

8.5 網路發現

當新的網路節點啟動後,它必須發現網路中的其他比特幣節點,以參與到其中。為了開始這個過程,新的節點必須發現網路中至少一個已存在的其它節點並與它建立連線,其它節點的地理位置是無關緊要的。由於比特幣網路的拓撲結構並不基於節點間的地理位置,因此,在新節點建立連線時,可以隨機選擇網路中已存在的任何比特幣節點。

節點通常建立一條TCP連線以連線到已知的對等節點,一般是使用對方的8333埠(該埠號通常是比特幣所使用的)或者對方提供的其它替代埠。在建立連線時,節點會通過傳送一個包含基本認證資訊的version訊息來開始“握手”通訊過程(見圖8-4)。基本認證資訊包括:

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

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

nTime  當前時間

addrYou  當前節點所見到的遠端節點的IP地址

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

subver  一個子版本號,表示當前節點執行的軟體的型別(例如:/Satoshi:0.9.2.1/)

BaseHeight  當前節點的區塊鏈的區塊高度

(version網路訊息的具體用例請參見GitHub )

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

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

或者,不知道網路任何資訊的自舉節點必須被給予至少一個比特幣節點的IP地址,之後可以通過進一步引進來建立連線。 命令列引數 -seednode 可用於連線到一個節點,該節點僅作為一個種子用於引進其他節點。 在使用初始種子節點完成引進其他節點後,客戶端將與初始種子節點斷開連線並使用新發現的對等節點。 這裡寫圖片描述 Figure 8-4. The initial handshake between peers

當建立一個或多個連線後,新節點將一條包含自身IP地址的addr訊息傳送給其相鄰節點。相鄰節點再將此條addr訊息依次轉發給它們各自的相鄰節點,從而保證新節點被廣為所知並保證連線更穩定。另外,新接入的節點可以向它的相鄰節點發送getaddr訊息,要求它們返回其已知對等節點的IP地址列表。通過這種方式,節點可以找到能連線到的對等節點,並向網路宣告它的存在,以便其他節點能夠找到它。圖8-5描述了這種地址發現協議( address discovery protoco)。 這裡寫圖片描述  Figure 8-5. Address propagation and discovery

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

在執行比特幣核心客戶端的節點上,您可以使用 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=<IPAddress> 選項來指定一個或多個IP地址,從而覆蓋節點的自動管理並指定IP地址列表。如果採用此選項,節點將只會連線到這些選定的IP地址,而不會自動發現並維護與對等節點的連線。

如果已建立的連線上沒有資料通訊,節點會定期傳送資訊以維持連線。如果節點在一條連線上超過90分鐘都沒有任何通訊,它會被認為已經斷開連線,並將尋找新的對等節點。因此,比特幣網路會隨時根據變化的節點(transient  nodes)及網路問題進行動態調整,可以根據需要有機地擴張和收縮而不需要中心化的控制。

8.6 全節點

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

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

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

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

8.7 交換“庫存清單”(Exchanging “Inventory”)  一個全節點連線到對等節點之後,第一件要做的事情就是構建完整的區塊鏈。如果該節點是一個全新的(brand-new)節點,不包含任何區塊鏈資訊,它只知道一個區塊,即創世區塊,它是靜態嵌入在客戶端軟體中的。新節點需要下載從0號區塊(創世區塊)開始的數十萬區塊的全部內容,才能跟網路同步,並重建全區塊鏈。

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

擁有更長區塊鏈的對等節點比其他節點擁有更多的區塊,可以識別出哪些區塊是其他節點需要以便能“趕上”的。它會識別出第一批500個區塊,通過使用inv(inventory)訊息把這些區塊的雜湊值分享並傳播出去。缺少這些區塊的節點便可以通過傳送一系列的getdata訊息來請求全區塊資料,並用inv訊息中的雜湊值來確認請求到的區塊,從而獲取這些缺失的區塊。

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

每當一個節點離線,不管離線時間有多長,這個與對等節點比較本地區塊鏈並恢復任何缺失區塊的過程就會發生。節點無論是隻離線幾分鐘導致缺失了幾個區塊,或者離線長達一個月導致缺失了上千個區塊,它啟動時,都會發送 getblocks 訊息,收到一個inv響應,接著開始下載缺失的區塊。庫存和區塊傳播協議如圖8-6所示。 這裡寫圖片描述 Figure 8-6. Node synchronizing the blockchain by retrieving blocks from a peer

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 attacks),即SPV節點被連線到虛假節點或虛假網路中,沒有連線到可靠節點或真正的比特幣網路。

在絕大多數的實際情況中,具有良好連線的SPV節點是足夠安全的,它在資源需求、實用性和安全性之間維持恰當的平衡。當然,如果要保證絕對的安全性,沒有什麼比執行完整區塊鏈的節點更安全。

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

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

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

這裡寫圖片描述 Figure 8-7. SPV node synchronizing the block headers

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

8.9 Bloom過濾器  Bloom過濾器是一個允許使用者描述期望的模式而不必精確表述的基於概率的搜尋過濾器。Bloom過濾器提供了一種既能表達搜尋模式同時也能保護隱私的有效的方法。這一方法被用在SPV節點中向對等節點請求符合指定模式的交易,同時交易地址不會被暴露。

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

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