Bitcoin Core P2P网络层
原文链接:http://www.lotushy.com/?p=115
数据结构
在任意给定时刻,一个节点总是连接到多个其他节点。默认情况下,一个节点连接到8个其他节点(链出),并允许多达125个链入节点连接进来。
相关常量定义在net.h文件中。
节点集合则由全局变量vNodes维护。
CNode用于表示一个节点。
CNode包含许多属性,其中大部分属性都与底层链路(如套接字,字节流等)有关。
CNode的关键属性如下:
nServices: 通常被称为“服务位”。这是一个bitmap数据结构,用于表示peer提供的服务种类。具体种类如下。
fClient: 表示节点是否是SPV节点
fWhiteListed: 是否是白名单节点。如果是的话,该节点不会因为
坏的行为被屏避掉。vSendMsg: 队列中待发送的消息队列
vRecvMsg: 我们从Peer接收到的消息队列
节点发现和节点连接
地址管理
地址管理器用于管理节点的IP地址和端口。(见addrman.h)
设计目标:
- 将地址表保存在内存中,并将整个表异步转储到peers.dat。
- 确保没有(本地化的)攻击者可以用它的节点/地址填充整个表格。
为此:
- 地址以Bucket的方式组织,即地址被放到桶里。
- 尚未尝试过的地址进入1024个“new”桶。
- 已知可访问的节点地址进入256个“tried”桶。
- 每个地址范围随机选择8个桶
- 根据完整地址从实际存储桶中选择实际存储桶。
- 当为一个完整的桶添加一个新的好地址时,一个随机选择的entry(偏向于最近尝试过的)会被弹出,回到“新”桶。
- 分组选择基于密码散列,使用随机生成的256位密钥,这不应该被攻击者观察到。
- 多个索引用于提升性能。
** 时间戳 **
地址管理器也要持续跟踪每个节点的最近活跃情况。时间戳仅在一个地址上更新,并且在时间戳超过20分钟时保存到数据库。 通过理解时间戳的作用,将更加清楚的理解为什么要保持时间戳。
节点发现
节点发现从链路层来讲,就是发现一个节点的IP地址和端口号。有多种方式:
- 地址数据库,即peers.dat文件
- 在节点启动时读入并加载到节点管理器中。该方法在节点首次运行时是不支持的。因为peers.dat文件还不存在。
- 用户指定(--addnode, --connect)
- DNS种子(DNS seeding)
- 仅当peers.dat文件为空时,DNS种子才会被使用。
- 默认DNS种子有6个:seed.bitcoin.sipa.be, dnsseed.bluematt.me, dnsseed.bitcoin.dashjr.org, seed.bitcoinstats.com, seed.bitcoin.jonasschnelli.ch, seed.btc.petertodd.org
- 硬编码的种子
- 如果DNS seeding失败,客户端使用硬编码的种子。[chainparamsseeds.h] 这些地址仅用作最后的手段。理想情况是尽快远离种子节点,以避免过载这些节点。DNS种子和硬编码的种子的时间戳均为0,这样可以避免此类地址被广播到网络中或响应
getaddr。
- 如果DNS seeding失败,客户端使用硬编码的种子。[chainparamsseeds.h] 这些地址仅用作最后的手段。理想情况是尽快远离种子节点,以避免过载这些节点。DNS种子和硬编码的种子的时间戳均为0,这样可以避免此类地址被广播到网络中或响应
- 从其他Peer获取(
getaddr和addr消息)- 节点间通过
getaddr和addr交换IP地址信息。 - 但是,“addr”消息也可能会不请自来,因为节点在以下情况时无偿地发布地址:
- 当节点转发地址时
- 周期性广播节点自己的地址(每24小时)
- 当连接建立时(响应
version消息时带回)
- 节点发送
getaddr消息的时机- 在响应
version消息,并且节点自身的地址量小于1000时。
- 在响应
- 当接收到
addr时:- 发送消息的节点版本太老,并且我们已经有1000个节点地址了,该消息被忽略。
- 如果节点是当前版本,并且尝试向我们发送超过1000个节点地址,则该节点会被惩罚。
- 如果该地址24小时内已经发现,并且当前时间戳超过60分种,则时间戳更新为60分种。
- 如果该地址24小时内没有出现过,而时间戳是24小时之前,则更新为24小时。
- 当响应
getaddr消息时:- 该节点计算出在过去3个小时内有多少个地址有时间戳。
- 它发送这些地址,但如果有超过2500个地址,它随机选择2500。
- 它清除我们认为远程节点所拥有的地址列表,这将触发发送到节点的刷新。 请参阅SendMessages。
- 地址中继:
- 一旦新地址被添加
- 地址的时间戳在10分钟之内
addr消息包括10个地址或少一些- fGetAddr==false
- 该地址是可路由的
- 满足以上条件,则新地址会被随机的发送出去
- 一旦新地址被添加
- 节点间通过
节点连接
节点链接由线程ThreadOpenConnections管理。它负责选择可用的地址,建立链接并在适当的时候释放链接。
而inbound链接则由ThreadSocketHandler负责处理[ThreadMessageHandler]。
对于inbound链接,系统通过select执行IO操作。所以,其支持的inbound数量不会太多,目前,是125个。
插口(Sockets)和消息
Socket线程 (net.cpp)
消息线程
ProcessMessages (net_processing.cpp)
ProcessMessages是net_processing.cpp中的处理和验证交易和区块等相关代码代码的入口点,同时它也处理getaddr, addr等比特币协议相关的消息。该方法主要完成消息的复制并调用ProcessMessage处理消息。
ProcessMessage基本上是一个大型的“开关”,它根据消息类型[NetMsgType]来采取行动。
消息类型列表如下[protocol.cpp]:
namespace NetMsgType {
const char *VERSION="version";
const char *VERACK="verack";
const char *ADDR="addr";
const char *INV="inv";
const char *GETDATA="getdata";
const char *MERKLEBLOCK="merkleblock";
const char *GETBLOCKS="getblocks";
const char *GETHEADERS="getheaders";
const char *TX="tx";
const char *HEADERS="headers";
const char *BLOCK="block";
const char *GETADDR="getaddr";
const char *MEMPOOL="mempool";
const char *PING="ping";
const char *PONG="pong";
const char *NOTFOUND="notfound";
const char *FILTERLOAD="filterload";
const char *FILTERADD="filteradd";
const char *FILTERCLEAR="filterclear";
const char *REJECT="reject";
const char *SENDHEADERS="sendheaders";
const char *FEEFILTER="feefilter";
const char *SENDCMPCT="sendcmpct";
const char *CMPCTBLOCK="cmpctblock";
const char *GETBLOCKTXN="getblocktxn";
const char *BLOCKTXN="blocktxn";
}
SendMessages (main.cpp)
SendMessages创建消息并在peer的vSendMsg队列(双端队列或C ++中的“deque”)中对其进行排队。vSendMsg对象基本上只是序列化的数据。
Locks
P2P层主要的锁有:
- cs_vNodes: 控制对CNode对象的访问
- cs_vSend: 控制对节点的发送缓存的访问
- cs_vRecvMsg: 控制对节点的接收缓存的访问
- cs_inventory
拒绝服务的防范措施
一旦发现异常行为的节点,则直接ban掉。
DoS预防框架在2011年引入。
具体见:https://github.com/bitcoin/bitcoin/pull/517
** 被禁节点 **
被禁节点存储在setBanned中。setBanned是map类型的数据结构,定义为typedef std::map<CSubNet, CBanEntry> banmap_t。
默认情况下,一个节点被禁止24小时,但可以使用-bantime选项进行配置。
Bitcoin Core P2P网络层的更多相关文章
- Bitcoin Core钱包客户端的区块数据搬家指南
最近在饭团(微信中的一个服务号)里教一些朋友学习比特币和区块链技术,为了让大家深刻地理解去中心化网络和钱包等概念,我推荐大家一定要安装经典的Bitcoin Core钱包软件,有些朋友在安装的时候没有留 ...
- 从源码开始运行Bitcoin Core
安装Ubuntu 环境:虚拟机 网络连接:桥接 系统版本:16.04 源:ali 安装编译环境(依赖库) sudo apt-get update sudo apt-get install build- ...
- Win10环境配置Bitcoin Core节点
区块链是当下比较火热的技术,我也来蹭下热度,研究一把Bitcoin Core的技术. 入门篇 一.Bitcoin Core安装 1.下载 一般有2种安装方式:源码编译安装 和 下载现成的安装包安装 源 ...
- 五大主流数字币钱包:imToken数字货币钱包,Bitcoin core钱包,BTS网页版钱包,AToken轻钱包,Blockchain
AToken数字货币钱包 超容易上手支持五大主流币种 互联网 | 编辑: 王静涛 2017-12-28 09:58:33转载 国家监管部门已叫停数字货币交易,包括火币网.比特币中国.OKC ...
- windows 安装Bitcoin Core使用
1.官网下载https://bitcoin.org/en/download 选择Windows 其他系统就选择对应的就好 2.双击安装完过后,进入bin目录,打开bitcoin-qt.exe运行,提 ...
- BitCoin p2p通信过程
众所周知,Bitcoin是建立在p2p网络上的,但是具体的通信过程一直没有搞懂,所以特意去bitcoin的Developer Guid上去了解了一下.由于本人英文水平有限,理解难免有偏差的地方,希望大 ...
- 关于Bitcoin的分叉之路
今年对与bitcoin来讲是不平凡的一年,它经历了价格的暴涨.腰斩和再次暴涨,对于这些现象背后的利益博弈网上分析的文章很多,我就不再赘述了.我们从技术的角度上分析一下bitcoin的发展历程,同时预测 ...
- P2P综述
原文参见:http://www.lotushy.com/?p=113 [TOC] 什么是P2P P2P全称是Peer-to-peer.P2P计算或P2P网络是一种分布式应用架构.它将任务或负载分发给P ...
- 详解区块链P2P网络
根据前一篇文章<从微观到宏观理解区块链>我们已经了解到,微观上,区块链本质就是一种不可篡改且可追踪溯源的哈希链条:宏观上,还具备了另外三个基本特征:分布式存储.P2P 网络和共识机制.分布 ...
随机推荐
- virtualbox+vagrant学习-2(command cli)-27-vagrant connect命令
Connect 命令: vagrant connect NAME connect命令通过启用对共享环境的访问来补充share命令.你可以在“vagrant share”部分了解有关vagrant sh ...
- 二进制包 vs. 源代码包
在ROS中, 我们可能经常会遇到缺少相关的ROS依赖的问题. 有些时候你编译或者运行一些ROS程序, 系统会提示找不到XXX功能包. 如果是缺少ROS的依赖, 通常可以用以下命令来安装: $ sudo ...
- vbs获取当前主机IP
Function GetIP GetIP = "" Dim objWMIService, colAdapters, objAdapter strComputer ...
- WARNING OGG-01519
2019-02-14 05:13:09 WARNING OGG-01519 Waiting at EOF on input trail file /home/u01/app/ogg/dirdat/ ...
- 修改通达oa数据库root密码
第一步: 打开通达oamysql远程网页地址:如http://127.0.0.1/mysql,点击修改密码功能按钮,根据提示修改,不要生成加密密码,执行即可! 第二步:修改service.php文件的 ...
- Mysql 5.7 windows安装 zip安装
最近想安装一个本地数据库, 发现网上写的没一个能安装成功的, 各种蛋疼, 我还是自己写一个吧 参考链接: https://www.cnblogs.com/by330326/p/5608290.html ...
- 微信公众号开发被动回复用户消息,回复内容Content使用了"\n"换行符还是没有换行
使用语言和框架:本人后端开发使用的Python的DRF(Django REST framework)框架 需求:在微信公众号开发时,需要实现自动回复,即被关注回复.收到消息回复.关键词回复 发现问题: ...
- Scala-构造函数
/*scala的构造函数分为主构造函数和辅助构造函数. 一.主构造函数在Scala中,每个类都有主构造函数,和类的定义交织在一起.一个Scala类的主构造函数包括:1.构造函数的参数:2.类体中调用的 ...
- [shell]关闭超时的进程
应同事要求,写了个shell, 主要功能为查找超时的进程,并关闭! 调用方式: shell_sheep : 为进程名 30 : 为30分钟 从打印的日志能看出会多两个PID,不要惊慌,由于你执行时会 ...
- Lua 语言学习
详细讲解见菜鸟教程 Lua. 一.数据类型 -- 直接输出 print("hello") -- 全局变量 b = print(b) -- nil(空) print(type(a)) ...