在Solana上,状态压缩是一种创建链下数据指纹(fingerprint
)(或哈希值)
并将此指纹存储在链上以进行安全验证的方法。
有效地利用Solana分类账的安全性来安全验证链下数据,确保其未被篡改。
这种压缩方法允许Solana程序和dApps使用廉价的区块链分类账空间, 而不是更昂贵的账户空间来安全存储数据。
这是通过使用一种特殊的二叉树结构(称为并发默克尔树)来实现的,
该结构为每个数据片段(称为叶子)创建一个哈希值, 将它们一起哈希,并仅将最终哈希值存储在链上。
什么是状态压缩?
简单来说,状态压缩使用“树”结构 以确定性方式将链下数据加密哈希在一起, 计算出一个单一的最终哈希值并将其存储在链上。
这些树是在这种“确定性”过程中创建的:
- 取任意数据片段
- 创建该数据的哈希值
- 将此哈希值作为树底部的叶子(
leaf
)存储 - 然后将每对叶子(
leaf
)哈希在一起,创建一个分支(branch
) - 然后将每个分支(
branch
)哈希在一起 - 不断向上攀登树并将相邻的分支哈希在一起
- 一旦到达树顶,生成最终的根哈希(
root hash
)
这个根哈希(root hash
)然后存储在链上,作为所有叶子数据的可验证证明。
允许任何人加密验证树内的所有链下数据,同时实际上只在链上存储最少量的数据。
因此,由于这种状态压缩,显著降低了存储/证明大量数据的成本。
默克尔树和并发默克尔树
Solana的状态压缩使用了一种特殊类型的默克尔树,
允许对任何给定树进行多次更改,
同时仍保持树的完整性和有效性。
这种特殊的树称为并发默克尔树,它有效地在链上保留了树的“变更日志”。 允许对同一棵树进行多次快速更改(即,在同一个区块中),在证明无效之前。
什么是默克尔树?
默克尔树,有时称为哈希树,是一种基于哈希的二叉树结构,
其中每个叶节点表示其内部数据的加密哈希值。
而每个非叶节点(称为分支)表示其子叶哈希的哈希值。
然后每个分支也被哈希在一起,攀登树,直到最终只剩下一个单一的哈希值。
这个最终的哈希值称为根哈希或“根”, 可以与证明路径结合使用来验证存储在叶节点中的任何数据片段。
一旦计算出最终的根哈希(root hash
),
存储在叶节点中的任何数据片段都可以通过重新哈希特定叶的数据和攀登树的每个相邻分支的
哈希标签(称为证明或证明路径)来验证。
将这个重新哈希与根哈希进行比较就是对基础叶数据的验证。
如果它们匹配,则数据被验证为准确。
如果不匹配,则叶数据已更改。
只要需要, 原始叶数据可以通过简单地对新叶数据进行散列并以与原始根相同的方式重新计算根散列来更改。
然后,使用此新根哈希来验证任何数据,并有效地使先前的根哈希和先前的证明失效。
因此,对这些传统 Merkle 树进行的每次更改都必须按顺序执行。
当使用默克尔树时,更改叶数据并计算新的根哈希的过程可能是非常常见的事情!
虽然这是树的设计重点之一,但也可能导致其中一个最显著的缺点:快速变化。
什么是并发默克尔树?
在高吞吐量应用中,例如在Solana运行时环境中, 验证者可能会相对快速地接收到更改链上传统默克尔树的请求(例如,在同一个插槽中)。
每次叶数据更改仍需按顺序执行。
导致每个后续更改请求失败,因为根哈希和证明已被插槽中的先前更改请求无效化。
引入并发默克尔树。
并发默克尔树在链上的每棵树特定账户 中存储了最近更改、其根哈希及其派生证明的安全变更日志。 这种变更日志缓冲区具有最大数量的变更日志“记录”(即最大缓冲区大小)。
当验证者在同一插槽中接收到多个叶数据更改请求时, 链上的并发默克尔树可以使用这个“变更日志缓冲区”作为更可接受证明的来源。
有效地允许同一棵树在同一插槽中进行最多最大缓冲区大小次更改。显著提高吞吐量。
并发默克尔树大小调整
创建这些链上树时, 有3个值将决定您的树的大小、创建成本和对您的树的并发更改数量: