Hi Guest

More contents, please log on!

Bitmere.com 区块链前沿 Content

P2P 网络的思考

韩氏王子韩hl
15 0 0
P2P网络综述

    P2P网络中每个节点具有完全相同功能,既提供服务又提供客户端访问。这样做的好处是可扩展性非常强。可以随意增加或者减少节点,对整个网络服务不会有很大影响。P2P网络和现在Internet上大部分网络之间最大区别在于,现在大部分网站是C/S(Client/Server)架构,而C/S架构是有一个强依赖。如果中心节点挂掉,Client节点将无法工作。P2P和C/S架构区别就是P2P架构没有一个中心节点,每一个节点其实都是一个小中心,这样网络上只要存在节点,那么整个服务就能继续进行。

    比特币P2P网络

    了解了P2P网络的定义之后,接下来开始讲解比特币P2P网络。按照顺序,我们从比特币节点启动开始,给大家讲解如何同步到最高高度、出块、转发交易。

    节点启动

    首先是启动,启动就有一个节点发现的过程。比特币客户端启动时,有四种选择来连接该网络。

    用命令行强指定链接某个节点,那么就会去连接。

    如果没有命令行指定,就在本地节点查询是否有存储的、连接过的IP地址,如果有就尝试链接。连接不上那么会选择第三步。

    如果没有命令行指定也连接不上之前连接过的IP地址,那么在比特币每次发版时,在代码里面硬编码了一些DNS的服务器,这些服务器可以理解为我们现在Internet里,网址和IP对应的服务器。这个服务器本身可能是静态或者是动态的,如果节点查到有相应服务器的话,就向相应地址发起连接请求,如果还不能连接上,那么就到最后一步。

    客户端维护了一个活跃节点列表,客户端和他们连接能够获取一些网络的信息。

    (这个感觉有点像你实在找不到人求救的时候还能打110的固定电话)

    这就是比特币网络发现节点的过程,和普通的一些分布式应用节点发现类似,(在版本编码时)都有一个类似注册中心,如果没有直接指定,节点就会向注册中心发起一些查询工作来寻找可以连接的节点。

    查询到可连接IP后

    那么下一步,本地节点如果已经链接到可用的IP时候,会做什么?

    首先,比特币知道IP时,将对远端节点发送Version消息,里面会有自己客户端的型号、版本号、类型(轻节点、全节点或者验证节点)。远端节点收到这个消息之后会根据自己的版本号、能够接受的消息来返回消息,如果这个消息验证结果是我能和这个节点通信,那么就会返回一个消息verack,远端节点也会同时向节点发布一个Version确定自己版本和节点类型。请求verack之后本地节点就向远端节点发送它记录的IP节点的list,就把活跃的list存在数据库,方便以后快速启动节点。

    同步策略

    在新节点链接上网络时,本地是没有数据的,这时需要向远端节点请求一些历史数据,同步整个链的数据到本地,这里有两个策略。分别是版本0.9.3之前的Blocks-first策略,和0.10之后的Headers-first策略,对比图如下:

    实际上交互模式是一样的,首先是hash或者header。hash是每个块的hash,每个块的块头会有一个代表整个块的hash,headers-first则将每个块的headers拿过来。之后是用header或者hash向远端节点请求blocks,然后往复进行。看上去协议都差不多,为什么要这样做?

    Blocks-first问题

    Blocks-first唯一优点是实现方便,但它存在下面几个问题:

    首先,我的节点连接到其他的节点,实际上如果没有断掉就会一直请求数据。那么如果这是一个故意做恶节点呢?它会返回一些不是最大工作量证明的hash,而本地节点是不知道hash里面是什么,只会根据返回的hashlist去请求。最后同步到什么状态呢?Bitcoin每到一定高度会有checkpoint的点,会检查你同步的块是最大工作量证明还是错误的块。如果连接的节点是恶意节点,那么,我的节点只有到checkpoint时,才会发现我同步的几块是错误的,这样导致我本地服务器的磁盘消耗会非常大,一般是几个甚至是几十个G之后发现这些是无效数据。

    其次,是速度限制。Blocks-first协议规定,如果这个连接没有中断的话,将一直向同一个节点请求数据。如果远端节点上传和下载数据受到限制,本地节点同步的速度将受到限制。

    最后,是高内存占用。Blocks-first策略请求的是块的hash,一个问题就是协议要求远端节点的hash是完全按照顺序发送的,如果没有按照顺序本地节点就会验证不了,从而导致乱序的块。这样的块如果找不到parentsblock,比特币就会把这些块定义为是孤儿块,会把它们临时存放在一个内存里面,直到请求到完整的parentsblock之后才会把parentsblock和孤儿块入库。这时候如果远端节点做恶的话,先给很多高度很高的块,前面的都不给(也就是没有parentsblocks),每个块需要几k,几十万个块就能把你的内存撑爆。

    Headers-first策略

    Headers-first的策略闪亮登场。这个策略会把整个链的headers全部下载下来,headers里面包括所有block的hash以及parents的hash,可以用headers串起一条链。虽然不知道交易是什么,但是能够从headers里面确定链是连续的,不连续会扔掉孤儿块。并且根据官方验证,一个新的节点同步整个链的话,只需要30m的存储能够把整个链全部同步下来,磁盘消耗非常小。

    那么速度限制怎么解决?headers一次请求是2000个块的步长。如果请求验证没问题的话,就会把haederhash16个一组发送给所有能够连接到的节点,来验证是不是对的,然后把对应的header的block给他,这样同步的时候不会被某个节点的网络限制,可以获取一批blocks向四周发送同步请求。

    这就是比特币的同步策略。相比于blocks-first策略,headers-first策略解决了1、速度限制;2、无效下载;3、高内存占用三个问题。

    新块广播

    接下来,同步到最高高度的时候,如果是挖矿节点就会涉及到挖矿广播的问题。我发现了下一个块的hash,我就会把块广播给我链接到的所有节点来获取奖励,这时候广播会有三种模式:

    1、推送式。这一种用的比较少。只要能连接上对方节点,那就把整个块推送过去,不管对方接不接受。

    2、标准转发模式,发现新块时,将新块的hash做一个消息推给周围所有人,如果对方返回消息说他需要hash具体数据,那么就将整个块给他,有一个通知→回复→再回复的过程。

    3、0.10.0之后,出现了块头公告的模式。只要是headers-first策略的节点,启动时,会做一件事情告诉连接所有节点,我不要标准转发的模式,我需要的是发现新块时,直接把header给我。这样就能够省去一个「我给列表→你请求列表数据→然后再把数据给我」的整个过程。直接把header给他,然后他就可以向任何人请求headers对应的data。

    这就是新块广播的过程。

    节点交易转发过程

    交易发送到任意能够接受的节点的时候,交易会存在当前节点的内存池里面,然后节点收到交易时,会做一个hash列表,发送给能够连接到的所有人。一个节点最多能够连接8个节点,如果别的节点发现内存池里面没有这个交易,那就返回getdata。那么对方收到的时候会把整个交易的内容转发过去。

    这里有一个问题,就是不要相信每个交易都会上链,因为交易是存在内存池里面的,并不上链。如果一个节点没有把交易发送出去就下线了,那么这笔交易就会丢失,这是很正常的一件事情。

    这就是交易的转发过程。

    到这里比特币的网络协议基本就是这样节点启动、同步、最高高度之后能够转发交易,能够运作。

    公有许可链CITA

    比特币是区块链的鼻祖,但在性能上存在一个问题,10分钟一个块,6个块之后才能确认交易是放在主链上的。之后为了能够有更高的性能就出现了联盟链。CITA项目初创的时候是联盟链,我们讲一下当前状态的CITA联盟链是什么样的。

    CITA网络综述

    CITA的网络,和比特币不一样的地方就是CITA是N个进程结合在一起作为整个逻辑节点的。比特币是一个进程,CITA是微服务架构,所以有七个进程。CITA对外有节点间通信,对内还有每个服务之间的通信,所以会分为节点间的通信和节点内的通信。因为CITA刚开始时,作为联盟链,节点数在链的初始状态就确定了,也不会很多,所以在一开始就使用TCP全连接。

    这么做的好处是什么?即我的消息,只要是知道的,只需转发就点对点转发给我所知的所有节点,消息到达速度非常快。比特币消息转发给全世界需要时间,CITA作为联盟链的时候,每个节点之间都是有连接的,如果一个消息要广播给整个网络,只要他保留TCP所有连接,就能够一次性转发出去。节点之间的通信协议并没有比特币那么复杂,并没有Version、transaction、getdata等,而是最简单的协议,只有开始符、长度和数据。

    节点间同步

    目前,CITA共识算法是PBFT,是确定性的、一定不会分叉的共识算法,做恶节点小于三分之一时即可保证不会分叉。所以CITA的同步不需要分叉判断,只需要判断块高。如果我这个节点发现我连接的整个网络块高比我高三个块左右时,就会随机选择一个节点,大概20个块一组去同步。同步的消息是整个块发过来的,而不是像比特币那样先发送一个列表、header之后再把整个块发过来。

    交易转发

    关于交易的转发,因为CITA是全连接的,只要接到交易,验证通过之后,交易就会加入本地交易池,之后转发给所有能连接的节点,除了来源之外(转发交易给我的)所有节点都发一遍,在确保每个交易正常和网络正常的情况下,是不会拉下任何一个节点的。

    共识提出

    在CITA中,共识的proposal提出的话,也是以广播的方式去发送的。CITA里面节点是分为共识节点和只读节点。共识节点有权发起投票,只读节点只能进行同步和交易的转发。虽然只读节点不能发起投票但是也能够收到proposal的消息,然后节点会判断自己能不能投票,如果不能投票就会放弃这个交易。这个是CITA节点之间的通信。对比特币来说,CITA节点通信简单了很多,因为网络环境比较简单,毕竟比特币是公网。

    节点内部通讯

    CITA节点内部的通信,每个微服务的通信都是异步的模式,即我(节点)发出消息之后,不管对方是否回复都先做自己的事情。这里有一个问题就是,如果我这个节点的消息你没有收到,另外一个微服务突然挂了,状态不一致的情况下,就有一个状态同步的问题。现阶段CITA分为共识进程,执行器进程,数据库进程以及网络进程,这些都是有状态的,以数据库为准。如果数据库说这个节点有100的高度,那么整个逻辑节点所有状态都是100的高度。如果不是,就是坏掉了。所以现在最复杂的问题是节点内部每个服务状态同步的问题,如果不一致会让整个节点出现异常。比如:出现对外表现不一致,或者因为状态不一样所以不能发器投票。因此节点内通信最重要的是状态的同步问题,如果我应该接收到的没有收到,就会发起一个request-response来确认状态,如果状态和数据库不一致的话,将调整状态。

    未来可能性

    如果CITA变成公网,我们会遇到的一个问题是网络连接质量下降,如何既保持开放又能为共识提供足够的网络速度?节点间的直连也许依然会是需要的一种方式,同时补充gossip网络协议,即在我发送消息时知道的所有节点中,随机找两个节点发出去,别人收到时也会随机选两个节点转发出去,全网最终能够达到一致的状态的,我的消息都能够传遍全网。这样能够大大降低服务器的网络开销。共识节点可以用直连的方式来保证出块和交易速度。
BitMere.com is Information release platform,just provides information storage space services.
The opinions expressed are solely those of the author,Does not constitute advice, please treat with caution.
You have to log in before you can reply Login | 立即注册

Points Rules

Write the first review

韩氏王子韩hl 小学生
  • Follow

    0

  • Following

    0

  • Articles

    2

币圈江左盟
Promoted