[TOC]
0x0 概述
比特币节点发现,指节点寻找其他节点的地址(IP和PORT)的方法。主要有以下几种:
- 节点发现本节点的外部IP
- 节点接收远程连接节点的回调地址
- 节点使用DNS服务发现地址
- 节点使用软件本身硬编码的地址列表
- 节点与其他节点交换地址列表
- 节点把地址列表存储到数据库,在启动时从数据库中读取
- 节点在启动时从配置文件中读取地址列表
为每个地址保留时间戳,以跟踪节点地址上次被查看的时间。当从节点收到消息(message)时,该时间戳被更新。时间戳仅在地址上更新,并且在时间戳超过20分钟时保存到数据库。
0x1 getaddr消息
当一个节点收到一个“getaddr”请求时,它首先计算出它在最近3个小时内有多少个地址有时间戳。如果地址数量超过2500个,它随机选择2500个最新的地址。
0x01 发现方法
本地节点的外网地址
本地节点发现自己的外网地址需要使用到公共服务。比特币网络(中本聪版本)中的过程如下:
- 节点尝试连接
91.198.22.70:80 #checkip.dyndns.org
- 若上述操作失败,尝试连接
74.208.43.192:80
- 如果连接成功,则发送HTTP请求,解决http response数据,获取IP地址。该地址作为该节点的外部地址广播给周边的其他节点
IRC地址
不再支持
DNS地址
节点在启动时,发布dns解析请求,请求种子节点的地址。截至到2017年,种子节点的域名列表如下:
- seed.bitcoin.sipa.be
- dnsseed.bluematt.me
- dnsseed.bitcoin.dashjr.org
- seed.bitcoinstats.com
- seed.bitcoin.jonasschnelli.ch
- seed.btc.petertodd.org
硬编码种子地址
这些地址仅用作最后的手段。
地址广播(addr消息)
节点在发送“getaddr”请求之后可以在“addr”消息中接收地址,或者“addr”消息可能未经请求而到达,因为节点在中继地址时会无条件地通告地址(见下文) 或建立连接时。
如果地址来自真正的旧版本,则会被忽略; 如果来自不太旧的版本,如果我们已经有1000个地址,它将被忽略。
如果发件人发送超过1000个地址,则全部被忽略。
从“addr”消息收到的地址有一个时间戳,但时间戳不一定是可信的。
对于消息中的每个地址:
如果时间戳太低或太高,则设置为5天前。
我们从时间戳中减去2小时并添加地址。
如果地址在过去24小时内出现过,而时间戳现在已超过60分钟,那么它会更新到60分钟前。
如果在过去24小时内没有看到地址,并且时间戳目前已超过24小时,则会更新到24小时前。
地址中继
一旦地址从“addr”消息中被添加(见上文),则它们可以被中继到其他节点。 首先,必须设定以下标准[9]:
- 处理后的地址时间戳在当前时间的60分钟内
- “addr”消息包含10个地址或更少
- 并且fGetAddr未在节点上设置。 当我们从节点请求地址时,fGetAddr开始为false,设置为true,当我们从一个节点接收少于1000个地址时,它被清除。
- 地址必须可路由
对于符合上述条件的每个地址,节点都会对地址,当天(以整数形式)和随机256位值(在客户端启动时生成)进行hash。 该节点获取散列值最低的两个地址,并向它们中继“addr”消息。 这确保了每个节点只在任何给定时间将“addr”消息中继给另外两个客户端,另外两个客户端是随机选择的,并且随机选择至少每24小时开始一次。
自广播
每24小时,节点将自己的地址通告给所有连接的节点。
它还会清除我们认为远程节点具有的地址列表,这将触发发送到节点的刷新。
地址入库
地址入库操作大概每0.1秒调用执行一次。
文本文件提供的地址
客户端将自动读取比特币数据目录中名为“addr.txt”的文件,并将其中找到的任何地址添加为节点地址。 这些节点没有特别优先于其他地址。 他们只是添加到地址池中。
从文本文件加载的地址最初被赋予零时间戳,因此它们不会响应“getaddr”请求而被公布。