《迅雷链精品课》第九课:区块链 P2P 网络
作者:互联网
上一节课我们学习了迅雷链的多链结构,今天我们将学习区块链P2P网络,通过这节课我们将了解迅雷链的P2P网络是怎样组成的,同时学习比特币和以太坊的P2P网络相关内容。
在学习课程的时候,你也可以领取BaaS平台为期一个月的试用机会,免费使用高性能区块链服务(点击链接即可免费领取https://blockchain.xunlei.com/baas/try.html)。课程学习结合实践操作,让你迅速成为区块链大牛!
第九课 区块链P2P网络
目前区块链技术的模型主要是由自下而上的数据层、网络层、共识层、激励层、合约层和应用层组成,网络层主要包括P2P组网机制、数据传播和数据验证机制等。迅雷作为一家以P2P下载起家的企业,将迅雷P2P协议应用到迅雷链,可以说让迅雷链具有得天独厚的优势。下面主要介绍迅雷链的P2P网络是怎样组成的,同时介绍比特币和以太坊的P2P网络。
P2P 网络模型
P2P 网络不同于传统的客户端/服务端(client/server)结构,P2P 网络中的每个节点都可以既是客户端也可以是服务端,因此也不适合使用 HTTP 协议进行节点之间的通信,一般都是直接使用 Socket 进行网络编程,协议使用TCP或者UDP协议。
P2P 主要存在四种不同的网络模型,也代表着 P2P 技术的四个发展阶段:集中式、纯分布式、混合式和结构化模型:
(1) 集中式:即存在一个中心节点保存了其他所有节点的索引信息,索引信息一般包括节点 IP 地址、端口、节点资源等。集中式路由的优点就是结构简单、实现容易。但缺点也很明显,由于中心节点需要存储所有节点的路由信息,当节点规模扩展时,就很容易出现性能瓶颈,而且也存在单点故障问题。
图1:集中式模型
(2) 纯分布式:移除了中心节点,在P2P节点之间建立随机网络,就是在一个新加入节点和 P2P 网络中的某个节点间随机建立连接通道,从而形成一个随机拓扑结构。新节点加入该网络的实现方法也有很多种,最简单的就是随机选择一个已经存在的节点并建立邻居关系。新节点与邻居节点建立连接后,还需要进行全网广播,让整个网络知道该节点的存在。全网广播的方式就是,该节点首先向邻居节点广播,邻居节点收到广播消息后,再继续向自己的邻居节点广播,以此类推,从而广播到整个网络。这种广播方法也称为泛洪机制。纯分布式结构不存在集中式结构的单点性能瓶颈问题和单点故障问题,具有较好的可扩展性,但泛洪机制引入了新的问题,一是容易形成泛洪循环,比如节点 A 发出的消息经过节点 B 到 节点 C,节点 C 再广播到节点 A,这就形成了一个循环;另一个棘手问题则是响应消息风暴问题,如果节点 A 想请求的资源被很多节点所拥有,那么在很短时间内,会出现大量节点同时向节点 A 发送响应消息,这就可能会让节点 A 瞬间瘫痪。
图2:纯分布式模型
(3) 混合式:混合式其实就是混合了集中式和分布式结构,网络中存在多个超级节点组成分布式网络,而每个超级节点则有多个普通节点与它组成局部的集中式网络。一个新的普通节点加入,则先选择一个超级节点进行通信,该超级节点再推送其他超级节点列表给新加入节点,加入节点再根据列表中的超级节点状态决定选择哪个具体的超级节点作为父节点。这种结构的泛洪广播就只是发生在超级节点之间,就可以避免大规模泛洪存在的问题。
图3:混合式模型
(4)结构化 P2P 网络:它也是一种分布式网络结构,但与纯分布式结构不同。纯分布式网络就是一个随机网络,而结构化网络则将所有节点按照某种结构进行有序组织,比如形成一个环状网络或树状网络。而结构化网络的具体实现上,普遍都是基于 DHT(Distributed Hash Table,分布式哈希表) 算法思想。
比特币P2P
比特币网络是纯分布式的P2P网络,节点第一次启动的时候,程序并不知道全网任何活动节点的 IP 地址。为了发现这些 IP 地址,程序会请求一个或者多个 DNS 地址(也叫做 DNS 种子或者种子节点),这些 DNS 地址都是硬编码到 Bitcoin Core当中的,而且由比特币的社区维护者维护这些域名。比特币程序通过发送 version 消息到远程节点表示成功连接到一个节点,这个消息会包含本节点的版本信息、区块和当前的时间。远程节点会返回它自身的version 信息,然后两个节点都会发送 verack 信息给到对方来表示连接已被建立。连接一旦被建立,本节点会发送 getaddr 和 addr 消息到远程节点来收集比特币网络上更多的节点信息,并且与获取的这些节点继续建立P2P连接,默认情况下,一个节点会连接到8个其他节点(链出),并允许多达125个链入节点连接进来,并且对于成功连接的节点,会将这些节点信息(ip\port等)保存到本端DB。
上图为比特币的源码部分代码,其中seed.bitcoin.sipa.be、dnsseed.bluematt.me等为DNS种子节点地址。
以太坊P2P
以太坊网络是结构化P2P网络,以太坊的p2p网络主要由两部分构成:节点之间互相连接用于传输数据的TCP网络和节点之间互相广播用于节点发现的UDP网络。
(1) UDP网络:以太坊里的每个节点会维护一张路由表table,table是通过称为K桶的数据构造而成,K桶相当于是内存数据,记录了节点NodeId、distance、ip:port等信息。以太坊K桶按照与目标节点距离进行排序,共256个K桶,每个K桶包含16个节点。节点启动时,首先会生成一个随机ID,然后通过Kademlia 算法从K桶里已知的节点寻找离随机ID最近的16个节点信息(ip:port等)。对于初次启动的节点,由于K桶里面没有存有任何节点的信息,所以需要将硬编码的种子节点加入K桶,并且向种子节点通过Kademlia 算法寻找离随机ID最近的16个节点。寻找成功后,会将成功获取的节点保存到DB和K桶里,而且这些节点一定是可以ping通的(节点通过发送一个UDP ping包探测是否可以正常连接到目的端),这样节点下次重启后,会首先将DB里存有的历史节点添加到K桶里,最多添加30个历史节点信息存到K桶里,并且将种子节点也添加到K桶里,并且向K桶里的这些节点发送相关信息,目的是为了更新本节点的K桶数据,同时也让对端节点记录本端的节点信息。以太坊每个节点的K桶会每隔一个小时定时更新,对于udp通信失败次数过多的节点会及时从K桶和DB(database)删掉。
关于Kademlia 算法:
i. Kademlia使用了名为K桶的概念来储存其他(临近)节点的状态信息,对于160bit的节点ID, 就有160个K桶,对于每一个K桶i, 它会储存与自己距离在区间 [2^(i-1), 2^(i)) 范围内的节点的信息,每个K桶中储存有k个其他节点的信息,在以太坊实现中,k的取值为16,下表反映了每个K桶所储存的信息。
Kademlia算法要解决的是如何根据目标ID找到目标地址或者找到与该ID最接近的目标节点地址。在一个对等网络中,某个节点要查询其他节点的信息时,它可依赖的信息只有两个:1.目标节点ID 2.当前节点维护的路由表。其查询的核心思想是:逐步迭代,递进查找。其基本过程如下:
(1) 发起者首先计算自身(L)与目标节点(T)的距离,即cpl,查询本地维护的路由表,计算方法为Bucket = local.Buckets[cpl],这个Bucket中的节点与目标节点有着公共前缀。然后再从该Bucket中选择与目标节点T有最长cpl的节点,假设为X。
(2) 本地节点向X发起查询请求(FindNode),当X收到L发起的对目标节点T的查询请求时,会根据自身维护的路由表信息,返回距离T更近的节点供查询发起者L继续查询。当然,如果目标节点就是自身,那直接返回自身信息即可。需要说明的是:返回的响应消息里包含的节点并非是距离目标节点最近的那一个节点,而是一批节点。这样做有几点好处:1). 避免单个节点不可用导致的查询失败;2). 查询发起者可以根据响应结果进行并发查询,提升查询速度。
(3) 查询发起者L收到X的响应后,会继续向响应结果里的节点进行查询,而且会对响应中的结果进行过滤:如果该节点在之前已经被询问过,便不再加入待查询列表,从而保证查询的收敛性。
(4) 查询的最终结果是得到了一批距离目标节点最近的节点列表,然后从节点列表中选择出最接近目标的N个节点。
下图摘自原始论文,基本描述了查询流程。
(2)TCP网络:以太坊里的每个节点启动时会尝试通过UPNP或者NAT-PMP方法将本端内网地址和端口映射到外网地址和端口,并且通过TCP方式监听映射的外网地址和端口。以太坊里的每个节点会作为TCP客户端最多主动连接到13个节点,13个节点里有的是通过读取配置文件获取的静态节点(如种子节点),有的是通过K桶里随机选取的节点,以太坊保证本端节点和每个终端节点最多建立一个连接,如节点A作为客户端连到B后,B作为客户端时不会再建立一个到A的连接。TCP连接建立好后,本端节点会和对端节点协商获取一个公共对称密钥。密钥获取成功后会给对端发送一个握手请求,请求交换本端和对端的信息,信息主要包括本端id、协议版本等内容,通过匹配协议版本和收到的id信息来确认是否需要继续和对端保持TCP连接。以上操作完成后,后面本端发送数据给对端时都要通过之前获取的对称密钥加密,对端发送给本端的数据也需要用对称密钥解密数据。
迅雷链P2P
迅雷链网络也是结构化P2P网络,网络中由多个种子节点和验证人节点组成,种子节点和验证人节点共同负责记账和出块。种子节点主要由性能和存储空间较好的服务器组成,而且由迅雷和迅雷联盟链相关公司共同维护。迅雷链验证人节点是从全网所有的验证人设备里面挑选的网络最好、存储空间最大的节点。验证人节点和种子节点主要通过TCP协议建立连接,验证人与验证人之间的网络连接主要通过UPNP和P2P穿透协议来实现。对于UPNP映射成功的节点,连接方式为TCP连接,对于P2P穿透成功的节点,连接方式为UDP+TCP连接。目前P2P穿透连通率大概为96%,对于P2P穿透成功的UDP连接,迅雷基于UDP协议自己实现了一套可靠传输,而且网络传输包支持模糊协议。
迅雷链网络里面的每个记账节点也会记录一张路由表,对于节点第一次启动时,需要连接到硬编码的种子节点上,将本节点的相关信息传送给种子节点,而且从种子节点通过Kademlia 算法获取网络上其他验证人节点的信息。然后通过迅雷P2P协议尝试连接到这些节点,并且将成功连接的节点信息保存到本端路由表和DB里,对于心跳超时或者接收消息失败超过一定次数的节点会及时从路由表和DB里面删除。当节点下次重新启动时,会从DB里随机选择几个记账节点尝试建连,并且定时刷新本端的路由表。当节点成功连接到网络其他节点后,会对比本节点和网络其他节点的区块高度是否相同,如果相同则进入共识出块阶段,如果不同则随机选择一个有相关区块高度的节点进行快速同步,直到同步高度和所有网络节点中最大区块高度相同,然后进入共识出块阶段。当本节点通过共识算法检测到作恶节点后,会断开和作恶节点的连接,并且从路由表和DB里删除此节点的信息,并且向其他节点询问此节点是否是作恶节点,如果达成2/3共识,则将对作恶节点进行相关惩罚,并且下次启动时也不会接受作恶节点的请求连接。
图4:迅雷链节点发现主要流程
如图4,迅雷链在节点1与节点3之间增加了P2PServer,P2PServer主要用于处理节点1和节点3 P2P消息的转发,从而达到节点1和节点3 P2P穿透的目的。其中P2PServer服务可以部署在公网服务器上,也可以部署在链上全网所有节点上。
所以,对比比特币和以太坊网络,迅雷链网络节点采用种子节点和验证人节点结合的方式,而且对于验证人节点之间的连接,增加了P2P穿透协议,从而增加了验证人节点之间的连通率,间接减少了种子节点连接压力,避免种子节点过度中心化。而且对于网络中的作恶节点,能够结合共识算法及时检测到并做出相应惩罚,并且保证下次不会接受作恶节点的网络包,从而也保证了正常节点的网络安全性。
*恭喜完成第九课的学习,第十课我们将学习区块链的共识算法,欢迎关注~
标签:精品课,网络,信息,节点,P2P,第九课,迅雷,连接 来源: https://blog.csdn.net/weixin_43378619/article/details/110490511