时间回到2008年. 我想设计一个分布式的交易系统, 需要包含哪些功能?

可信任的分布式

首先需要支持在分布式的情况下, 系统不被任何个体控制. 在这个要求下, 系统本身不信任任何运行节点, 而是通过多个节点之间的”共识”来得到计算结果. 这就意味着, 如果某一个参与者控制了网络中的51%的节点, 就等于控制了整个网络. 这个问题目前看无解, 分布式信任下, 必须假设没有人能够控制51%的节点.

如何提高控制51%节点的难度呢? 这个就是架构设计的考虑点之一.

不可篡改

我们需要让已经发生的交易, 不能被任何人篡改. 这个设计上比较容易做到. 最简单的思路, 就是参考证书的信任链.

证书信任链首先假设, 根证书可信. 然后生成子证书后, 用根证书的私钥对子证书的公钥进行签名, 然后分发. 依此类推, 只需要公布根证书的公钥, 就可以一层层去验证证书链签发的文件的可信.

在区块链中, 我们不需要跟证书. 只需要用固定的哈希算法, 计算前一个区块的哈希, 称为哈希A. 然后将哈希A加上新增的数据, 计算出哈希B. 依此类推.

这样, 我们只需要保证最后一个区块没有被篡改, 然后通过验证哈希链, 就可以证明前面的所有区块都没有被篡改. 这样设计的好处是, 攻击者没有办法直接修改中间的一个区块. 如果要修改其中的一个区块, 就需要修改后面所有的区块.

计算难度

假设这样一种情况: 我就是要修改其中一个区块, 例如倒数第三个(记为M-3), 我需要怎么做?

首先, 我找到M-3, 修改其中的数据, 然后计算一个新的哈希H-3, 然后依次计算出H-2, H-1, H-0. 接着将H-0对应的最新区块M-0广播出去就行了.

如果其他人认可我的区块M-0, 那么篡改就大功告成.

为了避免这个问题, 我们需要设计一些简单有效的机制.

首先, 提高计算哈希的难度. 一种简单的方案是, 给我需要计算的数据末尾添加一些随机字节, 然后要求计算出来的哈希以N个0开头. 这样, N的数字越大, 计算的难度就越大, 避免了有人能够快速计算出符合要求的哈希链.

其次, 要求节点只认可接收到的最长的哈希链. 在N固定的情况下, 哈希链越长, 计算难度越大.

这样, 除非有人能够拿到接近51%的算力, 否则篡改不可行. 实际上, 算上运气, 篡改哈希链并不需要51%的算力, 只是越接近, 篡改成功的几率越大. 如果真的超过了, 从数学期望上来讲, 控制这个系统是必然的事情.

链的增长速度

一个好的系统, 应该具备各种稳定性. 我当然不需要我的区块链, 在某些时间段, 数据处理的速度特别快, 而在其他时候特别慢. 我也不需要外部世界的环境变化, 影响我的系统安全性.

如果上面的难度N是固定的, 那么可能发生这样一个情况: 根据摩尔定律, 每18个月, 计算机的速度会翻一倍. 这就意味着, 每过18个月, 我的系统里, 计算哈希的难度降低一倍. 9年之后, 计算哈希的难度降低到了1/100, 风险出现.

为了避免这个问题, 我的系统里, 难度N是会变化的. 首先每个区块本身需要带上生成的时间戳. 然后, 每个节点在确定难度N时, 需要根据过去的节点的生成时间, 来确定N的值. 简单来说, 目标就是让区块的生成时间平均下来是比较固定的. 如果过去的1000个区块生成的速度很快, 那就增大N, 反之就减小N. 最终达成一个速度的平衡.

计算和验证效率

如果区块希望包含完整信息, 区块通常是比较大的(例如2M). 如果每次尝试计算哈希的时候, 都需要将整个区块计算一次, 那么随着时间的累积, 对节点的要求会越来越高(存储成本). 我们希望网络中, 用来保证系统安全的节点只需要做简单的事情(计算哈希), 这样网络中符合要求的节点越多, 整个系统就越安全.

因此, 我们不应该需要所有的节点都本地存储全部的区块数据. 大多数节点只需要存储可以计算出哈希的数据即可. 少数节点存储全部的数据, 提供系统需要的功能.

但是当我的简单节点, 需要验证某些数据时, 我可以方便的去对我指定的数据进行验证, 这有什么办法可以实现呢?

有个好东西, 叫Merkle树. 原理很简单. 我有100组数据, D1-1到D1-100. 然后计算出100个哈希H1-1到H1-100. 将这些哈希以二叉树的形式, 每两个哈希计算出下一层的哈希H2-1. 依此类推, 最后我会得到一个H8-1. 为了验证D1的真实性, 我实际上只需要D1-1, H1-1, H1-2, H2-1, …, H8-1. 因为哈希计算是不可逆的, 我只需要验证H8-1是没有被篡改的, 那么D1-1就一定是没有被篡改的(其实H1-2也是没有被篡改的, 但是对我不重要).

所以, 简单节点并不需要拿到所有的数据来计算哈希, 而我的区块实际上也不是对原始数据计算哈希. 我只需要拿到H8-1, 这个Merkle树的根节点就行了. 通过区块链来保证H8-1这样的根节点的真实性, 就能保证所有的数据都是可验证的.

在实际的验证中, 我要验证一笔交易是否真实, 只需要将区块链中涉及交易付款方的地址的历史数据拉过来, 验证一遍Merkle树和区块链, 就能确保真实性, 而不需要本地拿到所有的区块数据.

其他

以太坊的原理 EOS的原理 solana的原理