更通用的P2P網路協議棧——Libp2p

買賣虛擬貨幣
Libp2p是什麼?Libp2p是用於構建P2P網路的模組化網路堆疊和庫,源自開源專案IPFS,模組化設計使它能夠用來構建各種去中心化應用的P2P網路層。目前,知名區塊鏈專案Ethereum 2.0、Pokdot、BitXHub都選擇基於Libp2p庫搭建系統網路層。Libp2p作為P2P網路協議棧,它是透過解決實際問題不斷成長的,可以認為是構建P2P網路經驗的積累。Libp2p解決了哪些問題?Libp2p作為網路協議棧,主要解決兩個問題:· 節點發現節點發現用來發現P2P網路中的其它節點及維護節點線上狀態,並且根據節點狀態調整網路連線,構建穩定的網路拓撲。
· 資料傳輸資料傳輸負責節點間資料的流轉。為了支援各種異構的網路裝置互連,Libp2p核心要求之一就是傳輸層不可知,Libp2p支援不同的傳輸層協議,例如TCP、UDP、QUIC等。在傳輸層建立連線後還需要考慮網路資料的隱私安全,Libp2p對傳輸通道加密,節點間透過加密通道進行通訊。為了高效傳輸資料,Libp2p支援對連線進行多路流複用從而支援節點間多個併發流通訊。本文主要討論Libp2p解決資料傳輸問題方案,程式碼基於go-libp2p v0.9.2。Libp2p是如何解決資料傳輸問題的· 傳輸層不可知
傳輸層不可知是指Libp2p支援多種傳輸層協議,例如TCP、UDP、QUIC等,應用程式開發者在使用Libp2p庫時不需要知道完成資料傳輸使用的傳輸層協議,Libp2p會根據遠端節點地址資訊自動完成協議選擇。· 地址定義資料傳輸建立在節點連線的基礎上,在可以撥號遠端節點並建立連線之前,需要知道遠端節點的監聽地址。因為每種傳輸協議都有自己的地址格式,所以Libp2p使用一種稱為“multiaddr”的編碼方案來統一不同的協議的地址格式。TCP/IP傳輸協議“multiaddr”的描述如下:/ip4/127.0.0.1/tcp/9999UDP傳輸協議“multiaddr”的描述如下:
/ip4/127.0.0.1/udp/9998用這種描述方式來代替127.0.0.1:9999的好處是什麼呢?“multiaddr”能更明確的描述使用的協議,如127.0.0.1屬於IPv4協議,9999屬於TCP協議,9998屬於UDP協議。以上為“multiaddr”描述的節點監聽地址,當撥號一個節點時也是使用“multiaddr”,但需要加上遠端節點的ID,例如:/ip4/192.168.100.100/tcp/9999/p2p/QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6這樣就知道對方使用IP4,地址:192.168.100.100,TCP協議,埠:9999,是一個P2P節點,節點ID:QmcEPrat8ShnCph8WjkREzt5CPXF2RwhYxYBALDcLC1iV6。· 節點ID定義
節點ID是一串字元,由節點公鑰的hash產生,並進行base58編碼,節點ID是全網唯一的,撥號時使用節點ID可以有效解決中間人攻擊問題。· 支援多種傳輸協議

Libp2p的Swarm模組負責將多個傳輸層組合到一個介面中,從而允許應用程式撥號節點,而不必指定要使用的傳輸層。它還負責協議協商、多路流複用、建立安全通訊等介面升級操作。

Network介面是Libp2p對外提供服務的介面,Swarm是Network介面的具體實現。Libp2p在Swarm中維護現有連線的狀態,維護支援的傳輸層協議。Swarm透過以下操作支援多傳輸協議:

· 為了支援多種傳輸層協議,新建節點時(NewNode)會將節點支援的傳輸層協議透過AddTransport加入Swarm的transports結構中。

·  當節點開啟監聽(Listen)時,Swarm模組會呼叫TransportForListening獲取監聽地址對應的傳輸層協議,並呼叫相應的傳輸層協議的Listen函式。

· 當節點主動連線(Dial)其它節點時,Swarm模組會呼叫TransportForDialing獲取撥號地址使用的傳輸協議,並呼叫相應的傳輸層協議的Dial函式。

Libp2p透過“multiaddr”的編碼方案來統一不同協議的地址格式,在Swarm模組根據“multiaddr”解析協議並呼叫相應協議的介面完成具體操作,從而達到了應用層不需要關注使用的傳輸層協議的目的。

資料安全傳輸

以上過程在節點間建立了連線,Libp2p是如何保證傳輸資料隱私的?這裡以TCP協議為例進行展開介紹。

TcpTransport是TCP的傳輸層實現模組,其中組合了Upgrader模組,Upgrader負責把一個原始的TCP連線升級為支援加密,支援多路流複用的連線。secio和tls是兩個實現了SecureTransport介面的庫,Libp2p庫預設使用secio加密庫。

以上為TCP收到一個遠端節點連線請求的呼叫流程,主動撥號遠端節點呼叫過程類似。這裡使用secio包的runHandshakeSync函式對連線進行加密。

secio庫金鑰交換使用Diffie-Hellman金鑰協商演算法(secio協議具體內容)。當然也可以使用tls對連線進行加密。

多路流複用

Libp2p應用程式通常會在節點之間開啟許多獨立的通訊流,並且可能會與某個遠端節點同時開啟多個併發流。多路流複用允許與遠端節點建立一次連線即可完成整個生命週期的資料收發,同樣只需要處理一次NAT操作,因為和同一個遠端節點所有的流都共享相同的底層傳輸連線。在配置Libp2p時,會啟用流複用模組,Swarm將在撥號遠端節點和偵聽連線時使用它們。如果遠端節點支援相同的多路流複用實現,則Swarm將在建立連線時選擇並使用它;如果撥號Swarm已經與之建立連線的遠端節點,則新建流將自動在現有連線上進行多路複用。

upgrader的muxer模組負責將加密後的連線升級為支援多路流複用的連線。MuxedConn為多路流複用操作介面,multiplex為多路流複用操作具體實現,負責具體的流建立及管理。除了預設的multiplex,Libp2p還支援yamux、spdy、muxado等不同的多路複用器實現。

還是以監聽為例,收到連線請求後,Upgrader的Secure模組首先會將連線升級為加密連線。然後透過NewMultiplex建立多路複用器例項,多路複用器例項把介面升級為支援流複用的介面。

MuxedConn的OpenStream介面用於向遠端節點傳送新建流請求,AcceptStream介面用於接收遠端節點建立流的請求。

由於節點間通訊多個流使用的仍是同一個連線,為了區別不同的流,multiplex模組實際上是對傳送的資料新增了header欄位。

header高61bits為stream id,每次新建流時stream id會自增。

header低3位表示訊息型別,總共定義了4種流訊息:

newStreamTag = 0  // 建立流訊息
messageTag= 2 // 資料訊息
closeTag= 4 // 關閉流訊息
resetTag= 6 // 重置流訊息

Libp2p透過upgrader的muxer模組將普通介面升級為支援流複用的介面,節點間資料傳輸時會在連線上透過流進行並行資料收發,而不是新建連線,從而減少了節點間新建連線的消耗。為了區別不同的流上的資訊,流複用器對收發資料新增了表示流資訊的header欄位。

總結

從Libp2p解決資料傳輸問題能夠看到Libp2p有很多小元件組成,解決相同問題小元件遵循相同介面,可以根據使用場景進行替換,各元件庫可以單獨開發升級,而不會對其它部分產生影響。“multiaddr”的地址編碼方案使基於Libp2p的應用層開發不需要關注底層使用的傳輸層協議。節點間可以透過協議協商選擇共同支援的加密模組對資料傳輸通道進行加密,從而保證資料隱私性。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;