Flyclient 超轻节点
先回顾一下spv client
SPV client
运行区块链节点,需要将整条链下载下来,并从头到位验证一遍。随着区块链的延伸,整条链占用的空间会越来越大。为此而提出了轻节点的概念,最早 Bitcoin 论文提出了 SPV client。它不下载区块的完整内容,而只下载区块头,对链的工作量进行验证。如果 SPV client 从网络中获取到多个不同版本的链,它可以根据其工作量决定选择哪一条链。当需要验证交易时,只需获取交易的 Merkle Proof。就这样,大大节省了硬盘和带宽的占用。
而且这个方案很安全,没有人能欺骗 SPV client,除非它有超过 51% 的算力。但是由于 SPV client 没有下载并验证全部的交易,所以它只能基于一个假设:最长链的交易都是合法的。
虽然全部区块头的体积也会随着时间的延长而增大,但是情况比下载完整区块还是要好很多。Bitcoin 目前下载全部的区块头只需要几十兆,但是 Ethereum 则需要大约 4GB,因为它的出块间隔更短,区块头体积更大。所以以太坊的 SPV client 并不算轻。
Flyclient
假设区块个数为 n,Flyclient 不需要下载整条链的 n 个区块头以验证工作量,而只需要下载 log(n) 个。办法是将整条链的n 个区块头作为叶子,构建一个 Merkle Tree,并将其 Merkle Root 写入下一个区块的区块头。轻节点可以利用 Merkle Root 验证区块链的工作量。
首先,轻节点从网络中获取最新的区块头 Bn,假设:
- 轻节点连接了 2 个全节点,一个是正常节点,一个是恶意节点。恶意节点的算力与全部正常节点的算力的比值为 c,且 c<1。
- 轻节点从 2 个全节点那里分别获得 2 个不同版本的第 n 个区块的区块头 Bn。
- 区块链的 hashrate 不变;
抽查
接下来,轻节点需要对其工作量进行验证。由于恶意节点的算力与正常节点的算力比值为 c,所以它们能够生成合法区块(也就是 blockhash 低于要求的门槛的区块)的数量的比值也大致为 c。于是,如果轻节点随机抽查检查区块的工作量,恶意节点能够提供合法区块的概率为 c,检查 k 个位置的区块,每次都合法的概率为 c ^ k。如果 k 足够大,那么恶意节点每次都成功的概率就会很低。当发现至少一个不合法的区块,那就验证不通过,轻节点便放弃这条链。
不过如果恶意节点是从第 m 个区块开始分叉的(m<n),那么恶意节点的链在第 m 个区块之前都是合法的,而这个区块之后的区块合法的概率为 c。如果恶意节点分叉不久,那么恶意节点的链当中的非法区块其实会少。所以前述的随机抽查方法就很没有效率。
解决办法是基于 2 分法进行检查,以找到分叉的点。先检查第 2/n 个区块,如果 2 条链提供的结果相同,那么就检查从2/n到 n 之间的中间区块,如果相同,那么在继续取3/4 * n 到 n 之间的中间区块。直到找到不同的区块。
那么这个不同区块位于分叉点之后,且恶意节点在分叉点之后的区块仍然有 c 概率是非法的,然后使用前述的办法在此取件进行抽查验证工作量。
当抽查时,轻节点向全节点请求第 k 个区块头的时候,全节点需要返回:
- 第 k 个区块头的信息;
- 以及证明区块位于第 k 个位置的 Merkle Proof;
Merkle Proof 包括从第 k 个区块到 Merkle Root 之间所需要的所有 sibling,比如对于为了证明下面这个 Merkle Tree 的叶子 H(K),需要提供的 Merkle Proof 包含: H(L), H(IJ), H(MNOP), H(ABCDEFGH)。
position binding
全节点是否有可能随意返回其他任意位置的合法区块,以通过检查呢?
不行。
和 Vector commitment 一样,Merkle Tree 也具备 position binding 的功能。如果提供的区块位置不是 k,那么将无法得到正确的 Merkle Root,从而无法通过验证。当每 2 个 sibling 拼接以计算上一层节点的 hash 时,拼接顺序会影响其结果。其拼接顺序与叶子所处位置有关,由于 H(K) 所处的位置,决定它和 H(L) 拼接时,应该处于H(L)左边的位置。H(IJ)应该也处于H(KL)左边,H(MNOP)应该处于右边。
如果全节点返回其他位置的区块及其 Merkle Proof,那么拼接时会因为左右顺序出错,而无法得到正确的 Merkle Proof,从而无法通过验证。
验证交易
利用上述方法,轻节点便能分辨出哪条链是当前合法的、工作量最大的链。之后,当轻节点需要验证一笔交易时,需要获取:
- 这笔交易所在区块及证明这个区块的 Merkle Proof;
- 这笔交易在区块中的信息及其 Merkle Proof;