主页 > imtoken testflight下载 > 以太坊源码分析(四节点发现)

以太坊源码分析(四节点发现)

imtoken testflight下载 2023-06-18 05:30:49

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);