實現以太坊第二周 RLPX 子協議, Actor model
來自專欄 代碼水上書
根據上篇繼續: 實現以太坊第一周 DEVP2P::RLPX 握手協議
本周比較懶,字寫的盡量少一點。
上周實現了以太坊的網路協議 DevP2P 中的握手部分。DevP2P 還包括了節點發現功能,子協議傳輸功能,還有整合了所有以上邏輯的 Server。
下一步我打算優先實現以太坊子協議,而不是繼續實現 DevP2P 的其他功能。
以太坊子協議定義了一整套以太坊節點間的消息格式:同步區塊,獲取交易信息,獲取區塊頭等等。實現了以太坊子協議,就可以接著實現區塊同步,挖礦,還有相關的 web 3 介面。這部分功能觸及了區塊鏈、以太坊的核心機制,實現起來很有意思。比起單純的 DevP2P 協議更有趣,所以我們採用深度優先的方式來實現以太坊,先做個能部分使用的客戶端。
以太坊子協議是通過 DevP2P 中『RLPX 子協議』功能實現。上周我們實現了 RLPX 握手,握手之後就可以通過 RLPX 傳輸數據。RLPX 使用子協議的概念進行數據傳輸。
RLPX 子協議
RLPX 包包含了 code, size, payload 三個欄位。
RLPX 包(message): code | size | payload
payload 中用來保存二進位信息。(經過以太坊使用的 RLP 編碼後的內容)
『RLPX 子協議』是在 RLPX 包之上的邏輯,允許包中傳輸幾個不相干的子協議信息。
RLPX 通信時要求兩個節點事先知道自己支持的子協議的 name、version、length 。
發送信息時按照 name, version 排序,並用 message code 代表當前協議的偏移量。
這樣兩個節點知道協議的順序、長度,也知道偏移量,發送消息時如下:
預先知道: protocol-1(name: "eth", version: 63, length:17)protocol-2(name: "test", version: 1, length:20)RLPX 包(message): code | size | payload發送 protocol-1 時:code: 16(message 頭,固定 16)payload: protocol-1 內容發送 protocol-2 時,protocol-2 排序在 p1 之後,所以 code 要加上 p1 的偏移量:code: 16(message 頭) + 17(p1 的長度)payload: protocol-2 內容可以看出,通過 message code 偏移,RLPX 能夠實現一個包中同時存在多個協議,但目前看 geth 代碼中並沒有這樣使用。
於是接收者也能按照同樣規則解析不同的子協議。
Actor 模型
參考 geth 簡單的實現了DevP2P Server 的基礎功能,Server 能主動連接 bootnode 並進行以太坊子協議的握手。
DevP2P Server 維護多個節點(peers),每個節點同時有多個子協議,不同的子協議理論上都是可以並發處理的。
geth 大量使用 channel 和 go-routine 處理並發邏輯,導致代碼有點混亂。
如果用 Actor 模型,介面會更整潔。
Actor 是個自動執行的實體,和對象不同,只能通過發送或接收消息來和 Actor 通信。
初接觸 Actor 模型時沒感覺和 CSP 有太大差別,現在看 Actor 抽象程度更高。
我發現 Actor 的最大優勢就是在於使用消息的交互方式。這種交互方式可以對用戶屏蔽更多的信息。調用傳統庫我們需要關心代碼是否線程安全,而 Actor 的消息介面則對用戶屏蔽了這一點,我們只需對 Actor 發送消息,等待回復,而具體代碼由 Actor 執行,自然調用者不需要考慮並發、多線程安全等等問題,細節部分對調用者完全屏蔽。
我在實現 Server 相關邏輯時,用 200 行 ruby 實現的精簡 Actor 模型 github
ethruby 項目地址 ruby-ethereum/ethruby
本作品採用知識共享署名-相同方式共享 4.0 國際許可協議進行許可。 如果對文章感興趣,歡迎訂閱我的博客: 知乎專欄? RSS? 郵件訂閱?
推薦閱讀: