节点发现协议

作者: Jisen | 来源:发表于2018-06-04 19:13 被阅读0次

    简而言之:

    • 旨在发现要连接的PLPx节点
    • 基于UDP的RPC协议(类似kademila
    • 定义4种数据包类型:ping,pong,findnodeneighbours

    原文:Node Discovery Protocol v4

    本文档定义了节点发现协议版本4,这是一个类似KademliaDHT,用于存储有关以太坊节点的信息。选择Kademlia结构是因为它产生了低直径的拓扑结构。

    节点标识

    每个节点都有一个加密标识,这是椭圆曲线secp256k1上的一个key。节点的公钥作为其标识符或node ID
    两个节点ID之前的“距离”是按位排他的或公钥的散列值,即数字。

    distance(n₁, n₂) = keccak256(n₁) XOR keccak256(n₂)
    

    节点表

    发现协议中的节点保留有关其附近的其他节点的信息。相邻节点存储在由'k-bucket'组成的路由表中。对于0 ≤ i < 256的每一个节点,都保留一个k-bucket,表示2i2i+1节点之间的距离。

    节点发现协议使用k = 16,即每个k-bucket包含多达16个节点条目。这些条目按最近一次看到的时间排序 - 最近最少看到的节点在头部,最近最多看到的节点在尾部。

    每遇到一个新节点N₁,它就可以插入到相应的bucket中。如果bucket中包含少于k条目N₁可以简单地添加为第一个条目。如果bucket已经包含k条目,则bucket中最近最少可见的节点N₂需要通过发送ping数据包来重新生效。如果没有收到来自N₂的应答,则认为该节点N₂不生效了,并将N₁加到bucket的前面。

    端点证明

    为防止流量放大攻击,实现必须验证查询的发送方是否参与了发现协议。如果数据包的发送者在过去12小时内发送了匹配ping哈希的有效pong响应,则认为该数据包的发送者已被验证。

    递归查找

    “查找”定位与节点ID最近的k个节点。

    查找发起者首先选择α最接近它所知道的目标的节点。然后发起者将并发FindNode数据包发送到这些节点。α是系统范围的并发参数,例如3.在递归步骤中,发起方将FindNode重新发送到它从前面的查找中了解到的节点。“k”节点的发起者监听到最近的目标节点,它选择α尚未查找的节点并向其重新发送FindNode。无法快速响应的节点将被排除在考虑之内,除非它们确实响应了。

    如果一轮FindNode查询无法返回比最近看到的”最近节点“更近的节点,则发起方将find node重新发送到k尚未查询过的所有最近的节点。当发起者查找并从k最近的节点获得响应时,查找终止。

    Wire协议

    节点发现消息作为UDP数据报发送。任何数据包的最大大小是1280字节。

    packet = packet-header || packet-data
    

    每个数据包都以一个标题开头:

    packet-header = hash || signature || packet-type
    hash = keccak256(signature || packet-type || packet-data)
    signature = sign(packet-type || packet-data)
    

    当在同一个UDP端口上运行多个协议时,hash的存在使包的格式变得可识别。它没有别的用处。

    每个数据包都由节点的身份密钥签名。signature被编码为长度为65的字节数组,作为签名值rs和“恢复id”v的连接。

    packet-type是定义消息类型的单个字节。下面列出了有效的数据包类型。报头后的数据特定于数据包类型,并被编码为RLP列表。按照EIP-8,实现应该忽略列表中的任何其他元素以及列表之后的任何额外数据。

    Ping数据包(0x01)

    packet-data = [version, from, to, expiration]
    version = 4
    from = [sender-ip, sender-udp-port, sender-tcp-port]
    to = [recipient-ip, recipient-udp-port, 0]
    

    expiration字段是绝对的UNIX时间戳。包含过去时间戳的数据包过期可能无法处理。

    当收到ping包时,收件人应该用pong包回复。它也可以考虑将发送者添加到节点表中。

    如果在过去的12小时内没有与发件人进行任何沟通,除了pong之外,还应发送一个ping来获得端点证明。

    Pong数据包 (0x02)

    packet-data = [to, ping-hash, expiration]
    

    Pong是对ping的回复。

    ping-hash应该等于相应ping数据包的hash。实现应该忽略不包含最近ping数据包hash的未经请求的pong数据包。

    FindNode数据包 (0x03)

    packet-data = [target, expiration]
    

    FindNode数据包请求关于靠近target节点的信息。这target是一个65字节的secp256k1公钥。当接收到FindNode时,收件人应回复包含最近的16个节点的neighbors数据包,该节点在其本地表中找到。

    为防止流量放大攻击,只有在端点证明过程验证了FindNode的发送方时才应发送neighbors回复。

    Neighbors数据包 (0x04)

    packet-data = [nodes, expiration]
    nodes = [[ip, udp-port, tcp-port, node-id], ... ]
    

    Neighbors是对FindNode的回复。

    已知问题和实现建议

    expiration存在于所有数据包中的字段应该防止数据包重放。由于它是绝对时间戳,因此节点的时钟必须准确无误才能正确验证。自从协议于2016年发布以来,我们收到了无数关于用户时钟错误连接问题的报告。

    端点证明是不准确的,因为FindNode的发件人无法确定收件人是否看到最近的pong。Geth如下处理它:如果在最后12小时内没有与收件人通信,请发送ping命令启动该过程。等待来自另一端的ping,回复并发送FindNode。

    相关文章

      网友评论

        本文标题:节点发现协议

        本文链接:https://www.haomeiwen.com/subject/aigysftx.html