以太坊節點發現協議
本檔前部分翻譯自以太坊定義的節點發現協議(版本4),後半部分給出了原始碼實現的大致流程,以幫助理解。
以太坊節點資訊的儲存採用的是
Kademlia
分散式雜湊表。理解節點發現協議主要是理解分散式雜湊表的原理,再加上定義的節點間通訊的報文格式,節點ID的定義,距離的計算,加在一起就是以太坊的節點發現協議了。以太坊不同語言版本程式碼實現上具體細節可能不同但大致流程思想是相同的。
第一部分——節點發現協議定義
節點ID
每個節點都有一個
secp256k1
橢圓曲線密碼學ID。節點的公鑰作為標識或節點ID。節點之間的距離為公鑰按位異或或者是公鑰的雜湊值按位異或。計算公式如下:
distance(n₁, n₂) = keccak256(n₁) XOR keccak256(n₂)
節點表
節點表在節點發現協議中用於儲存鄰節點資訊。鄰節點被存在一個包含有K桶的路由表中。協議中 k = 16 ,即每個K桶至多含有16個節點條目。每項按時間排序——最新發現更新的節點放在前,其他在後。
每當一個新節點 N 1 被發現,就可以插入相應的桶中。如果桶中少於 k 個條目, N 1 可新增到桶中第一個條目。如果桶中已含有 k 項,桶中最早發現的節點 N 2 ,需要透過傳送ping包重新檢測其有效性。如果沒有收到來自 N 2 的回覆則認為該節點已失效(下線),從路由表中移除並將 N 1 新增到桶的前部。
以太坊文件中
Node Table
一節有部分內容錯誤,For each 0 ≤ i < 256, every node keeps a k-bucket for nodes of distance between 2i and 2i+1 from itself.
,應該是 [ 2 i , 2 i + 1 ) 。建議閱讀論文 。
端點驗證
為了預防流量放大攻擊,必須驗證查詢的傳送者是否參與了發現協議。如果資料包的傳送者在過去12小時內傳送了具有匹配ping雜湊的有效pong響應,則認為該資料包的傳送者已經過驗證。
遞迴查詢
一次查詢會找到
k
個距離目標節點最近的節點。節點查詢發起後先選取
a
個距離目標節點最近的已知節點。隨後同時向這些節點傳送
FindNode
包。其中,
a
是一個引數,通常可設為3。發起者繼續向先前查詢到的節點傳送
FindNode
,如此不斷進行遞迴。對獲知的
k
個離目標節點最近的節點,選取
a
個尚未查詢過的節點向其傳送
FindNode
。無法快速響應的節點將被排除在外,除非他們做出響應。
如果一輪
FindNode
查詢失敗,即沒有返回任何一個比目前節點中更近的節點,那麼將會繼續向
k
個最近節點未被查詢過的節點中傳送
FindNode
。
報文協議
節點發現協議報文都是UDP報文,報文中最大的是1280位元組。
packet = packet-header || packet-data
資料包頭部:
packet-header = hash || signature || packet-typehash = keccak256(signature || packet-type || packet-data)signature = sign(packet-type || packet-data)
當在同一UDP埠上執行多個協議時,
hash
可使分組格式可識別。除此並無其他目的。每個包都由節點公鑰來簽名,簽名是一個編碼長度為65位元組陣列,簽名值
r,s
,簽名驗證值
v
。
訊息型別
packet-type
佔單位元組。包有效資料在訊息型別後面。資料包頭部之後的資料用RLP進行編碼。根據EIP-8,實現應忽略列表中的任何其他元素以及列表後的任何額外資料。
Ping Packet (0x01)
packet-data = [version, from, to, expiration]version = 4from = [sender-ip, sender-udp-port, sender-tcp-port]to = [recipient-ip, recipient-udp-port, 0]packet-data = [ver
expiration
欄位是UNIX時間戳,如果一個資料包的時戳過期了可能會無法處理。收到ping資料包後,接收節點應回覆pong資料包。並可考慮將傳送節點新增到節點表中。
如果在過去12小時內未與傳送方進行任何通訊,則除了pong之外還應傳送ping以驗證對端節點。
Pong Packet (0x02)
packet-data = [to, ping-hash, expiration]
Pong是ping的響應。
ping-hash
須與相應的ping包
hash
一致。實現時應該忽略那些不含有ping包
hash
的pong包。
FindNode Packet (0x03)
packet-data = [target, expiration]
FindNode
包用於請求距離目的節點近的節點。目標節點ID是一個65位元組長度的
secp256k1
橢圓曲線公鑰。當接收到
FindNode
,接收端需要回覆在本地節點表中距離請求目的節點最近的16個節點。
為了對抗流量放大攻擊,只有被驗證過的
FindNode
傳送者才會被回覆鄰節點資訊。
Neighbors Packet (0x04)
packet-data = [nodes, expiration]nodes = [[ip, udp-port, tcp-port, node-id], ... ]
FindNode
包的響應。
存在的問題及建議
凡含有
expiration
欄位的資料包都是用於防止資料重放的。因為是絕對時間戳,節點時鐘必要要十分準確以正確驗證時戳的有效性。自從2016年協議釋出後起,已經接收到無數的因為使用者的時鐘不準確造成的錯誤報告。
端點驗證是不嚴密是因為
FindNode
的傳送方永遠法確定接收端十分接收到足夠的pong。Geth按如下方式處理:如果在最近12小時內未與收件人進行通訊,請透過傳送ping啟動該過程。等待來自另一方的ping,回覆它然後傳送
FindNode
。
第二部分——節點發現協議程式碼實現流程
流程圖
節點如何加入到對應的K桶
計算節點之間的距離很簡單,直接按位異或後的值即為兩節點之間的距離值,但節點應該加入那個K桶呢?可以公鑰雜湊值按位異或後最高位的值(例如: 異或值
0000 ... 0000 0101
,則桶距離為3 ),則將節點放入第3個桶中。
為什麼?
主要是要理解二叉樹的拆分過程:
對每一個節點,都可以
按照自己的視角對整個二叉樹進行拆分。拆分的規則是:先從根節點開始,把
不包含自己的那個子樹拆分出來;然後在剩下的子樹再拆分不包含自己的下一層子樹;以此類推,直到最後只剩下自己。
拆分的最後一個K桶(距離自己最近的那個K桶),只有最後1位不同,異或值為
0000 ... 0000 0001
,最高位為1,第一個K桶;拆分的倒數第二個K桶,異或值為
0000 ... 0000 001x
,最高位為2,第二個K桶;依此類推......
在具體實現細節上,以太坊節點節點公鑰是512位,計算距離時的ID是取節點公鑰的雜湊,值為256位。所以節點路由表由256個K桶組成,每個K桶最多16個節點。
參考文件:
Node Discovery Protocol v4
聊聊分散式雜湊表(DHT)的原理——以 Kademlia(Kad) 和 Chord 為例
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69973775/viewspace-2697828/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 以太坊原始碼分析(15)node包建立多重協議以太坊節點原始碼協議
- 以太坊原始碼分析(37)eth以太坊協議分析原始碼協議
- 死磕以太坊原始碼分析之p2p節點發現原始碼
- Python從頭實現以太坊(二):Pinging引導節點Python
- 死磕以太坊原始碼分析之rlpx協議原始碼協議
- 以太坊公鏈節點連線節點超時問題排查
- Geth簡介及如何執行以太坊節點
- 以太坊智慧合約開發第三篇:安裝節點工具Ganache
- 慢霧區披露新攻擊手法,建議不要在以太坊節點存放私鑰檔案
- Python Web3.py 設定託管以太坊節點(Windows)PythonWebWindows
- 以太坊開發計劃
- 以太坊DApp開發指南APP
- 路印協議成為WBTC合作伙伴:將比特幣帶入以太坊協議比特幣
- EthBox以太坊開發套件,一鍵安裝部署以太坊開發環境套件開發環境
- 如何通過Geth、Node.js和UNIX/PHP訪問以太坊節點Node.jsPHP
- 如何通過 Geth、Node.js 和 UNIX/PHP 訪問以太坊節點Node.jsPHP
- 如何透過 Geth、Node.js 和 UNIX/PHP 訪問以太坊節點Node.jsPHP
- 以太坊學習筆記————4、以太坊發展歷史回顧筆記
- web3公測版本教程(三)-不用自己同步以太坊節點,直接發起簽名交易Web
- 以太坊是什麼?以太坊交易可靠嗎?
- 以太坊連載(一):以太坊是什麼?
- Cisco發現協議協議
- 以太坊智慧合約開發第二篇:理解以太坊相關概念
- 開發者的以太坊入門指南 | Jeth 以太坊系列線下活動
- 3.5 以太坊開發環境搭建開發環境
- 如何使用Meteor開發以太坊DappAPP
- 理解以太坊DApp及開發工具APP
- 以太坊原始碼分析(18)以太坊交易執行分析原始碼
- 以太坊學習筆記————1、以太坊是什麼?筆記
- 以太坊學習筆記————7、以太坊賬戶管理筆記
- Python從頭實現以太坊(六):RoutingPython
- 以太坊代幣空投合約實現
- 以太坊簡介
- 以太坊原始碼分析(47)p2p-rlpx節點之間的加密鏈路原始碼加密
- 以太坊原始碼分析(52)以太坊fast sync演算法原始碼AST演算法
- WebSocket 協議 1~4 節Web協議
- WebSocket 協議 5~10 節Web協議
- 【以太坊剖析】以太坊虛擬機器(EVM)之基本定義虛擬機