文章 关于我 RSS 订阅 邮件订阅 Email

06 May 2018
实现以太坊第一周 DevP2P::RLPX 握手协议

前因

《实现以太坊》是一个系列笔记。主要记叙我从头实现一个以太坊的过程,形式是每周或每两周的流水账总结,内容包括:这段时间我实现了哪些东西,这些东西是干嘛的,以太坊为什么要设计这些东西。 因为是流水账的形式,预计到之后也极有可能出现『本周打牌,什么都没写』的情况。

那么为什么又要实现个以太坊呢?难道 geth, parity, ethereumj, pyethereum, elixir-ethereum(WIP), ruby-ethereum 还不够用么?

主要考虑三个原因:

  1. Double 工资。偶尔听到老板说谁可以从头实现个以太坊,就给 double 工资。为了考验自己对公司和老板的信任,决定试一试

  2. 学习。纸上谈来终觉浅,自己实现一遍领悟到的设计和从书上看来是永远不一样的。实现一遍才可以拥有对以太坊设计的发言权。

  3. 弥补生态。上述的客户端中其实 pyethereum, ruby-ethereum 已经年久失修, elixir-ethereum 还在开发,实际能用的客户端不多。有人在尝试用 python 做另外一个 ethereum 的实现(trinity)。因为比较熟悉 ruby 生态,我决定用 ruby 实现。

因此我决定从头来实现一个 ethereum 客户端,代码放在 ruby-ethereum/ethruby,项目暂定名 ethruby (组织头像是 GitHub 自动生成的,非常有意思的图案)。

第一周 DevP2P::RLPX

第一周,我决定从 DevP2P 组件开始,DevP2P::RLPX 是以太坊的底层网络协议套件,包括 P2P 加密通信,节点发现等功能。实现了 DevP2P,ethruby 就拥有和其他节点通信的能力,再去实现上层的协议可以直接在真实环境中测试,如鱼得水。

DevP2P::RLPX 包含通信协议和节点发现协议,还有运行这两个协议的 Server 逻辑。本周我只实现了加密通信部分。

当以太坊节点启动时,会同时监听 TCP 和 UDP 的端口(通常是用同一个端口),UDP 用来处理节点发现协议,TCP 用来接收 P2P 通信。

想要连接到以太坊的节点开始通信,需要如下信息 node_id,ip, tcp port。要注意 node_id 同时也是节点的公钥地址,之后协议握手时会用到。

下面是个 enode 地址,包含了 node_id, ip, tcp port

enode://d1f109478397b1ffd3c1b2a094c57b957d6c5356e359d2ad7e75c97448f9e4b0d[email protected]127.0.0.1:33333

每个节点拥有自己的公钥私钥对(node_id 就是公钥)。进行 P2P 通信时,接收方和发送方会各自再生成一个临时的公钥、私钥对。

迪菲-赫尔曼(ECDH)算法是个重要加密学技术,可以用私钥和对方公钥计算出一个共享的密钥,比如有 A、B 两个公私钥对,ECDH(A私钥, B公钥) == ECDH(B私钥, A公钥)。是交换密钥的重点原理。

  1. 通信的第一个阶段,发起者发起 tcp 请求。用接受者的公钥(node_id)加密,发送自己的公钥和包含临时公钥的签名,还有一个随机生成的 nonce。

  2. 接受者收到信息,获得发起者的公钥,同时利用 ECDH 算法从签名中最终获取发起者的临时公钥(留到第 4 步使用)。接受者把自己的临时公钥和随机 nonce 用发起者的公钥加密并发送。

  3. 发起者获取到接受者的临时公钥和 nonce,利用 ECDH 算法从自己的临时私钥和对方的临时公钥计算出共享密钥,共享密钥用来加密之后的通信过程,nonce 用来验证之后对方发来的信息。

  4. 接受者进行同样的计算,用自己的临时密钥和发起者的临时公钥获取共享密钥。

第一阶段的密钥交换完成,现在发起者接受者拥有同一个共享密钥,和对方的 nonce。共享密钥会用来加密以后的通信内容(对称加密比非对称加密效率更高),nonce 会用来生成 mac(消息认证码),保证收到的信息完整。

进行完密钥交换后,以后的通信都要使用 Frame 格式,Frame 包含 head 和 body, 很类似 TCP 包的格式。这里不再深入具体格式,可以从文档看。

第二阶段握手称为协议握手,发起节点发送自己支持的协议、节点名称、节点版本,接受者会进行判断,如果协议版本不符合则断开。

至此,RLPX 的协议握手完成,之后的操作是在 RLPX 之上实现的以太坊子协议。

DevP2P RLPX 是个很灵活的协议,不仅是用于 Ethereum,而是为 P2P 通信而建设。

这篇大概描述了 RLPX 的握手过程,关于 RLP 编码(以太坊用的二进制编码),加密原理,节点发现等等都没有涉及。我会在之后的文章加入这部分内容,如果对文章感兴趣,欢迎订阅我的博客(推荐 Feedly, 也可以点上方链接通过邮箱订阅)。


知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
如果对文章感兴趣,欢迎订阅我的博客:
知乎专栏RSS邮件订阅

Til next time,
JJY 2018.05.06

文章 关于我 RSS 订阅 邮件订阅 Email