實現以太坊第二周 RLPX 子協議, Actor model

實現以太坊第二周 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? 郵件訂閱?


推薦閱讀:

為什麼我覺得 Actor 很難用?

TAG:P2P | 以太坊 | actor模型 |