之前看了下比特币P2P通讯的代码,记录一下
大家都知道比特币是去中心化的,那么节点与节点之间是如何通讯的呢,新节点怎么加入到节点网络呢,读完本文就知道大概流程了;如有不对的地方欢迎留言讨论
比特币线程
比特币代码启动之后会开启五个线程用于P2P通讯
ThreadDNSAddressSeed
从配置好的DNS服务器获取节点的ip地址添加到addrman;这就解决了新节点怎么加入到网络
ThreadOpenAddedConnections
处理rpc客户端添加的节点信息,然后连接到节点
ThreadOpenConnections
根据addrman中的ip连接到对应节点,创建节点CNode(连接别人fInbound为false,被连接为true)。默认最多连接到8个节点。默认连接总数不大于125个,包括被连接的节点数
ThreadSocketHandler
收发各个节点相关的socket数据。监听到有其他节点连接创建CNode(fInbound为true)
ThreadMessageHandler
处理其他CNode发来的消息与发送消息到其他CNode
节点通讯
全部在线程ThreadMessageHandler中处理消息,每个节点自身遍历连接的所有节点CNode,ProcessMessage处理收到的消息,SendMessages发送消息到其他节点
消息交互
以新加入网络的NodeA和运行全节点的NodeB为例
NodeA connect NodeB的IP地址(比如通过DNS Seed获取到Node B的IP地址),创建CNode B,fInbound为false,同时发送’version’消息,包含自身的版本信息、block高度等信息
NodeB监听到NodeA连接,创建CNode A,fInbound为true
NodeB收到’version’消息后,回复一个’version’消息,同时发送’verack’消息
NodeA收到NodeB发送的’version’消息后,发送’verack’消息。同时发送’getaddr’消息获取NodeB连接的更多节点信息(只有fInbound为false才发送此消息)
NodeA/B收到对方的’verack’消息后,对方的版本号大于等于70012发送’sendheaders’信息,版本号大于等于70014发送’sendcmpct’消息(关于cmpct,即compact block,请参看后续介绍)
NodeB收到’getaddr’消息,发送自己的addrman保存的节点IP信息,最多发送1000个,带在’addr’消息中
NodeA收到’addr’消息后,添加到自己的addrman,然后在ThreadOpenConnections继续连接其他节点直到达到8个的限制
NodeA/B收到对方的’sendheaders’消息,设置fPreferHeaders为true,SendMessages中继续处理。从自己的vBlockHashesToAnnounce中查找到对方blockindex的位置开始发送,附带在’headers’消息中(对于不支持此消息的版本会发送’inv’消息,每次最多发送50000个。区别是inv消息中带的是Block Header的hash,header中带的Block Header)
NodeA/B收到对方的’sendcmpct’消息,设置fProvidesHeaderAndIDs、fWantsCmpctWitness、fSupportsDesiredCmpctVersion等变量后续使用
NodeA收到’headers’消息后,如果自己没有这些header,新建blockindex到mapBlockIndex(保存着全部的block header等信息),然后发送’getdata’消息获取block内容。如果不支持headers信息,会收到’inv’消息,然后发送’getheaders’消息带hash start和stop参数让对方发送hash范围的headers,对方节点NodeB收到’getheaders’消息发送’headers’信息就跟此条开始一样的处理了
NodeB收到’getdata’消息,如果type是block,就发送’block’消息带block内容;如果type是filter block(SPV节点),就发送’merkleblock’带merkle节点信息;如果是cmpct block就发送’cmpctblock’消息带CBlockHeaderAndShortTxIDs信息
NodeA收到’blcok’消息写把block内容写入磁盘,然后更新bestchain(参看后续介绍);如果收到’cmpctblock’(关于compact block请参看后续介绍)消息,会发送’getblocktxn’消息获取更多的tx记录
NodeB收到’getblocktxn’消息,发送’blocktxn’消息带tx记录
NodeA收到’blocktxn’消息,组织成完整的block写入磁盘等