以太坊中的Kademlia协议
在阅读此文前,请先了解Kademlia协议的内容。
以太坊的P2P网络使用了Kademlia协议,以太坊在使用Kademlia时,对协议中某些参数是一定要确定下来的,经过源码的阅读分析,大致搞懂了以太坊中的Kademlia协议是怎么运作的,现记录下来。
Ethereum中的节点距离
注意,这里我们讲的“距离”并非地理空间上的距离。
在之前的文章《以太坊的NodeID》中,我们指出以太坊使用了NodeID作为一个节点的标识,计算这个NodeID的SHA-256哈希,可以得到一个长度为32字节(256位)的哈希值,本文将其称为GUID(Globally unique identifier),两个节点的距离就是通过对两个节点的GUID进行异或(XOR)得出的。
两个节点的GUID进行异或计算后,会得到一个256位的二进制字符串,本文称其为距离字符串。距离字符串最左侧会有n个连续的0,那么两个节点的距离就是256-n。
例如
- a XOR b = 000000111110111011.....,最左侧有6个连续的0,所以a和b距离为250;
- a XOR b = 100011111110111011.....,最左侧有0个连续的0,所以a和b距离为256;
- a XOR b = 110000111110111011.....,最左侧有0个连续的0,所以a和b距离为256;
- a XOR b = 001000111110111011.....,最左侧有2个连续的0,所以a和b距离为254;
Ethereum中K桶相关的参数设置
下图是以太坊对Kademlia协议的参数配置,重点关注图上圈出的参数:
geth一共使用了17个K桶,每个桶可以容纳16个对等节点。
因为两个节点的GUID都是其NodeID的哈希值,而距离字符串最左侧有n个连续的0意味着两节点的GUID的前n位相同,哈希值前n位相同的概率随着n的增大而变小。以太坊认为,前17位或者更多位相同的哈希值很稀少(甚至没有),并且为了防止日蚀攻击,以太坊设置了17个桶(从1.8.0版本开始)[1,2],第1个桶存放距离<=239的节点和距离为240的节点,第2个桶存放距离为241的节点,第3个桶存放距离为242的节点,.......,第17个桶存放了距离为256的节点。
每个桶可以放16个对等节点的信息。
Ethereum中K桶节点的限制
可以看到,以太坊限制了K桶所存储的节点的IP地址。
一个K桶中,至多有2个节点来自同一个/24网段。
比如网段192.168.0.*就是一个/24网段,当192.168.0.2和192.168.0.3都在第i个桶时,192.168.0.4便不能再加入第i个桶。
一个table中,至多有10个节点来自同一个/24网段。这里的table就是节点表格,里面有所有的17个桶。当192.168.0.2-192.168.0.11都已经和我们的节点连接后,192.168.0.12便不能再与我们的节点连接。
Ethereum中K桶节点的刷新与存储
以太坊P2P网络启动后,会启动协程loop循环:
- 每隔30分钟自动刷新一次K桶
- 每隔最大10秒钟验证每个K桶中的距离上次验证时间间隔最长的节点是否可以ping通
- 每30秒将K桶中存在超过5分钟的节点存储本地数据库,视作稳定节点
- 本地数据库中最多存储30个稳定节点
- 数据库中的稳定节点如果已经5天未被验证,则会被丢弃
参考
- Henningsen S, Teunis D, Florian M, et al. Eclipsing ethereum peers with false friends[J]. arXiv preprint arXiv:1908.10141, 2019.
- Marcus Y, Heilman E, Goldberg S. Low-resource eclipse attacks on ethereum's peer-to-peer network[J]. Cryptology ePrint Archive, 2018.