Binary Sparse Merkle Tree (BSMT)
Binary Sparse Merkle Tree (BSMT) 不仅仅是一种数据结构,它是解决区块链 “状态爆炸” 和 “高效验证” 矛盾的关键技术方案。它结合了 Merkle Tree 的验证能力和 Trie(前缀树)的寻址能力。
本文结构:通俗讲解->运行机制->代码实现
A 什么事是BSMT?
为了让你一听就懂,我们可以把 Binary Sparse Merkle Tree (BSMT) 想象成一个 “带有魔法的无限大仓库” 。
我们可以把它的三个名字拆开来理解:
1. Binary(二叉):这是“地图”
想象你要去仓库取东西,路标只有两种:“向左”(代表0)和 “向右”(代表1)。
所有的门牌号(Key)都是由0和1组成的。比如你要找门牌号 011 的柜子,你就走:左 -> 右 -> 右。
- 通俗点说: 只要知道门牌号(二进制),你就能顺着唯一的路径找到那个位置。
2. Sparse(稀疏):这是“魔法”
这是 BSMT 最核心的技术。
这个仓库理论上大到无穷大(比如有 个柜子,比宇宙里的原子还多)。
如果我们要真的造这么多柜子,地球都放不下。
魔法在于:
- 在这个无限大的仓库里,99.9999% 的柜子都是空的 。
- 对于空的柜子,我们 不造它,也不存储它 。
- 我们预先算好一个“空柜子的指纹”(Hash),凡是没东西的地方,直接用这个“空指纹”代替。
- 通俗点说: 这是一个 “懒人仓库” 。只有当你真的往某个柜子放东西时,我们才会在那一瞬间把去往那个柜子的路和柜子造出来。其他的空间都是虚拟的,不占地方。
3. Merkle Tree(默克尔树):这是“防伪锁”
仓库大门上有一把总锁(Root Hash)。
- 如果你偷偷改了哪怕最深处一个柜子里的东西,这把总锁的“指纹”就会立刻改变。
- 通俗点说: 它可以极快地证明“某样东西确实在这个仓库里”,而且没人动过手脚。
总而言之
它就是一个看起来有无限容量,但实际上只占用你存了多少东西的空间,且能随时极速验证数据真伪的超级数据库。
它解决了什么问题?
- 空间小: 哪怕树深达256层,如果你只存了3个数据,它占用的空间就只和这3个数据相关,而不是整个宇宙。
- 速度快: 验证数据是否存在非常快(顺着0和1走就行)。
- 甚至能证明“不存在”: 你顺着路走到某个位置,发现那是“空指纹”,就能立刻证明“这个数据确实不存在”(Non-inclusion proof),这在区块链里非常有用。
B 运行机制
好,我们继续用“魔法仓库”的比喻,把 BSMT (Binary Sparse Merkle Tree) 的具体运作流程拆解开来看。
首先你要记住一个核心规则:在这个树里,位置(Key)就是导航图。
比如你的 Key 是 101,那就代表:第一层向右走,第二层向左走,第三层向右走。
1. 存储:它是怎么做到“省空间”的?
普通的树是把所有节点都存进数据库,但 BSMT 是个“极简主义者”。
-
预计算空节点(Zero Hashes):
系统启动前,就已经算好了一套“空值表”。- 第256层(最底层)如果为空,Hash是 。
- 第255层如果左右孩子都为空(即孩子都是 ),那这一层的Hash就是 。
- …以此类推,算到根节点。
这些“空指纹”是永远不变的,不需要存进数据库,写在代码常量里就行。
-
只存有效路径:
当你要存一个数据时,BSMT 只会把从“根”到“叶子”这条路径上的非空节点 存到数据库(通常是 KV 数据库,如 LevelDB)里。- 如果一个节点的右边是空的? 数据库里不存右边,只记录“右边是默认空指纹”。
- 效果: 哪怕树有 256 层高,存一个数据只需要存 256 个节点(甚至经过优化压缩后更少),而不是存 个节点。
2. 更新(插入/修改):如何放入数据?
假设你要把 “苹果” 放入柜子 10...0(假设这是 Key)。
- 下沉(找位置):
从根节点(Root)出发,根据 Key(1 -> 右,0 -> 左…)一路往下走。 - 放置:
走到最底层的叶子节点,把“苹果”放进去。 - 上浮(重算指纹):
这是最关键的一步。你放了苹果,叶子的指纹变了。- 你需要算出新的叶子 Hash。
- 回到父节点,父节点的 Hash =
Hash(左孩子Hash, 右孩子Hash)。 - 注意: 如果左孩子是你刚改的,右孩子是空的,那就取
Hash(新左Hash, 预计算的空右Hash)。 - 一路向上计算,直到生成一个新的 Root Hash。
3. 证明存在(Merkle Proof):怎么证明“苹果”在里面?
你要向别人证明:柜子 10...0 里确实有“苹果”。你不需要把整个仓库给别人看,只需要提供一条“证据链”。
-
证据链(Proof)包含什么?
你需要提供从“苹果”所在位置,一直到树根的路径上,所有“另一侧”的兄弟节点的 Hash。- 比如:你要算你爸爸的 Hash,你需要你自己的 Hash + 你兄弟的 Hash。
-
验证过程:
验证者手里只有一个 Root Hash(可信的总指纹)。- 验证者拿着你给的“苹果”。
- 根据 Key(路径),配合你提供的“兄弟节点 Hash”,一层层往上算。
- 如果最后算出来的 Hash 等于 他手里的 Root Hash,那就证明:苹果确实在这个位置,且没有被篡改。
4. 证明不存在(Non-Inclusion Proof):怎么证明“没苹果”?
这是 BSMT 最厉害的地方。普通的 Merkle Tree 很难证明“没有”,通常需要把相邻的数据都拿出来由你来推断中间是空的,但 BSMT 很直接。
假设有人问:柜子 11...1 里有东西吗?
-
情况 A:路断了(遇到空子树)
你顺着1(向右)走,发现这里本该有个节点,但这棵子树全是空的(是一个预计算的空 Hash)。
证明: 你直接把这个“空 Hash”对应的兄弟路径给验证者。验证者一算,发现根 Hash 对得上,且路径指向的是个“空地”,那就证明该位置绝对没有数据。 -
情况 B:被占了(叶子节点不匹配)
你顺着路走到终点,发现里面确实有个东西,但它的 Key 是11...0,而不是你要找的11...1。
证明: 展示这个错误的叶子节点。验证者一看:路径是对的,但这只有11...0的数据,说明11...1没地方站了(位置冲突),所以 目标数据不存在。
总结一下流程
| 动作 | 核心机制 | 通俗解释 |
|---|---|---|
| 存储 | 剪枝 (Pruning) | 只有真的放了东西的柜子才会造出来,空的全部用“空气指纹”代替,不占硬盘。 |
| 更新 | 回溯重哈希 | 动了最下面的东西,要一层层往上汇报,直到大门上的总锁(Root)换成新的。 |
| 证明存在 | 兄弟路径 | “这是我和我每一级邻居的合影,你看最后能不能拼出那把总锁。” |
| 证明不存在 | 证明为空 | “你顺着路走,你看,那地方是一片荒地(默认空值),所以东西肯定不在那。” |
这就是为什么 BSMT 在区块链(如 CKB, Ethereum 2.0 的某些状态树)中很受欢迎:它又大(能存无限Key),又小(只占有效数据空间),还能极速证明“有”或者“没有”。
C 代码实现(Go)
1 | package main |