當前位置:編程學習大全網 - 源碼破解 - 以太坊源碼分析--p2p節點發現

以太坊源碼分析--p2p節點發現

節點發現功能主要涉及 Server \ Table \ udp 這幾個數據結構,它們有獨自的事件響應循環,節點發現功能便是它們互相協作完成的。其中,每個以太坊客戶端啟動後都會在本地運行壹個 Server ,並將網絡拓撲中相鄰的節點視為 Node ,而 Table Node 的容器, udp 則是負責維持底層的連接。下面重點描述它們中重要的字段和事件循環處理的關鍵部分。

PrivateKey - 本節點的私鑰,用於與其他節點建立時的握手協商

Protocols - 支持的所有上層協議

StaticNodes - 預設的靜態 Peer ,節點啟動時會首先去向它們發起連接,建立鄰居關系

newTransport - 下層傳輸層實現,定義握手過程中的數據加密解密方式,默認的傳輸層實現是用 newRLPX() 創建的 rlpx ,這不是本文的重點

ntab - 典型實現是 Table ,所有 peer Node 的形式存放在 Table

ourHandshake - 與其他節點建立連接時的握手信息,包含本地節點的版本號以及支持的上層協議

addpeer - 連接握手完成後,連接過程通過這個通道通知 Server

Server 的監聽循環,啟動底層監聽socket,當收到連接請求時,Accept後調用 setupConn() 開始連接建立過程

Server的主要事件處理和功能實現循環

Node 唯壹表示網絡上的壹個節點

IP - IP地址

UDP/TCP - 連接使用的UDP/TCP端口號

ID - 以太坊網絡中唯壹標識壹個節點,本質上是壹個橢圓曲線公鑰(PublicKey),與 Server 的 PrivateKey 對應。壹個節點的IP地址不壹定是固定的,但ID是唯壹的。

sha - 用於節點間的距離計算

Table 主要用來管理與本節點與其他節點的連接的建立\更新\刪除

bucket - 所有 peer 按與本節點的距離遠近放在不同的桶(bucket)中,詳見之後的 節點維護

refreshReq - 更新 Table 請求通道

Table 的主要事件循環,主要負責控制 refresh revalidate 過程。

refresh.C - 定時(30s)啟動Peer刷新過程的定時器

refreshReq - 接收其他線程投遞到 Table 的 刷新Peer連接 的通知,當收到該通知時啟動更新,詳見之後的 更新鄰居關系

revalidate.C - 定時重新檢查以連接節點的有效性的定時器,詳見之後的 探活檢測

udp 負責節點間通信的底層消息控制,是 Table 運行的 Kademlia 協議的底層組件

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 的處理循環,負責控制消息的向上遞交和收發控制

udp 的底層接受數據包循環,負責接收其他節點的 packet

以太坊使用 Kademlia 分布式路由存儲協議來進行網絡拓撲維護,了解該協議建議先閱讀 易懂分布式 。更權威的資料可以查看 wiki 。總的來說該協議:

源碼中由 Table 結構保存所有 bucket bucket 結構如下

節點可以在 entries replacements 互相轉化,壹個 entries 節點如果 Validate 失敗,那麽它會被原本將壹個原本在 replacements 數組的節點替換。

有效性檢測就是利用 ping 消息進行探活操作。 Table.loop() 啟動了壹個定時器(0~10s),定期隨機選擇壹個bucket,向其 entries 中末尾的節點發送 ping 消息,如果對方回應了 pong ,則探活成功。

Table.loop() 會定期(定時器超時)或不定期(收到refreshReq)地進行更新鄰居關系(發現新鄰居),兩者都調用 doRefresh() 方法,該方法對在網絡上查找離自身和三個隨機節點最近的若幹個節點。

Table 的 lookup() 方法用來實現節點查找目標節點,它的實現就是 Kademlia 協議,通過節點間的接力,壹步壹步接近目標。

當壹個節點啟動後,它會首先向配置的靜態節點發起連接,發起連接的過程稱為 Dial ,源碼中通過創建 dialTask 跟蹤這個過程

dialTask表示壹次向其他節點主動發起連接的任務

在 Server 啟動時,會調用 newDialState() 根據預配置的 StaticNodes 初始化壹批 dialTask , 並在 Server.run() 方法中,啟動這些這些任務。

Dial 過程需要知道目標節點( dest )的IP地址,如果不知道的話,就要先使用 recolve() 解析出目標的IP地址,怎麽解析?就是先要用借助 Kademlia 協議在網絡中查找目標節點。

當得到目標節點的IP後,下壹步便是建立連接,這是通過 dialTask.dial() 建立連接

連接建立的握手過程分為兩個階段,在在 SetupConn() 中實現

第壹階段為 ECDH密鑰建立 :

第二階段為協議握手,互相交換支持的上層協議

如果兩次握手都通過,dialTask將向 Server 的 addpeer 通道發送 peer 的信息

  • 上一篇:免費解夢網
  • 下一篇:零基礎學習Java編程報java培訓班有用嗎?
  • copyright 2024編程學習大全網