主页 > imtoken testflight下载 > 以太坊源码分析(四节点发现)
以太坊源码分析(四节点发现)
ethereum - 构建不可阻挡的应用程序
节点发现
以太坊的节点发现协议使用KAD算法(kademlia)
数据存储结构
它在一个数组中维护了256个桶,每个桶的数据下标就是它的深度。 每个bucket最多可以存储16个节点,所以一个节点可以存储的节点数是256 * 16个节点
这是在 NodeTable 中定义的
图片.png
距离算法
每个节点都有一个nodeId,它是一个512位的公钥,由节点的地址通过哈希算法导出并使用ECC加密
final ECKey generatedNodeKey = ECKey.fromPrivate(sha3(addressOrEnode.getBytes()));
public byte[] getNodeId() {
if (nodeId == null) {
nodeId = pubBytesWithoutFormat(this.pub);
}
return nodeId;
}
两个节点之间的距离是通过两个nodeId异或后取最高位1的位置得到的。 例如:
如果节点A的nodeId为1011011(二进制表示),节点B的nodeId为1100110以太坊全球节点数量,则两者之间的距离为6以太坊全球节点数量,距离越小,存储的桶越浅,即越近,节点将选择最近的16个节点发起节点查询请求
消息类型节点发现实现
首先是节点发现协议使用的Udp,入口是UDPListener,这个类在初始化的时候会读取初始节点发现配置文件配置的IP列表(peer.discovery.ip.list),然后启动它通过启动方法 3 个任务:
节点服务器监控任务
使用netty绑定默认端口30303,消息的处理器是messageHandler。 当接收到消息时,会使用NodeManager的handleInbound方法来处理上面提到的各种消息类型。
while (!shutdown) {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.handler(new ChannelInitializer() {
@Override
public void initChannel(NioDatagramChannel ch)
throws Exception {
ch.pipeline().addLast(stats.udp);
ch.pipeline().addLast(new PacketDecoder());
MessageHandler messageHandler = new MessageHandler(ch, nodeManager);
nodeManager.setMessageSender(messageHandler);
ch.pipeline().addLast(messageHandler);
}
});
channel = b.bind(address, port).sync().channel();
channel.closeFuture().sync();
...省略
}
节点发现任务每30秒向相邻节点发送一次findnode消息
discoverer.scheduleWithFixedDelay(
new DiscoverTask(nodeManager),
1, KademliaOptions.DISCOVER_CYCLE, TimeUnit.SECONDS);
刷新任务每7200毫秒刷新一次相邻节点列表,实际发送一个findnode消息
refresher.scheduleWithFixedDelay(
new RefreshTask(nodeManager),
1, KademliaOptions.BUCKET_REFRESH, TimeUnit.MILLISECONDS);