比特幣和以太坊的P2P網(wǎng)絡(luò)詳解(一)

1、P2P原理及協(xié)議概述

P2P 主要存在四種不同的網(wǎng)絡(luò)模型,也代表著 P2P 技術(shù)的四個(gè)發(fā)展階段:集中式、純分布式、混合式和結(jié)構(gòu)化模型。不過需要指出的是,這里所說的網(wǎng)絡(luò)模型主要是指路由查詢結(jié)構(gòu),即不同節(jié)點(diǎn)之間如何建立連接通道,兩個(gè)節(jié)點(diǎn)之間一旦建立連接,具體傳輸什么數(shù)據(jù)則是兩個(gè)節(jié)點(diǎn)之間的事情了。

最簡單的路由方式就是集中式,即存在一個(gè)中心節(jié)點(diǎn)保存了其他所有節(jié)點(diǎn)的索引信息,索引信息一般包括節(jié)點(diǎn) IP 地址、端口、節(jié)點(diǎn)資源等。集中式路由的優(yōu)點(diǎn)就是結(jié)構(gòu)簡單、實(shí)現(xiàn)容易。但缺點(diǎn)也很明顯,由于中心節(jié)點(diǎn)需要存儲(chǔ)所有節(jié)點(diǎn)的路由信息,當(dāng)節(jié)點(diǎn)規(guī)模擴(kuò)展時(shí),就很容易出現(xiàn)性能瓶頸;而且也存在單點(diǎn)故障問題。

image.png

那第二種路由結(jié)構(gòu)則是純分布式的,移除了中心節(jié)點(diǎn),在 P2P 節(jié)點(diǎn)之間建立隨機(jī)網(wǎng)絡(luò),就是在一個(gè)新加入節(jié)點(diǎn)和 P2P 網(wǎng)絡(luò)中的某個(gè)節(jié)點(diǎn)間隨機(jī)建立連接通道,從而形成一個(gè)隨機(jī)拓?fù)浣Y(jié)構(gòu)。新節(jié)點(diǎn)加入該網(wǎng)絡(luò)的實(shí)現(xiàn)方法也有很多種,最簡單的就是隨機(jī)選擇一個(gè)已經(jīng)存在的節(jié)點(diǎn)并建立鄰居關(guān)系。像比特幣的話,則是使用 DNS 的方式來查詢其他節(jié)點(diǎn),DNS 一般是硬編碼到代碼里的,這些 DNS 服務(wù)器就會(huì)提供比特幣節(jié)點(diǎn)的 IP 地址列表,從而新節(jié)點(diǎn)就可以找到其他節(jié)點(diǎn)建立連接通道。新節(jié)點(diǎn)與鄰居節(jié)點(diǎn)建立連接后,還需要進(jìn)行全網(wǎng)廣播,讓整個(gè)網(wǎng)絡(luò)知道該節(jié)點(diǎn)的存在。全網(wǎng)廣播的方式就是,該節(jié)點(diǎn)首先向鄰居節(jié)點(diǎn)廣播,鄰居節(jié)點(diǎn)收到廣播消息后,再繼續(xù)向自己的鄰居節(jié)點(diǎn)廣播,以此類推,從而廣播到整個(gè)網(wǎng)絡(luò)。這種廣播方法也稱為泛洪機(jī)制。純分布式結(jié)構(gòu)不存在集中式結(jié)構(gòu)的單點(diǎn)性能瓶頸問題和單點(diǎn)故障問題,具有較好的可擴(kuò)展性,但泛洪機(jī)制引入了新的問題,主要是可控性差的問題,包括兩個(gè)較大的問題,一是容易形成泛洪循環(huán),比如節(jié)點(diǎn) A 發(fā)出的消息經(jīng)過節(jié)點(diǎn) B 到 節(jié)點(diǎn) C,節(jié)點(diǎn) C 再廣播到節(jié)點(diǎn) A,這就形成了一個(gè)循環(huán);另一個(gè)棘手問題則是響應(yīng)消息風(fēng)暴問題,如果節(jié)點(diǎn) A 想請(qǐng)求的資源被很多節(jié)點(diǎn)所擁有,那么在很短時(shí)間內(nèi),會(huì)出現(xiàn)大量節(jié)點(diǎn)同時(shí)向節(jié)點(diǎn) A 發(fā)送響應(yīng)消息,這就可能會(huì)讓節(jié)點(diǎn) A 瞬間癱瘓。

image.png

再來看看第三種路由結(jié)構(gòu):混合式。混合式其實(shí)就是混合了集中式和分布式結(jié)構(gòu),如下圖所示,網(wǎng)絡(luò)中存在多個(gè)超級(jí)節(jié)點(diǎn)組成分布式網(wǎng)絡(luò),而每個(gè)超級(jí)節(jié)點(diǎn)則有多個(gè)普通節(jié)點(diǎn)與它組成局部的集中式網(wǎng)絡(luò)。一個(gè)新的普通節(jié)點(diǎn)加入,則先選擇一個(gè)超級(jí)節(jié)點(diǎn)進(jìn)行通信,該超級(jí)節(jié)點(diǎn)再推送其他超級(jí)節(jié)點(diǎn)列表給新加入節(jié)點(diǎn),加入節(jié)點(diǎn)再根據(jù)列表中的超級(jí)節(jié)點(diǎn)狀態(tài)決定選擇哪個(gè)具體的超級(jí)節(jié)點(diǎn)作為父節(jié)點(diǎn)。這種結(jié)構(gòu)的泛洪廣播就只是發(fā)生在超級(jí)節(jié)點(diǎn)之間,就可以避免大規(guī)模泛洪存在的問題。在實(shí)際應(yīng)用中,混合式結(jié)構(gòu)是相對(duì)靈活并且比較有效的組網(wǎng)架構(gòu),實(shí)現(xiàn)難度也相對(duì)較小,因此目前較多系統(tǒng)基于混合式結(jié)構(gòu)進(jìn)行開發(fā)實(shí)現(xiàn)。其實(shí),比特幣網(wǎng)絡(luò)如今也是這種結(jié)構(gòu),后面再細(xì)說。

image.png

最后一種網(wǎng)絡(luò)則是結(jié)構(gòu)化 P2P 網(wǎng)絡(luò),它也是一種分布式網(wǎng)絡(luò)結(jié)構(gòu),但與純分布式結(jié)構(gòu)不同。純分布式網(wǎng)絡(luò)就是一個(gè)隨機(jī)網(wǎng)絡(luò),而結(jié)構(gòu)化網(wǎng)絡(luò)則將所有節(jié)點(diǎn)按照某種結(jié)構(gòu)進(jìn)行有序組織,比如形成一個(gè)環(huán)狀網(wǎng)絡(luò)或樹狀網(wǎng)絡(luò)。而結(jié)構(gòu)化網(wǎng)絡(luò)的具體實(shí)現(xiàn)上,普遍都是基于 **DHT(Distributed Hash Table,分布式哈希表) **算法思想。DHT 只是提出一種網(wǎng)絡(luò)模型,并不涉及具體實(shí)現(xiàn),主要想解決如何在分布式環(huán)境下快速而又準(zhǔn)確地路由、定位數(shù)據(jù)的問題。具體的實(shí)現(xiàn)方案有 Chord、Pastry、CAN、Kademlia 等算法,其中 Kademlia 也是以太坊網(wǎng)絡(luò)的實(shí)現(xiàn)算法,很多常用的 P2P 應(yīng)用如 BitTorrent、電驢等也是使用 Kademlia。因?yàn)槠邢蓿筒徽归_講這些算法的具體原理了。目前,我們主要理解 DHT 的核心思想即可。

在 P2P 網(wǎng)絡(luò)中,可以抽象出兩種空間:資源空間和節(jié)點(diǎn)空間。資源空間就是所有節(jié)點(diǎn)保存的資源集合,節(jié)點(diǎn)空間就是所有節(jié)點(diǎn)的集合。對(duì)所有資源和節(jié)點(diǎn)分別進(jìn)行編號(hào),如把資源名稱或內(nèi)容用 Hash 函數(shù)變成一個(gè)數(shù)值(這也是 DHT 常用的一種方法),這樣,每個(gè)資源就有對(duì)應(yīng)的一個(gè) ID,每個(gè)節(jié)點(diǎn)也有一個(gè) ID,資源 ID 和節(jié)點(diǎn) ID 之間建立起一種映射關(guān)系,比如,將資源 n 的所有索引信息存放到節(jié)點(diǎn) n 上,那要搜索資源 n 時(shí),只要找到節(jié)點(diǎn) n 即可,從而就可以避免泛洪廣播,能更快速而又準(zhǔn)確地路由和定位數(shù)據(jù)。當(dāng)然,在實(shí)際應(yīng)用中,資源 ID 和節(jié)點(diǎn) ID 之間是無法做到一一對(duì)應(yīng)的,但因?yàn)?ID 都是數(shù)字,就存在大小關(guān)系或偏序關(guān)系等,基于這些關(guān)系就能建立兩者的映射關(guān)系。這就是 DHT 的核心思想。DHT 算法在資源編號(hào)和節(jié)點(diǎn)編號(hào)上就是使用了分布式哈希表,使得資源空間和節(jié)點(diǎn)空間的編號(hào)有唯一性、均勻分布式等較好的性質(zhì),能夠適合結(jié)構(gòu)化分布式網(wǎng)絡(luò)的要求。

綜上,這就是 P2P 網(wǎng)絡(luò)的一點(diǎn)理論基礎(chǔ),不同的區(qū)塊鏈可能會(huì)使用不一樣的網(wǎng)絡(luò)模型,但基本原理是一樣的。后面分別講解下最有代表性的兩個(gè)區(qū)塊鏈的網(wǎng)絡(luò):比特幣網(wǎng)絡(luò)和以太坊網(wǎng)絡(luò)。

2、比特幣和以太坊中的P2P網(wǎng)絡(luò)整體對(duì)比分析

2.1 通信協(xié)議層面

  • 比特幣的P2P網(wǎng)絡(luò)完全基于TCP構(gòu)建,主網(wǎng)默認(rèn)通信端口是8333。
  • 以太坊的P2P網(wǎng)絡(luò)是一個(gè)完全加密的網(wǎng)絡(luò),提供UDP和TCP兩種連接方式,主網(wǎng)默認(rèn)TCP端口30303,推薦UDP發(fā)現(xiàn)端口為30301.

2.2 初始節(jié)點(diǎn)發(fā)現(xiàn)

比特幣網(wǎng)絡(luò)中,初始節(jié)點(diǎn)發(fā)現(xiàn)有兩種方式:

  1. DNS-seed,又稱為DNS種子節(jié)點(diǎn),比特幣的社區(qū)會(huì)維護(hù)一些域名,通過nslookup該域名可解析出數(shù)十個(gè)A記錄的主機(jī)IP。例如:

nc -nvv 149.202.179.35 8333
found 0 associations
found 1 connections:
1: flags=82<CONNECTED,PREFERRED>
outif en0
src 192.168.1.104 port 62125
dst 149.202.179.35 port 8333
rank info not available
TCP aux info available
Connection to 149.202.179.35 port 8333 [tcp/*] succeeded!

  1. 硬編碼一些seed-node,當(dāng)所有的種子節(jié)點(diǎn)全失效時(shí),全節(jié)點(diǎn)會(huì)嘗試連接這些種子節(jié)點(diǎn)。

在以太坊中,思路也大致相同,也是在代碼中硬編碼(hard-code)了一些種子節(jié)點(diǎn)做類似的工作。

2.3 啟動(dòng)后節(jié)點(diǎn)發(fā)現(xiàn)

在 Bitcoin 的網(wǎng)絡(luò)中,一個(gè)節(jié)點(diǎn)可以將自己維護(hù)的對(duì)等節(jié)點(diǎn)列表 (peer list) 發(fā)送給臨近節(jié)點(diǎn),所以在初始節(jié)點(diǎn)發(fā)現(xiàn)之后,你的節(jié)點(diǎn)要做的第一件事情就是向?qū)Ψ揭斜恚骸翱彀涯愕墓?jié)點(diǎn)列表給我復(fù)制一份。”

所以在每次需要發(fā)送協(xié)議消息的時(shí)候,它會(huì)花費(fèi)固定的時(shí)間嘗試和已存的節(jié)點(diǎn)列表中的節(jié)點(diǎn)建立鏈接,如果有任何一個(gè)節(jié)點(diǎn)在超時(shí)之前可以連接上,就不用去 DNS seed 獲取地址,一般來說,這種可能性很小,尤其是全節(jié)點(diǎn)數(shù)目非常多的情況下。

而在以太坊網(wǎng)絡(luò)中,也會(huì)維護(hù)類似的一個(gè)節(jié)點(diǎn)列表 (NodeTable),但是這個(gè)節(jié)點(diǎn)列表與比特幣的簡單維護(hù)不同,它采用了 P2P 網(wǎng)絡(luò)協(xié)議中一個(gè)成熟的算法,叫做 Kademlia 網(wǎng)絡(luò),簡稱 KAD 網(wǎng)絡(luò)。

它使用了 DHT 來定位資源,全稱 Distributed Hash Table,中文名為分布式哈希表。KAD 網(wǎng)絡(luò)會(huì)維護(hù)一個(gè)路由表,用于快速定位目標(biāo)節(jié)點(diǎn)。由于 KAD 網(wǎng)絡(luò)基于 UDP 通信協(xié)議,所以以太坊節(jié)點(diǎn)的節(jié)點(diǎn)發(fā)現(xiàn)是基于 UDP 的,如果找到節(jié)點(diǎn)以后,數(shù)據(jù)交互又會(huì)切換到 TCP 協(xié)議上。

2.4 NAT穿透

局域網(wǎng)中的主機(jī)IP與公網(wǎng)IP建立P2P連接的解決方案是做NAT穿透。
比特幣和以太坊均使用了 UPnP (Universal Plug and Play)協(xié)議作為局域網(wǎng)穿透工具,只要局域網(wǎng)中的路由設(shè)備支持 NAT 網(wǎng)關(guān)功能、支持 UPnP 協(xié)議,即可將你的區(qū)塊鏈節(jié)點(diǎn)自動(dòng)映射到公網(wǎng)上。

UPnP 是通用即插即用(Universal Plug and Play)的縮寫,它主要用于設(shè)備的智能互聯(lián)互通,所有在網(wǎng)絡(luò)上的設(shè)備馬上就能知道有新設(shè)備加入。

2.5 節(jié)點(diǎn)交互協(xié)議

一旦節(jié)點(diǎn)建立連接以后,節(jié)點(diǎn)之間的交互是遵循一些特定的命令,這些命令寫在消息的頭部,消息體寫的則是消息內(nèi)容。

命令分為兩種,一種是請(qǐng)求命令,一種是數(shù)據(jù)交互命令。

節(jié)點(diǎn)連接完成要做的第一件事情叫做握手操作。這一點(diǎn)在比特幣和以太坊上的流程是差不多的,就是相互問候一下,提供一些簡要信息。

比如先交換一下版本號(hào),看看是否兼容。只是以太坊為握手過程提供了對(duì)稱加密,而比特幣沒有。

握手完畢之后,無論交互什么信息,都是需要保持長連接的,在比特幣上有 PING/PONG 這兩種類型的消息,這很明顯就是用于保持節(jié)點(diǎn)之間長連接的心跳而設(shè)計(jì)的;而在以太坊的設(shè)計(jì)中,將 PING/PONG 協(xié)議移到了節(jié)點(diǎn)發(fā)現(xiàn)的過程中。

請(qǐng)求命令一般分為發(fā)起者請(qǐng)求,比如比特幣中的 getaddr 命令是為了獲取對(duì)方的可用節(jié)點(diǎn)列表,inv 命令則提供了數(shù)據(jù)傳輸,消息體中會(huì)包含一個(gè)數(shù)據(jù)向量。

我們說區(qū)塊鏈最重要的功能就是同步區(qū)塊鏈,而同步區(qū)塊恰巧是最考驗(yàn) P2P 網(wǎng)絡(luò)能力的。區(qū)塊同步方式分為兩種,第一種叫做 HeaderFirst,它提供了區(qū)塊頭先同步,同步完成以后再從其他節(jié)點(diǎn)獲得區(qū)塊體。

第二種叫做 BlockFirst,這種區(qū)塊同步的方式比較簡單粗暴,就是從其他節(jié)點(diǎn)獲取區(qū)塊必須是完整的。第一種方案提供了較好的交互過程,減輕了網(wǎng)絡(luò)負(fù)擔(dān)。這兩種同步方式會(huì)直接體現(xiàn)在節(jié)點(diǎn)交互協(xié)議上,他們使用的命令邏輯完全不同。

一般 P2P 網(wǎng)絡(luò)技術(shù)要解決兩個(gè)主要問題,第一是資源定位,第二是資源獲取,這一篇文章也是主要圍繞這兩點(diǎn)展開,其中節(jié)點(diǎn)發(fā)現(xiàn)和局域網(wǎng)穿透是屬于資源定位問題,節(jié)點(diǎn)交互協(xié)議是屬于資源獲取問題。

3、比特幣中的P2P網(wǎng)絡(luò)詳解

比特幣網(wǎng)絡(luò)

首先,比特幣網(wǎng)絡(luò)中的節(jié)點(diǎn)主要有四大功能:錢包、挖礦、區(qū)塊鏈數(shù)據(jù)庫、網(wǎng)絡(luò)路由。每個(gè)節(jié)點(diǎn)都會(huì)具備路由功能,但其他功能不一定都具備,不同類型的節(jié)點(diǎn)可能只包含部分功能,一般只有比特幣核心(bitcoin core)節(jié)點(diǎn)才會(huì)包含所有四大功能。

image.png

所有節(jié)點(diǎn)都會(huì)參與校驗(yàn)和廣播交易及區(qū)塊信息,且會(huì)發(fā)現(xiàn)和維持與其他節(jié)點(diǎn)的連接。有些節(jié)點(diǎn)會(huì)包含完整的區(qū)塊鏈數(shù)據(jù)庫,包括所有交易數(shù)據(jù),這種節(jié)點(diǎn)也稱為全節(jié)點(diǎn)(Full Node)。另外一些節(jié)點(diǎn)只存儲(chǔ)了區(qū)塊鏈數(shù)據(jù)庫的一部分,一般只存儲(chǔ)區(qū)塊頭而不存儲(chǔ)交易數(shù)據(jù),它們會(huì)通過“簡化交易驗(yàn)證(SPV)”的方式完成交易校驗(yàn),這樣的節(jié)點(diǎn)也稱為 SPV節(jié)點(diǎn)輕節(jié)點(diǎn)(Lightweight Node)。錢包一般是 PC 或手機(jī)客戶端的功能,用戶通過錢包查看自己的賬戶金額、管理錢包地址和私鑰、發(fā)起交易等。除了比特幣核心錢包是全節(jié)點(diǎn)之外,大部分錢包都是輕節(jié)點(diǎn)。挖礦節(jié)點(diǎn)則通過解決工作量證明(PoW)算法問題,與其他挖礦節(jié)點(diǎn)相互競爭創(chuàng)建新區(qū)塊。有些挖礦節(jié)點(diǎn)同時(shí)也是全節(jié)點(diǎn),即也存儲(chǔ)了完整的區(qū)塊鏈數(shù)據(jù)庫,這種節(jié)點(diǎn)一般都是獨(dú)立礦工(Solo Miner)。還有一些挖礦節(jié)點(diǎn)不是獨(dú)立挖礦的,而是和其他節(jié)點(diǎn)一起連接到礦池,參與集體挖礦,這種節(jié)點(diǎn)一般也稱為礦池礦工(Pool Miner)。這會(huì)形成一個(gè)局部的集中式礦池網(wǎng)絡(luò),中心節(jié)點(diǎn)是一個(gè)礦池服務(wù)器,其他挖礦節(jié)點(diǎn)全部連接到礦池服務(wù)器。礦池礦工和礦池服務(wù)器之間的通信也不是采用標(biāo)準(zhǔn)的比特幣協(xié)議,而是使用礦池挖礦協(xié)議,而礦池服務(wù)器作為一個(gè)全節(jié)點(diǎn)再與其他比特幣節(jié)點(diǎn)使用主網(wǎng)絡(luò)的比特幣協(xié)議進(jìn)行通信。

在整個(gè)比特幣網(wǎng)絡(luò)中,除了不同節(jié)點(diǎn)間使用比特幣協(xié)議作為通信協(xié)議的主網(wǎng)絡(luò),也存在很多擴(kuò)展網(wǎng)絡(luò),包括上面提到的礦池網(wǎng)絡(luò)。不同的礦池網(wǎng)絡(luò)可能還會(huì)使用不同的礦池挖礦協(xié)議,目前主流的具體礦池協(xié)議應(yīng)該是 Stratum協(xié)議,該協(xié)議除了支持挖礦節(jié)點(diǎn),也支持瘦客戶端錢包。一個(gè)包含了比特幣協(xié)議主網(wǎng)絡(luò)各種節(jié)點(diǎn)和 Stratum 網(wǎng)絡(luò),以及其他礦池網(wǎng)絡(luò)的擴(kuò)展比特幣網(wǎng)絡(luò)大概如下圖所示:

image.png

另外,挖礦這塊還有特殊需求。我們知道,礦工創(chuàng)建新區(qū)塊后,是需要廣播給全網(wǎng)所有節(jié)點(diǎn)的,當(dāng)全網(wǎng)都接受了該區(qū)塊,給礦工的挖礦獎(jiǎng)勵(lì)才算是有效的,這之后才好開始下一個(gè)區(qū)塊 Hash 的計(jì)算。所以礦工必須最大限度縮短新區(qū)塊的廣播和下一個(gè)區(qū)塊 Hash 計(jì)算之間的時(shí)間。如果礦工之間傳播區(qū)塊只采用上圖所示的比特幣協(xié)議網(wǎng)絡(luò),那無疑會(huì)有很高的網(wǎng)絡(luò)延遲,所以,需要一個(gè)專門的傳播網(wǎng)絡(luò)用來加快新區(qū)塊在礦工之間的同步傳播,這個(gè)專門網(wǎng)絡(luò)也叫比特幣傳播網(wǎng)絡(luò)或比特幣中繼網(wǎng)絡(luò)(Bitcoin Relay Network)。

4、以太坊中的P2P網(wǎng)絡(luò)詳解

以太坊網(wǎng)絡(luò)

和比特幣一樣,以太坊的節(jié)點(diǎn)也具備錢包、挖礦、區(qū)塊鏈數(shù)據(jù)庫、網(wǎng)絡(luò)路由四大功能,也同樣存在很多不同類型的節(jié)點(diǎn),除了主網(wǎng)絡(luò)之外也同樣存在很多擴(kuò)展網(wǎng)絡(luò)。但與比特幣不同的,比特幣主網(wǎng)的 P2P 網(wǎng)絡(luò)是無結(jié)構(gòu)的,但以太坊的 P2P 網(wǎng)絡(luò)是有結(jié)構(gòu)的。前面我們已經(jīng)提過,以太坊的 P2P 網(wǎng)絡(luò)主要采用了 Kademlia(簡稱 Kad) 算法實(shí)現(xiàn),Kad 是一種分布式哈希表(DHT)技術(shù),使用該技術(shù),可以實(shí)現(xiàn)在分布式環(huán)境下快速而又準(zhǔn)確地路由、定位數(shù)據(jù)的問題。所以,下面主要講解下以太坊的 Kad 網(wǎng)絡(luò)。

在 Kad 網(wǎng)絡(luò)中,每個(gè)節(jié)點(diǎn)都具有一個(gè)唯一的節(jié)點(diǎn) ID。另外,也會(huì)計(jì)算不同節(jié)點(diǎn)之間的距離,但這個(gè)距離不是物理上的距離,而是邏輯上的距離,是通過對(duì)兩個(gè)節(jié)點(diǎn) ID 進(jìn)行 異或(符號(hào)為^) 計(jì)算得到的,即 A、B 兩節(jié)點(diǎn)之間的距離的計(jì)算公式為:D(A,B) = A.ID^B.ID。異或有一個(gè)重要的性質(zhì):假設(shè) a、b、c 為任意三個(gè)數(shù),如果 a^b = a^c 成立,那就一定 b = c。因此,如果給定一個(gè)結(jié)點(diǎn) a 和距離 L,那就有且僅有一個(gè)結(jié)點(diǎn) b, 會(huì)使得 D(a,b) = L。通過這種方式,就能有效度量 Kad 網(wǎng)絡(luò)中不同節(jié)點(diǎn)之間的邏輯距離。

在異或距離度量的基礎(chǔ)上,Kad 還可以將整個(gè)網(wǎng)絡(luò)拓?fù)浣M織成如下圖所示的一個(gè)二叉前綴樹,每個(gè) NodeID 會(huì)映射到二叉樹上的某個(gè)葉子。

image.png

映射規(guī)則主要是:

  1. 將 NodeID 以二進(jìn)制形式表示,然后從高到低對(duì)每一位的 0 或 1 依次處理;
  2. 二進(jìn)制的第 n 位就對(duì)應(yīng)了二叉樹的第 n 層;
  3. 如果該位是 0,進(jìn)入左子樹,是 1 則進(jìn)入右子樹(反過來也可以);
  4. 全部位都處理完后,這個(gè) NodeID 就對(duì)應(yīng)了二叉樹上的某個(gè)葉子。

在這種二叉樹結(jié)構(gòu)下,對(duì)每個(gè)節(jié)點(diǎn)來說,離它越近的節(jié)點(diǎn)異或距離也是越近的。接著,可以按照離自己異或距離的遠(yuǎn)近,對(duì)整顆二叉樹進(jìn)行拆分。拆分規(guī)則是:從根節(jié)點(diǎn)開始,將不包括自己的那顆子樹拆分出來,然后在包含自己的子樹中,把不包括自己的下一層子樹再拆分出來,以此類推,直到只剩下自己。以上圖的 110 節(jié)點(diǎn)為例,從根節(jié)點(diǎn)開始,由于 110 節(jié)點(diǎn)在右子樹,所以將左邊的整顆子樹拆分出來,即包含 000、001、010 這三個(gè)節(jié)點(diǎn)的這顆子樹;接著,到第二層子樹,將不包含 110 節(jié)點(diǎn)的左子樹再拆分出來,即包含 100 和 101 這兩個(gè)節(jié)點(diǎn)的子樹;最后,再將 111 拆分出來。這樣,就將 110 節(jié)點(diǎn)之外的整個(gè)二叉樹拆分出了三顆子樹。

完成子樹拆分后,只要知道每個(gè)子樹里面的其中一個(gè)節(jié)點(diǎn),就可以進(jìn)行遞歸路由實(shí)現(xiàn)整顆二叉樹所有節(jié)點(diǎn)的遍歷。但在實(shí)際場(chǎng)景下,由于節(jié)點(diǎn)是動(dòng)態(tài)變化的,所以一般不會(huì)只知道每個(gè)子樹的一個(gè)節(jié)點(diǎn),而是需要知道多個(gè)節(jié)點(diǎn)。因此,Kad 中有一個(gè)叫 K-桶(K-bucket)的概念,每個(gè)桶會(huì)記錄每顆子樹里所知道的多個(gè)節(jié)點(diǎn)。其實(shí),一個(gè)K-桶就是一張路由表,如果拆分出來有 m 顆子樹,那對(duì)應(yīng)節(jié)點(diǎn)就需要維護(hù) m 個(gè)路由表。每個(gè)節(jié)點(diǎn)都會(huì)各自維護(hù)自己的 m 個(gè) K-桶,每個(gè) K-桶里記錄的節(jié)點(diǎn)信息一般會(huì)包括 NodeID、IP、Endpoint、與 Target 節(jié)點(diǎn)(即維護(hù)該 K-桶的節(jié)點(diǎn))的異或距離等信息。以太坊中,每個(gè)節(jié)點(diǎn)維護(hù)的 K-桶數(shù)量為 256 個(gè),這 256 個(gè) K-桶會(huì)根據(jù)與 Target 節(jié)點(diǎn)的異或距離進(jìn)行排序,每個(gè) K-桶保存的節(jié)點(diǎn)數(shù)量上限是 16。

在以太坊的 Kad 網(wǎng)絡(luò)中,節(jié)點(diǎn)之間的通信是基于 UDP 的,另外設(shè)置了 4 個(gè)主要的通信協(xié)議:

  1. Ping:用于探測(cè)一個(gè)節(jié)點(diǎn)是否在線
  2. Pong:用于響應(yīng) Ping 命令
  3. FindNode:用于查找與 Target 節(jié)點(diǎn)異或距離最近的其他節(jié)點(diǎn)
  4. Neighbours:用于響應(yīng) FindNode 命令,會(huì)返回一或多個(gè)節(jié)點(diǎn)

通過以上 4 個(gè)命令,就可以實(shí)現(xiàn)新節(jié)點(diǎn)的加入、K-桶的刷新等機(jī)制。具體的實(shí)現(xiàn)流程就不細(xì)講了,留給大伙自己去思考。

總結(jié)

不同結(jié)構(gòu)的 P2P 網(wǎng)絡(luò),會(huì)有不同的優(yōu)點(diǎn)和缺點(diǎn)。比特幣網(wǎng)絡(luò)的結(jié)構(gòu)明顯容易理解,實(shí)現(xiàn)起來也相對(duì)容易得多,而以太坊網(wǎng)絡(luò)引入了異或距離、二叉前綴樹、K-桶等,結(jié)構(gòu)上復(fù)雜不少,但在節(jié)點(diǎn)路由上的確會(huì)比比特幣快很多。另外,不管是比特幣還是以太坊,其實(shí)都只是一種或多種協(xié)議的集合,不同節(jié)點(diǎn)其實(shí)可以用不同的具體實(shí)現(xiàn),比如,比特幣就有用 C++ 實(shí)現(xiàn)的 Bitcoin Core,還有用 Java 實(shí)現(xiàn)的 BitcoinJ;以太坊也有用 Go 語言實(shí)現(xiàn)的 go-ethereum,也有用 C++ 實(shí)現(xiàn)的 go-ethereum,還有用 Java 實(shí)現(xiàn)的 Ethereum(J)。

思考和實(shí)踐

在以太坊的 Kad 網(wǎng)絡(luò)中,新節(jié)點(diǎn)的加入和 K-桶的刷新流程是怎樣的?比特幣的新節(jié)點(diǎn)加入流程又是怎樣的?哈希表有哪些實(shí)現(xiàn)方式?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容