摘要:前言負責以太坊底層節點間的通信,主要包括底層節點發現和上層協議運行兩大部分。啟動了一個定時器,定期隨機選擇一個,向其中末尾的節點發送消息,如果對方回應了,則探活成功。
前言
p2p(peer to peer)負責以太坊底層節點間的通信,主要包括底層節點發現(discover)和上層協議運行兩大部分。
節點發現節點發現功能主要涉及 Server Table udp 這幾個數據結構,它們有獨自的事件響應循環,節點發現功能便是它們互相協作完成的。其中,每個以太坊客戶端啟動后都會在本地運行一個Server,并將網絡拓撲中相鄰的節點視為Node,而Table是Node的容器,udp則是負責維持底層的連接。這些結構的關系如下圖
p2p/server.go type Server struct { PrivateKey *ecdsa.PrivateKey Protocols []protocol StaticNodes[] *discover.Node newTransport func(net.Conn) transport ntab disvocerTable ourHandshake *protoHandshake addpeer chan *conn ...... }
PrivateKey - 本節點的私鑰,用于與其他節點建立時的握手協商
Protocols - 支持的所有上層協議
StaticNodes - 預設的靜態Peer,節點啟動時會首先去向它們發起連接,建立鄰居關系
newTransport - 下層傳輸層實現,定義握手過程中的數據加密解密方式,默認的傳輸層實現是用newRLPX()創建的rlpx,這不是本文的重點
ntab - 典型實現是Table,所有peer以Node的形式存放在Table
ourHandshake - 與其他節點建立連接時的握手信息,包含本地節點的版本號以及支持的上層協議
addpeer - 連接握手完成后,連接過程通過這個通道通知Server
Server的監聽循環,啟動底層監聽socket,當收到連接請求時,Accept后調用setupConn()開始連接建立過程
Server的主要事件處理和功能實現循環
進行主動的節點發現,詳見之后的節點發現部分
posthandshake channel 接收已經完成第一階段的連接,這些連接的身份已經被確認,但還需要驗證
addpeer channel 接收已經完成第二階段的連接,這些連接已經驗證,調用runPeer()運行本節點與Peer連接上的協議
NodeNode唯一表示網絡上的一個節點
p2p/discover/node.go type Node struct { IP net.IP UDP, TCP uint16 ID NodeID sha common.Hash }
IP - IP地址
UDP/TCP - 連接使用的UDP/TCP端口號
ID - 以太坊網絡中唯一標識一個節點,本質上是一個橢圓曲線公鑰(PublicKey),與Server的PrivateKey對應。一個節點的IP地址不一定是固定的,但ID是唯一的。
sha - 用于節點間的距離計算
Table主要用來管理與本節點與其他節點的連接的建立更新刪除
p2p/discover/table.go type Table struct { bucket [nBuckets]* bucket refreshReq chan chan struct{} ...... }
bucket - 所有peer按與本節點的距離遠近放在不同的桶(bucket)中,詳見之后的節點維護
refreshReq - 更新Table請求通道
Table的主要事件循環,主要負責控制refresh和revalidate過程。
refresh.C - 定時(30s)啟動Peer刷新過程的定時器
refreshReq - 接收其他線程投遞到Table的刷新Peer連接的通知,當收到該通知時啟動更新,詳見之后的更新鄰居關系
revalidate.C - 定時重新檢查以連接節點的有效性的定時器,詳見之后的探活檢測
udp負責節點間通信的底層消息控制,是Table運行的Kademlia協議的底層組件
type udp struct { conn conn addpending chan *pending gotreply chan reply *Table }
conn - 底層監聽端口的連接
addpending -udp用來接收pending的channel。使用場景為:當我們向其他節點發送數據包后(packet)后可能會期待收到它的回復,pending用來記錄一次這種還沒有到來的回復。舉個例子,當我們發送ping包時,總是期待對方回復pong包。這時就可以將構造一個pending結構,其中包含期待接收的pong包的信息以及對應的callback函數,將這個pengding投遞到udp的這個channel。udp在收到匹配的pong后,執行預設的callback。
gotreply - udp用來接收其他節點回復的通道,配合上面的addpending,收到回復后,遍歷已有的pending鏈表,看是否有匹配的pending。
Table - 和Server中的ntab是同一個Table
udp的處理循環,負責控制消息的向上遞交和收發控制
addpending 接收其他線程投遞來的pending需求
gotreply 接收udp.readLoop()投遞過來的pending的回復
udp的底層接受數據包循環,負責接收其他節點的packet
接受其他節點發送的packet并解析,如果是回復包則投遞到udp.loop()
以太坊使用Kademlia分布式路由存儲協議來進行網絡拓撲維護,了解該協議建議先閱讀易懂分布式。更權威的資料可以查看wiki。總的來說該協議:
使用UDP進行節點間消息通信,有 4 種消息
ping - 用于探測其他節點是否還存在
store - 接收者受到后,將信息中key/value對存儲在本節點
findnode - 接受者向發送者返回 k 個它知道的與目標結點距離最近的節點
findvalue - 和findnode 差不多,區別是如果接收者本地存在與目標結點對應的value,那么就回復這個值給發送者。
每個節點根據與鄰居節點距離之間的距離(NodeID的差距),分別放到不同的桶(bucket)中。
本文說的距離,均是指兩個節點NodeID的距離,計算方式可見p2p/discover/node.go的logdist()方法
源碼中由Table結構保存所有bucket,bucket結構如下
p2p/discover/table.go type bucket struct { entries []*Node replacemenets []*Node ips netutil.DistinctNetSet }
entries 數組中保存經過bond的節點,并且其順序是越新bond通過了探活檢測(Revalidate)的節點位置越靠前。
replacemenets數組中保存候補節點,如果entries 數組數量滿了,之后的節點會被加入該數組
節點可以在entries和replacements互相轉化,一個entries節點如果Validate失敗,那么它會被原本將一個原本在replacements數組的節點替換。
探活檢測(Revalidate)有效性檢測就是利用ping消息進行探活操作。Table.loop()啟動了一個定時器(0~10s),定期隨機選擇一個bucket,向其entries中末尾的節點發送ping消息,如果對方回應了pong,則探活成功。
舉個栗子,假設某個bucket, entries最多保存2個節點,replacements最多保存4個節點。初始情況下entries=[A, B], replacements = [C, D, E],如果此時節點F加入網絡,bond通過,由于entries已滿,只能加入到replacements = [C, D, E, F]。 此時Revalidate定時器到期,則會對 B進行檢測,如果通過,則entries=[B, A],如果不通過,則將隨機選擇replacements中的一項(假設為D)替換B的位置,最終entries=[A, D],replacements = [C, E, F]更新鄰居關系
Table.loop()會定期(定時器超時)或不定期(收到refreshReq)地進行更新鄰居關系(發現新鄰居),兩者都調用doRefresh()方法,該方法對在網絡上查找離自身和三個隨機節點最近的若干個節點。
節點查找Table的lookup()方法用來實現節點查找目標節點,它的實現就是Kademlia協議,通過節點間的接力,一步一步接近目標。
鄰居初始化當一個節點啟動后,它會首先向配置的靜態節點發起連接,發起連接的過程稱為Dial,源碼中通過創建dialTask跟蹤這個過程
dialTaskdialTask表示一次向其他節點主動發起連接的任務
p2p/dial.go type dialTask struct { flags connFlag dest *discover.Node ...... }
在Server啟動時,會調用newDialState()根據預配置的StaticNodes初始化一批dialTask, 并在Server.run()方法中,啟動這些這些任務。
Dial過程需要知道目標節點(dest)的IP地址,如果不知道的話,就要先使用 recolve()解析出目標的IP地址,怎么解析?就是先要用借助Kademlia協議在網絡中查找目標節點。
當得到目標節點的IP后,下一步便是建立連接,這是通過dialTask.dial()建立連接
連接建立的握手過程分為兩個階段,在在SetupConn()中實現
第一階段為ECDH密鑰建立:
sequenceDiagram Note left of Dialer: Calc token Note left of Dialer: Generate Random PrikeyNonce Note left of Dialer: Sign Dialer->>Receiver: AuthMsg Note right of Receiver: Calc token Note right of Receiver: Check Signature Note right of Receiver: Generate Random PrikeyNonce Receiver->>Dialer: AuthResp
第二階段為協議握手,互相交換支持的上層協議
sequenceDiagram Dialer->>Receiver: protoHandshake Receiver->>Dialer: protoHandshake
如果兩次握手都通過,dialTask將向Server的addpeer通道發送peer的信息
sequenceDiagram participant Server.run() participant dialTask participant Remote Node dialTask->>Remote Node:EncHandshake Remote Node->>dialTask:EncHandshake dialTask->>Server.run(): posthandshake dialTask->>Remote Node:ProtoHandshake Remote Node->>dialTask:ProtoHandshake dialTask->>Server.run(): addpeer Note over Server.run(): go runPeer()協議運行
協議運行并不單單指某個特定的協議,準確地說應該是若干個獨立的協議同時在兩個節點間運行。在p2p節點發現提到過,節點間建立連接的時候會經過兩次握手,其中的第二次握手,節點間會交換自身所支持的協議。最終兩個節點間生效的協議為兩個節點支持的協議的交集。
功能主要涉及 Peer protoRW 這幾個數據結構,其關系如圖
rw - 節點間連接的底層信息,比如使用的socket以及對端節點支持的協議(capabilities)
running - 節點間生效運行的協議簇
Peer.run()負責連接建立后啟動運行上層協議,它自身運行在一個獨立的go routine,具有自己的事件處理循環,除此之外,它還會額外創建2+n個go routine, 其中2包括一個用于保活的pingLoop() go routine和一個用于接收協議數據的readLoop() go routine ,而 n 為運行于其上的n個協議的go routine,即每個協議調用自己的Run()方法運行在自己多帶帶的go routine
Run 每種協議自身的運行入口,以新的go routine形式啟動.
總結p2p主要由底層節點發現和上層協議運行兩部分組成,節點發現負責管理以太坊網絡中各個節點間的連接建立,更新和刪除,Server是p2p功能的入口,Table負責記錄peer節點信息, udp負責底層通信。而在底層的基礎上,節點間可以運行多個獨立的協議。
以太坊使用Kademlia分布式路由存儲協議來進行網絡拓撲維護,將不同距離的peer節點放在不同的bucket中。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/24380.html
摘要:前言是以太坊中一項非常有趣的技術,它是一個基于身份的通信系統,被設計用于之間少量數據通信。協議運行在以太坊協議框架之上,所有運行協議的節點以下簡稱節點組成一個網絡。 [TOC] 前言 Whisper是以太坊中一項非常有趣的技術,它是一個基于身份的通信系統,被設計用于Dapp之間少量數據通信。Whisper協議運行在以太坊p2p協議框架之上,所有運行Whisper協議的節點(以下簡稱節點...
摘要:說明的視頻片段分發現在沒做出什么成果作者還提了一句,協議有望成為直播內容的傳播協議。仿佛也沒能掩飾住不知道怎么分發視頻片段的尷尬說了這么多,看了代碼發現視頻片段還是通過分發總結最終將建立一個可擴展的,即用即付的直播網絡 Background Livepeer旨在構建帶有激勵機制的視頻直播分布式網絡 Blockchain 以太坊 智能合約和交易基于Ethereum以太坊網絡 DP...
閱讀 738·2021-11-11 16:54
閱讀 3053·2021-09-26 09:55
閱讀 2004·2021-09-07 10:20
閱讀 1198·2019-08-30 10:58
閱讀 1040·2019-08-28 18:04
閱讀 698·2019-08-26 13:57
閱讀 3584·2019-08-26 13:45
閱讀 1150·2019-08-26 11:42