(二)IPFS底层技术分析

  • 传统KAD算法的存在的问题

1.常见的KAD攻击办法

1.1 攻击底层网络

        假设底层网络层不为覆盖层提供任何安全属性。 因此攻击者可能能够偷听或修改任意数据包。此外,我们假设节点可以欺骗IP地址,并且底层中没有数据包的认证。 因此,对底层的攻击可能会导致对覆盖层的拒绝服务攻击。

1.2 攻击覆盖路由

  • 日蚀攻击:通过在某一个或者几个恶意节点周围放置恶意节点,使得正常节点的所有路由消息都至少经过一个恶意节点,这样使得攻击者可以操控部分上层协议的网络,从而达到将部分正常节点从网络中屏蔽的目的。不过这个问题是可以容易防范的,如果节点的ID是不能随意生成,并且新节点影响其它节点路由表的方式是受控的,那么这个问题可以得到解决,从前面的章节我们已经知道,kademlia的k-bucket里面节点的替换原则是,更青睐长期在线的老节点信息,因此较为安全的避免了此类攻击。
  • 女巫攻击:在一个完全去中心化的网络中,没有方案可以控制节点ID的生成,这样攻击者可以生成一定数量的恶意节点ID来达到控制网络的目的,经过证明,这种攻击是无法完全杜绝的,只能通过增加生成ID的成本来控制这种攻击带来的危害。中心化的系统可以通过支付一定费用并绑定现实世界的个人来解决这种攻击问题,但是区块链世界就必须绑定一定的代币并且付出一定的计算机资源,以此来提高攻击网络的成本。
  • 客户流失攻击:如果攻击者拥有一定数量的节点并且使得网络的使用达到一定的失败率,那么会有非恶意节点的退出,劣币驱逐良币,这样整个网络就会失去价值,不过这种攻击对kademlia的攻击影响有限,因为本协议更倾向于长久在线的老的节点,因此除非初始的多数节点都是恶意攻击者,否则流失攻击对系统影响有限。
  • 恶意路由攻击:如果一个节点不响应查询或者不路由任何数据,那么其他节点就会将其从路由表中删除,因此一个恶意节点攻击网络的方式就只能是广播恶意的路由信息,比如一个恶意节点会返回某一个被查找节点ID附近的节点,而不是被查找节点本身,这样查询者就无法正确的找到目标节点,通过改善查找算法,通过查找多条没有交点的,能够到达目标节点的路径,来规避此类攻击,只要其中一个路径上没有恶意节点,那么就可以成功找到目标节点。

2.KAD的缺点

  1. 没有计算节点之间的往返时延,可能会导致访问等待时间比较长
  2. 由于KAD的数据存储策略,容易引起热点问题和树饱和问题。所谓热点拥挤是由于在节点路由期间,可能同时有多个查询要访问同一个节点,因而覆盖网络上的这个节点成为覆盖网络上的一个热点。若出现这种现象,查询访问的延迟相对而言就会非常大,因而将会对后续访问请求阻塞。“树饱和”,指的是当路由被阻塞在某条路径上时,即使这些被阻塞的节点和其后的节点有不同的目的路由,也会进一步阻塞其后的查询或插入操作。
  • S/Kademlia

1.制定节点ID生成规则

       首先是更加安全的节点编号生成规则。如果我们能够限制参与者随意选择节点ID的情况,那么我们就可以规避日食攻击,因为一旦ID的生成规则不被操控,那么就很难在被攻击节点周围形成有效的遮挡,无法到达屏蔽节点的目的。如果设计一个规则,使得攻击者很难廉价的生成大量的节点编号,那么就可以有效的规避女巫攻击。同时如果对节点的ID进行授权和检验,那么没有人可以仿冒或者偷走别人的节点ID。可以通过将IP地址和端口进行hash运算或者对节点的公钥进行hash运算来达到对节点进行有效性检验的目的,但是对于NAT网络来说,很多共享网络的节点对外的IP地址是相同的,并且也无法通过IP地址的方式来限制节点的生成个数,因此我们采用后者,对一个公钥进行hash来生成节点的ID。

        为了达到抵御女巫攻击和日食攻击的目的,还需要一些机制来限制设计节点ID的生成规则。有2种方式可以达到这个目的,一个是通过中心化的证书认证机构来实现,另一个是在生成节点编号时通过解答加密谜题的方式实现。通过中心化的CA证书方式,可以有效解决项目早期,节点较少时的网络女巫攻击问题。通过评估早期公链早期节点数量来决定是否采用此方案。在纯粹的去中心化网络中,没有中心认证机构的情况下,需要通过提高节点生成ID的成本和难度来预防女巫攻击和日食攻击。在我们的改进方案中,我们采用了2种解答谜语的方式,分别来解决女巫攻击和日食攻击的问题。

(二)IPFS底层技术分析_第1张图片

2.对消息进行签名

对节点与节点之间的消息进行签名。签名分为两种,一种是弱签名,一种是强签名。

  • 弱签名:只是对消息的部分内容进行签名,比如节点的IP地址,端口号和时间戳。时间戳指定了签名的有效时间,这个有效时间可以预防动态IP的接力攻击问题。这类签名可以用于查找节点和PING命令这些消息完整性要求不高的场景。
  • 强签名:是对节点之间的全消息进行签名,这保证了消息整体上的有效性,可以有效抵御中间人攻击,并且通过在消息中添加随机数,可以抵御接力攻击。

3.利用可靠的兄弟节点进行数据传播

        兄弟是负责需要存储在DHT中的某个键值对的节点。在传统的KAD里面,通过k个最接近key-value对中key的距离最近的节点来冗余存储value,我们可以实现数据的安全存储,并且这个k还是k-bucket的中的k的值,即每个距离等级下最多存储的节点的个数。也是用于冗余存储数据的距离key最近的节点的个数。一个常见的安全问题是兄弟信息的可靠性,当复制的信息需要存储在使用多数决定来补偿敌对节点的DHT中时产生。 由于Kademlia的原始协议收敛到兄弟列表中,分析和证明兄弟信息的一致性是很复杂的。我们现在考虑某个节点都保存w*s个距离最近的兄弟节点列表,这个列表可以确保每个节点知道至少S个距离某个ID的兄弟节点。

4.路由表的维护

        在路由消息的过程中,根据最新的消息来维护本地路由信息,如果是查找节点或者存储数据,那么我们都要执行相关的节点查询操作,根据查找消息的返回结果和响应情况来更新本地的路由信息。在改进方案中,根据消息是否签名来决定是否更新本地的路由信息,如果是弱签名或者是强签名,则可以根据一定的策略和情况来决定是否更新本地路由,如果消息未签名,则不用于更新本地路由。

5.通过不相交的路径进行查找

       在传统的KAD算法中,我们会在k个节点中人选a个节点来询问关于目标ID的信息,并逐渐的靠近目标节点ID,查找出k个距离目标ID最近的节点信息,这个过程中如果遇到恶意节点,则签名的递归查询就前功尽弃。为了解决这个问题,通过将k个靠近目标ID的节点信息查询出来并寻找D个不相交的到达目标ID的路径,然后同时发出寻找命令,那么就可以很好的规避恶意节点的攻击,只要D条路径中有一条路径上是安全的,没有恶意节点参与的,那么就可以成功完成查找动作。

  • Coral(DSHT)

       Coral 是一种在DHT的基础上扩展的索引机制,称之为DSHT(distributed sloppy hash table)。它主要解决了DHT覆盖网络中位置问题。不同于传统的DHT方式,在coral中,首先对所有节点的RTT(往返时延)进行一个综合评估,然后按照RTT是时间划分为几个等级,默认是3个等级L2(<20ms),l1(<60ms),l0(剩余的所有节点)。节点的ID空间任然是sha-1生成的160bit,但是在查找和放置的时候,优先在整个NodeID空间中的层次L2上的节点进行DHT查找,L2 层中找不到合适的节点再去L1层中查找,最后是L0层,由于L2的节点之间的延迟小于其他层级,通过这种方法实现位置感知,查找次数应该与一般的DHT方式相同,但是查找的开销相对于DHT却减少了。但是传统的DHT只需要维护一个DHT表,而coral需要维护3个,现在在节点加入或者离去的时候系统维护成本比较高。

1.Coral 组成

Coral的主要组成部分包含两部分:

  1. Coral DNS Server (dnssrv)
  2. Coral Http 代理(CoralProxy)

1.1 Dnssrv

        客户查找经过coralize URL时候,dnssrv返回离客户比较近的代理的Ip地址,这些代理都是在一个合适的cluster(就是前面说的L2、了L1、L0层)之中,同时保存来自于相同客户的DNS请求不会离开该cluster。

       所谓的coralize化的URL是指在原来的域名后加上.nyucd.net:8089,但是这实际上是一个缩写,完整的应该是http.L2.L1.L0.nyucd.net,每一个dnssrv解析这个域名的名字服务器。同时coral假设dnssrv能够发现客户端的locality. 在每次请求中,dnssrv返回两个数据集:对于IP的代理地址集,对于name’s domain的名字服务器。而且客户和dnssrv之间RTT的如果在level-i层,那么dnssrv只返回那些在同一个level上coral node的地址。对于代理,返回的短TTL的,对于L2,L1是30ms,L0是60ms。dnssrv同时会在获得DNS授权的数据中查找,并把客户锁定到合适的cluster上面.并且给这些nameserver一个比较长的TTL。对于那些长于L1时间的客户,dnssrv返回的是域L0.nyucd.net的名字服务器。长于L0时间的客户,dnssrv返回的域L1.L0.nyucd.net的名字服务器。

1.2 Coral HTTP 代理:

       Coral设计是考虑低延迟,高吞吐量以及对于源服务器的负载减轻,采用“走过必留痕迹”的策略,每个coralProxy都尽可能的拉取数据,如果客户请求的URL不在本地缓存中,则他们就会在Coral中查找,然后在DSHT中插入一个references,告知系统自己有这个缓存,保存时间一般为20s,如果这个代理得到了完整的文件,就会告知系统它会保存更长时间备份。

2. Coral的sloppy存储方式

       coral使用sloppy存储技术在ID离key最近/较近的节点中缓存key/value对。所谓的sloppy存储技术就是在执行存储操作时并不是严格查找离key最近的节点,即使是最近的节点存在的情况下也可能将value缓存在非最近的节点上。这种缓存方法减少了热点拥挤和树饱和效应。由于树饱和会对后续路由有滚雪球效应,因而消除树饱和是非常重要的,目的是降低平均操作时延。因为通过索引机制,经常在离key较近而不是最近的节点中满足put和get的请求。这是DSHT有别于DHT的地方,在DHT中put操作总是在离开最近的节点上执行,从而容易产生热点拥挤。

         上述操作依赖于插入算法,DSHT在插入key/value对时执行两阶段的操作。开始时是“转发”阶段,DSHT路由到离最近的节点,然而,  为了避免树饱和,插入操作可能在定位最近节点之前终止,这种情况下,key/value对将存储在一个更远一点的节点上。具体讲,当发现另一节点处于关于这个key的full或loaded的状态时,转发阶段终止:

  1. key值为k的节点处于full状态是指当该节点已经存储了k的l个值,并且这l个值的TTL至少是新存储值的TTL一半。
  2. Key值为k的节点处于loaded状态是指:当一分钟内收到多于a个关于k的询问。

       缺省情况下,l=4,a=12,意味着在高负载情况下,每5秒钟一次以上的对节点的读取频次下会导致该节点被声称为loaded状态。这就防止了针对键值对最近节点的过多插入和集中检索操作,从而避免了树饱和效应。然而,每分钟12次的读取频次依然允许足够多的请求以保证这些节点的内容能被及时刷新。

在转发阶段,coral的路由层重复执行RPC来依次联系与key比较接近(不是最接近)的节点。每个远程节点返回:

  1. key是否处于loaded状态
  2. 保存在这个key下的值的数量,以及每个值的最小过期时间TTL。

      客户节点使用这些信息确定远程节点是否接受存储,并替换出TTL最小的值。当客户节点要么发现离key最近的节点,要么发现关于key的节点处于full或loaded状态.转发过程终止。客户节点将所有联系过的非full和loaded状态的节点按照异或距离从小到大顺序放到堆栈中。

       在返回阶段,客户节点从堆栈中弹出一个远程节点,尝试在这远程节点插入值,如果这个操作没有成功,可能是由于别的插入正在进行,客户节点会再弹出一个稍远点的远程节点,再试着插入。重复这个过程直到存储成功或堆栈为空。

  • BitTorrent协议

1.概要

         BitTorrent(简称BT)是一个文件分发协议,每个下载者在下载的同时不断向其他下载者上传已下载的数据。而在FTP、HTTP协议中,每个下载者从FTP或HTTP服务器处下载自己所需要的文件,各个下载者之间没有交互。当多个用户同时访问和下载服务器上的文件时,由于FTP服务器的处理能力和带宽的限制,下载速度会急剧下降,有的用户根本访问不了服务器。BT协议与FTP协议不同,它的特点是下载的人越多下载的速度越快,其原因在于每个下载者将已下载的数据提供给其他下载者下载,它充分利用了用户的上传带宽。BT协议通过一定的策略保证上传的速度越快,下载的速度也越快。

2.基于BT协议的文件分发系统的构成

基于BT协议的文件分发系统由以下几个实体构成:

  1. 一个web服务器
  2. 一个种子文件
  3. 一个Tracker服务器
  4. 一个原始文件提供者
  5. 一个浏览器
  6. 一个或者多个下载者

        Web服务器上保存着种子文件,下载者使用浏览器从Web服务器上下载种子文件。种子文件,又称为元文件或metafile,它保存了共享文件的文件名、文件大小、Tracker服务器的地址等信息。种子文件通常很小,一般大小为1GB的共享文件,其种子文件不足100KB,种子文件以.torrent为后缀。Tracker服务器保存着当前下载的某共享文件的所有下载者的IP和端口。原始文件提供者提供完整的共享文件供其他下载者下载,它也被称为种子,种子文件就是提供者使用BT客户端生成的。每个下载者通过运行BT客户端软件下载共享文件。我们把某个下载者本身称为客户端,把其他下载者称为peer。

        BT客户端下载一个共享文件的过程是:客户端首先解析种子文件,获取待下载的共享文件的一些信息,其中包括Tracker服务器的地址。然后客户端连接Tracker获取当前下载该文件的所有下载者的IP和端口。之后客户端根据IP和端口连接其他下载者,从它们那里下载文件,同时把自己已下载的部分提供给其他下载者下载。

         共享文件在逻辑上被划分为大小相同的块,称为piece,每个piece的大小通常为256KB。对于共享文件,文件的第1字节到第256K(即262144)字节为第一个piece,第256K+1字节到第512K字节为第二个piece,依此类推。种子文件中包含有每个piece的hash值。BT协议规定使用Sha1算法对每个piece生成20字节的hash值,作为每个piece的指纹。每当客户端下载完一个piece时,即对该peice使用Sha1算法计算其hash值,并与种子文件中保存的该peice的hash值进行比较,如果一致即表明下载了一个完整而正确的piece。一旦某个piece被下载,该piece即提供给其他peer下载。在实际上传和下载中,每个piece又被划分为大小相同的slice,每个slice的大小固定为16KB(16384字节)。peer之间每次传输以slice为单位。

3. Peer之间的通信

        peer之间的通信协议又称为peer wire protocal,即peer连线协议,它是一个基于TCP协议的应用层协议。

       为了防止有的peer只下载不上传,BitTorrent协议建议,客户端只给那些向它提供最快下载速度的4个peer上传数据。简单地说就是谁向我提供下载,我也提供数据供它下载;客户端每隔一定时间,比如10秒,重新计算从各个peer处下载数据的速度,将下载速度最快的4个peer解除阻塞,允许这4个peer从客户端下载数据,同时将其他peer阻塞。

      一个例外情况是,为了发现下载速度更快的peer,协议还建议,在任意时刻,客户端保持一个优化非阻塞peer,即无论该peer是否提供数据给客户端下载,客户端都允许该peer从客户端这里下载数据。由于客户端向peer上传数据,peer接着也允许客户端从peer处下载数据,并且下载速度超过4个非阻塞peer中的一个。客户端每隔一定的时间,如30秒,重新选择优化非阻塞peer。

       当客户端对peer感兴趣且peer未将客户端阻塞时,客户端可以从peer处下载数据。当peer对客户端感兴趣,且客户端未将peer阻塞时,客户端向peer上传数据。

4.关键算法和策略

1.流水线作业

       BT协议作为一种构建在TCP协议上的应用层协议,可以通过流水线作业来提高数据传输的效率。具体而言,当客户端向peer发送数据请求时(即发送request消息),一次请求多个slice(即在一个数据包中发送多个request消息请求多个slice)。假如客户端一次只发送一个slice请求,则peer给客户端发送完一个slice的数据后就进入等待,等待客户端发送新的数据请求。如果一次发送多个slice请求,则peer发送完一个slice后接着发送下一个slice,从而避免了等待,提高了数据传输的效率。

2. 片断选择算法

2.1 片断原则第一策略

       一旦向某个peer发送对某个piece中的slice的请求后,则该piece中的其他slice也从该peer处下载,这样可以尽快地下载到一个完整的piece。因为某个peer拥有某个piece中的一个slice,则它必定拥有该piece的其他slice,并且如果peer愿意发送一个slice给客户端,它也应该愿意发送piece中的其他slice给客户端。该策略也被称为严格的优先级。

2.2 片断原则第二策略

        最少优先:即某个piece在所有peer中的拥有率最低,则优先下载该piece。这么做的优点是,第一,可以防止拥有这个piece的peer突然离开,导致某个piece的缺失,从而当前任何一个参与下载的peer都不能下载到一份完整的文件;第二,如果下载了某些拥有率较低的piece,则其他很多peer会向客户端请求数据,而要想从客户端下载到数据,那些peer就要提供数据给客户端下载,这样对于提高客户端的下载速度也是有帮助的。对于这个共享系统而言,优先下载拥有率较低的piece可以使得整个系统提高每个piece的拥有度,整个系统会趋向于最优。如果所有peer优先下载拥有率较高的piece,会使某些piece的拥有率进一步降低,而拥有这些低拥有率piece的peer一旦离开共享系统,则整个文件会越来越不完整,最后导致许多peer不能下载到一个完整的文件拷贝。

2.3 片断原则第三策略

       随机选择第一个要下载的piece。开始下载时,不能采用最少优先策略。原因在于,采用最少优先策略,如果某个piece的拥有率很低,那么下载到这个piece就相对较难。如果随机选择一个piece,那么更容易下载到该piece,一旦客户端下载到一个完整的piece,就可以提供给其他peer下载,而由于客户端向其他peer上传数据,会导致其他peer对客户端解除阻塞,从而有利于在起始阶段获得较高的下载速度。当然在下载到一些piece后,客户端应该采用最少优先策略来下载数据,这虽然会导致客户端的下载速度在短期内有所下降,但随后下载速度会有较大提高。

2.4 片断原则第四策略

      有时,从一个传输速度很慢的peer处下载一个piece会花费很长时间,在下载的过程中这不是什么大问题。但在下载接近完成时,如果发生这种情况,会导致客户端迟迟不能下载完成。为了解决这个问题,在最后阶段,客户端向所有peer发送对这个piece的某些slice的请求,一旦收到某个peer发来的slice,则向其他peer发送cancel消息,只从当前这个peer处下载。

3. 阻塞算法

        BT并不集中分配资源,每个peer有责任尽可能地提高自己的下载速度。peer从它可以连接的peer下载文件,并根据对方提供的下载速率给予同等的上传回报,对于合作者,提供上传服务,对于不合作的,就阻塞对方。阻塞是一种临时拒绝上传的策略,虽然上传停止了,但是下载仍然继续。在解除阻塞时,连接并不需要重新建立。因为阻塞过程中只是拒绝传输piece消息,其他消息,如have消息,interested消息仍可以传输。阻塞算法虽然不是BT协议一部分,但是它对提高性能是必要的。

        每个客户端一直与固定数量的peer保持疏通(通常是4个),那么以什么方式来决定是否保持与某个peer疏通呢?通常的做法是,严格地根据当前的下载速度来决定哪些peer应该保持疏通。但计算当前下载速度是个大难题。当前的实现通常是计算最近10秒从每个peer处下载数据的速度。以10秒为间隔重新选择保持疏通(即解除阻塞)的peer,是为了避免频繁地阻塞和解阻塞,造成资源的浪费。实践表明,10秒足以使下载速度达到最大。

          如果只是简单地为提供最高下载速率的4个peer提供上传服务,那么就没有办法发现那些空闲的连接是否有更好的下载速度。为了解决这个问题,在任何时候,每个peer都拥有一个称为“optimistic unchoking(优化非阻塞)”peer,这个连接总是保持疏通状态,而不管它的下载速率是多少。每隔30秒,重新选择一个peer作为优化非阻塞peer。30秒足以让该peer的上载能力达到最大。

一旦某个peer完成了下载,它不能再通过下载速率(因为下载速率已经为0了)来决定为哪些peer提供上载了。目前采用的解决办法是,优先选择那些从它这里得到更好下载速率的peer,保持与它们疏通。这样做的理由是尽可能的利用上载带宽。一旦某个peer完成了下载,那么它也就成为了种子。种子拥有一份完整的文件拷贝,并提供给其他peer下载。为了整个系统的性能,每个peer在完成下载后应该作为种子存在一段时间,作为对整个系统的回报。原始种子,即最初提供文件进行共享、并制作生成了种子文件,并把种子文件发布到Web服务器的种子,它至少应该存在到系统中生成另外一个种子时才能离开,否则当前参与下载的所有peer都不能获得一份完整的文件拷贝。

5. BT的系统结构设计

(二)IPFS底层技术分析_第2张图片

整个系统各个模块的功能如下:

(1)种子解析:负责解析种子文件,从中获取Tracker服务器的地址,待下载文件的文件名和长度,piece长度,各个piece的hash值。

(2)连接Tracker:根据HTTP协议构造获取Peer地址的请求,与Tracker建立连接,解析Tracker的回应消息,从而获取各个peer的IP地址和端口号。

(3)与peer交换数据:根据peer的IP地址和端口号连接peer、从peer处下载数据并将已下载的数据上传给peer。

(4)出错处理:定义整个系统可能出现的错误类型,并对错误进行处理。

(5)运行日志:记录程序运行的日志,并保存到文件中以备查看和分析。

 

模块“与peer交换数据”是本系统的核心和主要构成部分,划分成如下几个子模块:

(1)peer管理:系统为每一个已建立TCP连接的peer构造一个peer结构体。该结构体的主要成员有:peer的IP地址和端口号、与该peer进行通信的套接字、该peer的id、当前所处的状态、发送缓冲区、接收缓冲区、数据请求队列、数据被请求队列、从该peer处已下载的数据量和向该peer上传的数据量、下载速度和上传速度。本模块负责管理peer链表,添加和删除peer结点。

(2)消息处理:peer与peer之间以发送和接收消息的方式进行通信。本模块负责根据当前的状态生成并发送消息,接收并处理消息。BitTorrent协议共定义了12种消息,其中对下载和上传数据最重要的是request消息和piece消息。request消息向peer发送数据请求,指明请求的是哪个piece的哪个slice。Peer接收到request消息后根据当前的状态,决定是否发送数据给对方。如果允许发送,则构造piece消息,数据被封装在该消息中。每当下载完一个正确的piece时,就向所有peer发送have消息通告已获得该piece,其他peer如果没有该piece就可以向peer发送数据请求,每次请求都是以slice为单位。

(3)缓冲管理:如果下载完一个piece就立即写入硬盘,这样会导致频繁读写硬盘,既影响速度(读写磁盘要花费较多的时间),又不利于保护硬盘(频繁读写磁盘会使硬盘寿命缩短)。为了解决这个问题,几乎所有的BT软件都在程序中增加了一个缓冲管理模块。将下载到的数据先缓存起来,等到下载到一定量的数据后再集中写入硬盘。peer请求一个slice的数据时,先将该slice所在的整个piece读入到缓冲区中,下次Peer再请求该piece的其他slice时,只常缓冲区中获取,避免了频繁读写硬盘。本模块负责维护一个16MB的缓冲区(大小可调),将下载到的数据保存在缓冲区中,并在适当时刻写入硬盘的文件中。

(4)位图管理:BT协议采用位图指明当前哪些piece已经下载,哪些piece还没有下载。每个piece占一位,值为0表示该piece还未下载到,为1则表明已经下载到该piece。本模块负责管理位图,客户端与peer建立了连接并进行握手之后,即发送位图给peer告知已下载到哪些piece,同时也接收对方的位图并将其保存在Peer结构体中。每下载到一个piece就更新自己的位图,并发送have消息给所有已建立连接的peer。每当接收到peer发来的have消息就更新该peer的位图。

(5)策略管理:BT协议的设计者为了保证整体性能而制定了许多策略,这些策略虽然没有写入BT协议,但已经成为事实上的标准,BT软件开发者一般都使用这些策略来保证程序的性能。本部分负责策略的管理,主要是计算各个peer的下载和上传速度,根据下载速度选择非阻塞peer,采用随机算法选择优化非阻塞peer,以及实现片断选择策略。

(6)信号处理:在运行过程中,程序可能会接收到一些信号,如SIGINT、SIGTERM,这些信号的默认动作是立即终止程序。这并不是所期望的。在程序终止前需要作一些处理,如释放动态申请的内存、关闭文件描述符、关闭套接字。

 

  • BitSwap

       IPFS中的BitSwap在BitTorrent基础上做了一些修改与优化,在底层和BT有着很多相同的地方,通过节点之间交换数据来分发数据。每个对等节点在下载的同时不断向其他对等节点上传已下载的数据。和BT协议不同的是, BitSwap 不局限于一个torrent文件中的数据块。BitSwap 协议中存在一个永久的市场,这个市场包括各个节点想要获取的所有块数据,而不管这些块是哪些如.torrent文件中的一部分。这些块数据可能来自文件系统中完全不相关的文件,这个市场是由所有节点组成的。

IPFS每个节点都维护两个列表:

  1. 已有的数据块(have_list)
  2. 想要的数据块(want_list)

       当两个节点建立连接后,节点间会根据这两个列表互通有无。对于p2p网络,有一个很重要的问题是:如何激励大家分享自己的数据,IPFS实现了自己的特殊的数据分享策略。IPFS的策略体系由信用、策略、账单组成。后期的话会使用filecoin实现激励机制。

1. BitSwap信用体系

BitSwap协议必须能够激励节点去乐于分享数据,即使这个节点暂时没有数据需求,IPFS根据节点之间数据收发建立一个信用体系:有借有还,再借不难。

  1. 给其他节点发送数据可以增加信用值
  2. 从其他节点接受数据会降低信用值

如果一个节点只接受数据而不分享数据,信用值就会降低而被其他节点忽略掉,简单而降就是:你乐于分享数据,其他节点也乐于发送数据给你,如果你不愿意分享,那么其他节点也不愿意给你。

2. BitSwap策略

根据上面饿信用体系,BitSwap可以采用不同的策略来实现,每一种策略都会对系统的整体性能产生不同的影响。策略的目标是:

  1. 节点数据交换的整体性能和效率最高
  2. 阻止“吃白食”(freeloaders)的现象。就是不能够只下载数据不上传数据
  3. 可以有效的防止一些攻击行为(比如:女巫攻击)
  4. 对信任节点建立宽松机制(lenient)

IPFS提供的策略机制为每个节点根据和其他节点收发数据,计算负责率r,节点根据负责率计算出来和这个节点数据发送率:

              R=bytes_sent/(bytes_recv +1)

              P(send/r) =1-1/(1+exp(6-3r))

      这个模型表达的意义:如果一个节点只接受数据不分享数据,别人发送给它的概率就会越来越低(到达某一个值后就会急剧降低接近0),如果节点保持分享数据,别的节点向你发送数据的概率就会越来越大。

(二)IPFS底层技术分析_第3张图片

 

 

3. BitSwap账单

        BitSwap节点会记录下来和其他节点通信的账单(数据收发),可以保持节点间数据交换的历史和防止篡改。当两个节点之间建立连接的时候,BitSwap会相互交换账单信息,如果账单不匹配,则清除重新记账。恶意节点可能会故意“丢失”账单,以希望清除掉自己的债务。其它交互节点会把这些都记下来,如果总是发生,节点就会被拒绝。

  • Merkle DAG

1. Merkle tree

(二)IPFS底层技术分析_第4张图片

       Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树。Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值。非叶节点是其对应子节点串联字符串的hash。

      Merkle Tree可以看做Hash List的泛化(Hash List可以看作一种特殊的Merkle Tree,即树高为2的多叉Merkle Tree)。

       在最底层,和哈希列表一样,我们把数据分成小的数据块,有相应地哈希和它对应。但是往上走,并不是直接去运算根哈希,而是把相邻的两个哈希合并成一个字符串,然后运算这个字符串的哈希,这样每两个哈希就结婚生子,得到了一个”子哈希“。如果最底层的哈希总数是单数,那到最后必然出现一个单身哈希,这种情况就直接对它进行哈希运算,所以也能得到它的子哈希。于是往上推,依然是一样的方式,可以得到数目更少的新一级哈希,最终必然形成一棵倒挂的树,到了树根的这个位置,这一代就剩下一个根哈希了,我们把它叫做 Merkle Root。

       在p2p网络下载网络之前,先从可信的源获得文件的Merkle Tree树根。一旦获得了树根,就可以从其他从不可信的源获取Merkle tree。通过可信的树根来检查接受到的Merkle Tree。如果Merkle Tree是损坏的或者虚假的,就从其他源获得另一个Merkle Tree,直到获得一个与可信树根匹配的Merkle Tree。

        Merkle Tree和Hash List的主要区别是,可以直接下载并立即验证Merkle Tree的一个分支。因为可以将文件切分成小的数据块,这样如果有一块数据损坏,仅仅重新下载这个数据块就行了。如果文件非常大,那么Merkle tree和Hash list都很到,但是Merkle tree可以一次下载一个分支,然后立即验证这个分支,如果分支验证通过,就可以下载数据了。而Hash list只有下载整个hash list才能验证。

Merkle Tree的特点

1. MT是一种树,大多数是二叉树,也可以多叉树,无论是几叉树,它都具有树结构的所有特点;

2. Merkle Tree的叶子节点的value是数据集合的单元数据或者单元数据HASH。

3. 非叶子节点的value是根据它下面所有的叶子节点值,然后按照Hash算法计算而得出的。

2. DAG(有向无环图)

        有向无环图(DAG, Directed Acyclic Graph):是一个无回路的有向图、DAG是一种模拟没有循环的信息的拓扑序列的方法。如果有一个图,从A点出发到B点,然后经过C点,最后可以顺着方向回到A,形成一个闭环,那么这个图就不是非向无环图。如果将从C到A的边方向改为从A到C,则变成有向无环图。

(二)IPFS底层技术分析_第5张图片(二)IPFS底层技术分析_第6张图片

拓扑排序:就是一个有向无环图的所有定点的线性序列。且这个序列必须满足这两个条件:

  1. 每个顶点出现且只出现一次;
  2. 如果在图中,有一条从A点到B点的路线,那么在拓扑排序中,点A一定排在点B的前面。

(二)IPFS底层技术分析_第7张图片        (二)IPFS底层技术分析_第8张图片

 

3. Merkle DAG

(二)IPFS底层技术分析_第9张图片

       IPFS中的任何内容,都可以有唯一的散列值,这也就是数据唯一的标识。因为每个数据块都有一个唯一的标识(散列值),那么,数据是防篡改的,因为修改它会改变散列值,如下所示:

(二)IPFS底层技术分析_第10张图片

         IPFS的中心原则就是对所有数据文件对应到一个统一的Merkle DAG上。这样的安全特性是无可比拟的。

 

版本控制系统:

         Merkle DAG结构的另一个强大的特征是,你可以利用它建立一个分布式的版本控制系统(VCS)。最流行的例子就是GitHub,GitHub在版本控制方面已经占据主流,开发人员通过它能够轻松地进行项目合作。同时,文件在GitHub中存储和版本管理通过Merkle DAG进行。它允许用户独立复制和编辑一个文件的多个版本,存储这些版本,修改和在需要的时候和原始文件合并编辑。

         IPFS对数据对象使用类似的模型:对应于原始数据对象的任何新版本都是可追溯的,可以检索整个文件历史记录。 鉴于数据块由本地存储至整个网络中,并且可以无限期地缓存,这意味着IPFS对象可以永久存储。

      另外,IPFS不依赖于Internet上任何一种单独的协议。数据的分发可以通过嵌套网络协议进行,也就是说,可以利用现有网络,但也可以在此之上构建新的网络协议。这种网络协议的中立性质非常值得注意,因为有了这样的方案,你可以自己构建设置、选择和构建所要使用的网络协议,从而完全可以避开网络审查。 因此,IPFS可能成为促进言论自由以对抗全球互联网审查流行的有用工具,但同时,也可能存在被不良行为者滥用的可能性。

MerkleDAG特点

Merkle DAG拥有如下的功能:

• 内容寻址:使用多重哈希来唯一识别一个数据块的内容

• 防篡改:可以方便的检查哈希值来确认数据是否被篡改

• 去重:由于内容相同的数据块哈希是相同的,可以很容去掉重复的数据,节省存储空间

MerkleDAG树形结构构建过程

        在IPFS网络中,存储文件时,首先会将文件切片,切割成256KB大小的文件。之后循环调用(MerkleDAG.Add)方法构建文件MerkleDAG。 文件hash值创建流程: 1:将切片之后的文件进行sha-256运算 2:将运算结果选取0~31位 3:将选取结果根据base58编码,运算结果前追加Qm 即为最后结果作为文件的46位hash值 根据IPFS底层代码计算,Merkle DAG为多叉树结构,最多为174叉树。

你可能感兴趣的:(IPFS)