一个比特币扩容争议中永存的新主张。
SPV号称允许比特币轻松移除区块大小上限,进而支持十亿级用户。有鉴于SPV客户端需要存储的数据大小极低,因此理论上SPV 扩容的潜力极高。
那么,我们从多角度来深入研究一下这一主张。
SPV工作原理

比特币白皮书中对SPV 的高级设计原理有相应描述。不过真正实施是在两年后。
早期的 SPV 应用相当简朴,需要下载整个区块链,就带宽而言与全节点无差,谈不上效率。
后来开尝试丢弃与 SPV 客户钱包无关的交易,节省出大量磁盘空间。 BIP37 方案发布用了18 个月,提出了隆过交易过滤器(Bloom filtering)规范。布隆过滤器的依靠区块头的Merkle根证明交易是否包含于区块,也就是通过快速判断出某检索值一定不存在于某个指定的集合,进而过滤掉大量无关数据,减少客户端不必要的下载量,大大降低了对带宽的需求。
由于以往的比特币系统协议中缺少对 SPV 的支持,在原有的协议中,可以通过“getheaders”命令来获取区块头,也可以通过“getdata”命令支持获取指定的区块, 但这种协议不支持通过 tx_hash 反向查找关键信息所在的区块。为了定位区块,客户端不得不下载整个区块链,于是乎布隆过滤器出来救场了。
客户端与比特币网络同步后,若保持与全节点的连接,就可以接受布隆过滤加载出来的与 SPV 钱包相关的交易信息。
SPV客户端扩容
从客户端的角度来看,布隆过滤器是在完整区块链中检索相关交易信息的一种非常有效的方式,确认支付验证的同时能保证客户端占用最少的 CPU 资源、带宽和磁盘空间。
无论未来交易量有多大,比特币 区块头的大小始终不变,只有 80 字节。按照每小时 6 个块的出块速度,每年产出 52560 个区块。SPV 客户端只保存区块头的话,年新增存储需求约为 4 兆字节,100年 也只有400M,那么即便用户使用低端设备,正常情况下也完全能够满足要求。
用来证明区块中收录交易真实性的 Merkle 树也是扩展强树。 如图所示,添加到Merkle树中的每一层实际上相当于上一层叶子总数翻倍,也就是所谓的几何增长(每层 = 2n-1),因此并不需要挖的很深,就能验证交易是否包含于某区块。


那么,于SPV 客户端来说,即使比特币区块大小扩展至几GB,SPV 客户端需要处理的数据也就那么多,那么普通的 3G 手机也可以安装 SPV 客户端。
但是,比特币网络扩容岂止这么容易。
SPV服务器扩容
SPV 对于客户端来说非常有效,但对于服务器来说就是另外的故事了。服务器,就是SPV客户端发送请求的全节点。
原因有这么几点:
SPV客户端向网络全节点发送请求时,为证明交易存在,节点需要处理海量数据。每当有SPV客户端请求,就需要重复该过程。因此,磁盘的输出输入速度限制很快就成了瓶颈。
SPV 客户端与区块链网络连接后,必须同步整个区块链,若客户端认为错过了某些交易,则需要从钱包创建之初开始重新扫描整个区块链。
有鉴于区块链的仅添加属性,说明增长是持续的,若没有足够的协议变更,区块链修剪将无法与BIP-37兼容,要知道BIP-37是希望标记NODE_BLOOM的全节点上应该是有所有区块信息的。
BIP37 SPV 客户端会出现漏报的情形,为应对此问题, SPV 客户端需要连接到多个节点(四个),但这样也并不能完全保证,好比女巫攻击可以将SPV客户端与主网隔离。另外,全节点的负载也相当于乘以个4。
对于连接到主网络且与区块链末端同步的 SPV 客户端来说,每新添加一个块或新交易都需要单独过滤,这就涉及到明显的 CPU 处理数据时间量问题,连接到网络的各个SPV 客户端都躲不过。
上数据
之前,约有 8300 个运行全节点接受连接,约8000个节点标记NODE_BLOOM,就是说理论上是可以为SPV客户端提供服务。问题是又有多少监听全节点能够合理的支持SPV客户端呢?
于是,问题成了:网络中全节点既能支持十亿级日常用户又能支持大块,有什么要求?

比特币核心默认的最大传入连接为 117,意思是网络中的可用套接口上限是93.6万个,但是,大部分套接口已经被占用了。
默认下,每个全节点连接到8 个其他全节点。根据比特币核心的开发者粗略估计,节点数约为10万个,其中9.2万个没办法为 SPV 客户端提供可用套接口,也就是说80万个可用套接口就这么没了,给SPV客户端剩下的套接口只有13.6万个。
于是,可以得出结论:约85%的套接口已经被全节点网络消耗(这里注意下,比特币核心开发者的这种估值是确定不了非监听节点在线时间的,要知道这些节点上下线节点是不固定的)。
我自己的节点支持 http://statoshi.info 上的 100 个全节点和 25 个 SPV 客户端,那么相当于全节点消耗了80%的可用套接口。

回到SPV客户支持十亿级用户的主张,首先,足够的全节点数量是必须的,也就是说得网络套接口数量至少得够吧,然后是CPU 周期、磁盘输入和输出等等。
我们算笔账。
假设(保守),这十亿SPV客户端用户:
每天发送、接受一笔交易。
每天同步钱包
为降低漏报风险,同步时请求四个不同节点。
那么交易量是 10 亿次/日,平均分配到各个块(怎么可能平均分配),每个区块包含约 700 万笔交易。然后,请出大佬Merkle树,证明交易包含某区块的哈希值数量为23:相当于736 字节(哈希) + 大小平均为500 字节的交易。
再加上12KB/日的区块头,SPV 客户端每日使用的数据大小也只有20KB。
但是,但是,每日10 亿笔交易,全节点需要存储并处理的数据大小会飙升到500GB。那么,SPV 客户端连接全节点请求检查前一日交易的时候,四个全节点就得分别读取过滤500GB大小的数据。
上面提到,有8000个服务SPV客户端的全节点的网络中,留给SPV客户端的套接口数量只有13.6万个记得不?那么,一个SPV客户端占四个套接口,相当于只有3.4万个SPV客户端能同时与整个网络同步。 说明上线人数超过3.4万,就会有人无法连接到全节点进而无法同步的情形。
那么,10亿用户,每天同步一次,每次同步SPV客户端数量上限是3.4万。相当于这十亿客户端得分成2.94万个组,分别连接、同步,然后断开连接。一天有24小时,十亿人,都同步过来,每个客户同步前一日的数据就得在3秒内完成。
然后就有点棘手了,相当于全节点服务单个SPV客户端时,读取并过滤数据的速率要在167GB/秒。或者说不停歇的维持这个速率,因为不止这一个SPV客户端需要服务的呀。别忘了,一个SPV客户还很贱的连着4个全节点,那么,全节点的处理速度还得乘以4,就是3333GB/秒。这种吞吐能级的单个存储设备估计是外星人用的吧,RAID 0固态磁盘这种高级货,单个最大处理速度大概 600M/S左右呢。
想搞事情的话,就买5555 个RAID 0固态磁盘攒一大怪兽,一个400刀,内存1TB,能存储两日的数据,两天一换的话,单日成本111.1万刀(5555*400/2)。一年下来4 个多亿。
当然了,这笔账算得有点玩闹,下面我们朴实的算算节点成本。
假设10 万个全节点不用那么高级的硬盘,而且全都可以连接SPV客户端。再假设全节点可以服务1000个SPV客户端。
相当于网络有1亿个SPV客户端套接口,能同时支持2500万个SPV客户端。那么每个客户端每天有2160秒来同步区块链。接着全节点的服务单个客户端时的读取速度为231MB/秒,那么服务1000个客户端的话,总速率是231GB/秒。
10TB的驱动器要400刀,那么一套价值40万刀的RAID驱动器能存储20天的区块链数据,一年下来是720万刀左右。

这里要说一下,正常人不会搞这种RAID 0怪兽的,一旦某个驱动器出故障,整个怪兽就瘫了。但是容错RAID阵列更贵,性能也不是很理想。另外这700多万刀是运行一个节点的年成本,很贵的。
另外,上面的假设都是以客户端老实排队同步为前提的,实际呢,网络上的同步活动会出现周期性的波峰波谷。因此,网络的处理能力特在波峰时,肯定时要于估计值的。
不然,网络高峰期铁出现一波同步失败的SPV 客户端。
有一点比较有趣,说,更改每个节点的套接口数量不会影响全节点的总体负载,意思是每个全节点需要处理的数据量不变。 这里边真正重要的是全节点与SPV客户端的比值。在这个方程中真正重要的是完整节点和 SPV 客户端的比例,还有全节点需要处理的区块大小。
结论是什么呢,十亿级用户的主张中,运行全节点的成本高的令人发指。
未完待续。
Could SPV Support a Billion Bitcoin Users? Sizing up a Scaling Claim - CoinDeskwww.coindesk.com

网友评论