你的钱在一个 L2 上。状态转移全部被零知识证明保证过,绝对正确,一个字节都没错。
然后排序器不再公布数据。
你的余额还在链上,正确无误。可你不知道它是多少,也就构造不出取款需要的那份证明。
钱在,你取不出来。
前三讲反复指向同一个问题。这一讲正面处理它。
一、把问题说准确
⚠️ “数据可用性(DA)“这个名字有误导性——它讲的不是"存储”,是"发布”。
⭐ 准确的问题:
一个区块生产者广播了区块头(含数据的承诺)。
他是否真的把【完整数据】发布出去了,
使得任何想要的人都能拿到?
⭐ 注意它不问"数据会不会被永久保存"。 它只问:在发布的那一刻,数据是否真的进入了公共可及的状态。
二、为什么这个问题特别难
它有一个反直觉的性质:无法被归责。
❌ 方案一:让节点举报"我没收到数据"
⚠️ 一个恶意节点可以在数据明明发布了的情况下谎称没收到。
⟹ 无法区分"数据真的没发"和"这个人在撒谎"
❌ 方案二:让发布者签名承诺"我发布了"
他可以【只发给一部分人】。
收到的人说"发了",没收到的人说"没发"。
⟹ 从链上看,双方的证词无法裁决
❌ 方案三:谁没收到就罚发布者
那么任何人都可以通过谎称"没收到"来诬告发布者
打个比方
这三条路走不通的原因,可以用一句日常的话说清:“我没收到你的信"这件事,没法证明。
收到了,你可以把信拿出来。没收到,你拿不出任何东西——而拿不出东西,和"你在撒谎说没收到”,长得一模一样。
于是仲裁者面对两份互相矛盾的证词,手上没有任何可以裁决的材料。
⭐ 这被称为"渔夫困境(fisherman’s dilemma)":
对于"某件事没有发生"这类命题,不存在简洁的证明。
"这笔交易无效" —— ⭐ 可以证明(把交易和状态拿出来算一遍)
"这份数据没有被发布" —— 【无法证明】
⭐ 正因为无法归责,DA 不能靠惩罚机制解决,只能靠"让每个人自己去验证"——而这正是第五节采样方案的出发点。
三、它为什么是全部 L2 安全的地基
回顾前三讲,每一条都通向这里:
① Optimistic Rollup(第 27 讲)
⚠️ 没有数据 ⟹ 挑战者无法重算状态 ⟹ 生成不了欺诈证明
⟹ 排序器可以提交任意错误状态而无人能挑战
② ZK Rollup / Validium(第 26、28 讲)
状态转移是被证明过的,绝对正确。
但数据被扣留时,你【不知道自己的余额是多少】,
也就【构造不出提款所需的 Merkle 证明】。
⟹ 钱在链上,正确无误,而你取不出来。
③ 轻客户端(第 13 讲)
没有数据 ⟹ 欺诈证明无法生成 ⟹ SPV 无法被补救
⭐ 所以 L2 的分类,本质上就是按"数据发到哪里"来分的:
Rollup —— ⭐ 数据发到 L1 ⟹ 安全性 = L1 的安全性
Validium —— 数据在链下委员会 ⟹ 安全性 = 那个委员会
侧链 —— 数据在自己的链上 ⟹ 安全性 = 它自己的共识
四、朴素方案与它的代价
最简单的保证:让所有人都下载所有数据。
⭐ 这确实解决了问题——你自己下到了,就知道它可用。
但它把我们送回第 3 讲那个约束:T ≤ R / c
⟹ 数据量受限于普通人的带宽
⭐ 所以真正的问题变成:能不能在【不下载全部数据】的前提下,高置信度地确认它是可用的?
五、数据可用性采样
⭐ 既然"没收到"证明不了,那就别去证明它——换成每个人自己抽查几下。下面这一节的全部巧妙之处,是让"抽几下"这个廉价动作,能对"数据是否可用"给出极高的置信度。
朴素采样为什么不行
想法:每个轻节点随机抽查几个数据块。
⚠️ 攻击者只需藏起【1%】的数据,整块数据就无法完整重建。
而随机抽 30 次都没碰到那 1% 的概率是 0.99³⁰ ≈ 74%。
⟹ 大概率抽不到,采样几乎无效。
⭐ 根本问题:藏一点点就能造成致命破坏,而一点点很难被随机抽到。
纠删码把这个不对称扭转过来
把 n 个数据块,用 Reed-Solomon 码扩展成 2n 个:
⭐ 任意 n 个就能恢复出全部原始数据。
⟹ 攻击者要让数据【不可恢复】,
必须藏起【超过一半】的块(即多于 n 个)。
⭐ 这是整个方案的关键一步:它把"藏 1%“这个廉价攻击,变成了"必须藏 50% 以上”。
于是随机采样立刻变得极其有效:
攻击者藏起了超过一半的数据。
一个轻节点随机抽查 k 个位置,⭐ 全部命中"可用"部分的概率 ≤ (1/2)ᵏ
k = 10 ⟹ 约 1/1000
k = 20 ⟹ 约 1/100 万
k = 30 ⟹ 约 1/10 亿
每个轻节点只下载 30 个小块(几十 KB),就能以 10⁻⁹ 的错误率确认"数据可用"。
而且节点越多越安全:所有轻节点的采样合起来,实际上覆盖了全部数据——它们共同"托管"了这份数据,而没有任何一个人下载了全部。
还差一步:编码本身可能是错的
⚠️ 如果攻击者【故意错误地编码】,
那么"任意 n 个块可恢复"这个前提就不成立。
⟹ 你抽到的块都"可用",但拼起来是垃圾。
两种解决办法:
① 纠删码错误证明(fraud proof)
⚠️ 需要有人下载足够多的块来发现编码错误,
于是引入了二维纠删码:
按行列两个方向编码,使得"证明某一行编码错误"
只需要那一行的数据,而不是全部。
② 多项式承诺(KZG)—— 以太坊选的路
把每一行数据看成一个多项式,发布它的 KZG 承诺。
每个采样点都附带一个【常数大小】的证明,
证明"这个位置的值确实在承诺的多项式上"。
⟹ 编码正确性由密码学直接保证,根本不需要欺诈证明。
这就是第 8 讲提到的 KZG 在这里的真正用途,也是以太坊举办 14 万人可信设置仪式(第 28 讲)的原因。
六、EIP-4844:Blob
坎昆升级引入了一种专门承载 DA 数据的新载体。
一个 blob = 4096 个域元素 × 32 字节 = 128 KiB
每个区块目标 3 个 blob,上限 6 个(上线时的参数)
⭐ 三个关键设计:
① blob 数据不进入 EVM
合约只能看到 blob 的【versioned hash】(一个 32 字节的 KZG 承诺哈希),
⚠️ 无法读取 blob 的内容。
为什么:Rollup 根本不需要在合约里读这些数据——
它只需要"数据已发布"这个事实,以及一个能被证明绑定的承诺。
⟹ 于是数据不必进入状态,也不必被 EVM 处理,成本大幅降低。
② 独立的费用市场
blob 有自己的 blob gas 和 blob 基础费,
⭐ 与普通交易的 Gas 市场【完全解耦】,各自按 EIP-1559 式规则调整。
⟹ NFT 热潮推高普通 Gas 时,不会连带推高 Rollup 的数据成本
⟹ 反之亦然
⭐ 这是一个很好的机制设计:两种需求性质不同,就该有两个市场。
③ 约 18 天后删除
blob 只保留约 4096 个 epoch(约 18 天),之后节点可以删除。
这看起来很惊人——“数据被删了,还叫可用吗?”
回到第一节的定义就清楚了:
DA 保证的是"数据在【发布的那一刻】确实进入了公共可及状态",
⭐ 而不是"数据被永久保存"。
⟹ 只要在那 18 天里,所有关心的人(Rollup 节点、
挑战者、想提款的用户)都有充分时间取走它,
DA 的职责就完成了。
⟹ 长期存档是【另一件事】,由 Rollup 运营方、
区块浏览器、归档节点等自行负责——
而且它只需要 1-of-N 假设:只要有一个人还存着就行。
这个区分极其重要,因为它解释了为什么 DA 可以便宜:全网永久存储是昂贵的,而"保证发布 + 短期保留"便宜得多。
七、Danksharding 与 DA 层的选择
完整的 Danksharding 目标:⭐ 每个区块 32 MB 的 blob 数据,
而全节点【只做采样,不下载全部】。
⟹ 结合第 13 讲的无状态客户端,验证成本与数据量彻底解耦。
不同 DA 方案的安全性差异
| 方案 | 数据在哪 | 谁保证可用 | 安全性 |
|---|---|---|---|
| 以太坊 blob | L1 | 全体以太坊验证者 + DAS | 最高 |
| 独立 DA 链(如 Celestia) | 自己的链 | 它自己的验证者集 + DAS | 取决于该链的质押量 |
| DA 委员会(DAC) | 少数几台服务器 | 一个多签 | 等于那个多签 |
| 不发布 | 只有排序器有 | 无 | 等于信任排序器 |
⭐ 评估任何 L2 时,“数据发到哪里"是第一个该问的问题,而不是"用了 OP 还是 ZK”。
⚠️ 一个用 ZK 证明但把数据放在 5/8 委员会里的方案,
安全性上限就是那 5/8 委员会——
无论它的密码学多漂亮。
八、Go:纠删码与采样
package da
import "math"
// SampleFailureProbability 返回"数据不可恢复但采样全部通过"的概率。
// ⭐ 纠删码保证:攻击者要让数据不可恢复,必须藏起超过一半的块。
// 于是每次随机采样命中"可用部分"的概率 ≤ 1/2。
func SampleFailureProbability(samples int) float64 {
return math.Pow(0.5, float64(samples))
}
// SamplesNeeded 返回把失败概率压到 target 以下所需的采样次数。
func SamplesNeeded(target float64) int {
n := 0
for SampleFailureProbability(n) > target {
n++
}
return n // target = 1e-9 时约为 30
}
// NaiveSampleFailure 对照组:没有纠删码时的情况。
// 攻击者只需藏起 hiddenFraction(比如 1%),
// 而随机采样很难碰到它——这说明了纠删码为什么是必需的。
func NaiveSampleFailure(samples int, hiddenFraction float64) float64 {
return math.Pow(1-hiddenFraction, float64(samples))
}
// ─────────── Reed-Solomon 扩展(概念示意) ───────────
// Extend 把 n 个数据块扩展成 2n 个。
// 做法:把数据看成一个 n−1 次多项式在 n 个点上的取值,
// 再求出它在另外 n 个点上的值。
// ⟹ 任意 n 个点唯一确定该多项式 ⟹ 任意 n 个块可恢复全部。
// (与第 8 讲 Shamir 秘密分享是同一个数学原理。)
func Extend(data [][]byte, encode func([][]byte) [][]byte) [][]byte {
return encode(data) // 返回 2n 个块
}
// Recoverable 判断给定的可用块数是否足以恢复原始数据。
func Recoverable(availableBlocks, originalBlocks int) bool {
return availableBlocks >= originalBlocks
}
// MinHiddenToBreak 返回攻击者要让数据不可恢复至少需要藏起多少块。
// 扩展到 2n 之后,藏起 n+1 个才能让"任意 n 个"这个条件失效
// ——即必须藏起【超过一半】。
func MinHiddenToBreak(originalBlocks int) int {
return originalBlocks + 1 // 总共 2n 块,藏起 n+1 块
}
// ─────────── Blob 费用市场(EIP-4844) ───────────
const (
BlobSize = 131072 // 128 KiB = 4096 × 32 字节
TargetBlobsPerBlock = 3
MaxBlobsPerBlock = 6
)
// NextBlobBaseFee 用与 EIP-1559 相同的反馈规则调整 blob 基础费。
// 关键在于它是【独立市场】:普通交易拥堵不会推高 Rollup 的数据成本。
func NextBlobBaseFee(parentFee uint64, parentBlobs int) uint64 {
switch {
case parentBlobs > TargetBlobsPerBlock:
return parentFee + parentFee/8 // 上限约 +12.5%
case parentBlobs < TargetBlobsPerBlock:
if parentFee <= 1 {
return 1
}
return parentFee - parentFee/8
default:
return parentFee
}
}
// RetentionEpochs 是 blob 的保留期(约 18 天)。
// 删除不损害安全性:DA 保证的是"发布的那一刻数据公开可及",
// 而不是"永久保存"。长期存档是另一件事,
// 且它只需要 1-of-N 假设——有一个人还存着就够了。
const RetentionEpochs = 4096
九、本讲小结
- 数据可用性讲的是"发布",不是"存储"。 它只问:在发布的那一刻,数据是否真的进入了公共可及状态。
- ⭐⭐ 它无法被归责(渔夫困境):无法证明"某件事没发生"。举报可以撒谎,签名可以只发给一部分人。所以 DA 不能靠惩罚解决,只能靠每个人自己验证。
- 它是全部 L2 安全的地基:没有数据,欺诈证明生成不了;有效性证明再正确,你也构造不出提款所需的 Merkle 证明——钱在链上、正确无误,而你取不出来。
- L2 的分类本质上就是按"数据发到哪"划分的:Rollup 发到 L1、Validium 在委员会、侧链在自己链上。
- 朴素采样无效:藏起 1% 就能让数据不可恢复,而 30 次随机抽样有 74% 概率碰不到。
- ⭐⭐ 纠删码扭转了这个不对称:n 个块扩展成 2n,任意 n 个可恢复 ⟹ 攻击者必须藏起一半以上。于是 k 次采样的失败概率降到
(1/2)ᵏ——30 次采样、几十 KB,错误率约十亿分之一。 - 节点越多越安全:所有轻节点的采样合起来覆盖了全部数据,而没有任何一个人下载了全部。
- 还需保证编码本身正确:二维纠删码 + 错误证明,或 KZG 承诺直接用密码学保证(以太坊的选择,也是那场 14 万人仪式的用途)。
- EIP-4844 blob 的三个设计:数据不进 EVM(只暴露 versioned hash)、独立费用市场(NFT 热潮不再推高 Rollup 成本)、约 18 天后删除。
- 删除不损害安全性,因为 DA 保证的是"发布过"而非"永久存"。长期存档是另一件事,且只需要 1-of-N——有一个人还存着就够了。 这正是 DA 能便宜的原因。
- 评估 L2 时第一个该问的是"数据发到哪里",不是"用了 OP 还是 ZK"。 一个用 ZK 但把数据放在 5/8 委员会的方案,安全上限就是那个委员会。
思考题
- 用自己的话说清"数据可用性是发布而不是存储",并解释这个区分为什么让 blob 可以被删除。
- 为什么"某件事没有发生"无法被简洁证明?请构造一个具体的场景,说明举报机制会失效。
- 一个 Validium 的状态转移全部有 ZK 证明。运营者扣留数据时,你具体缺少什么、因而做不到什么?
- 没有纠删码时,攻击者藏 5% 的数据,你抽查 50 次碰到它的概率是多少?
- 有了纠删码后,为什么攻击者必须藏起一半以上?请从"任意 n 个块可恢复"推导。
- 要把失败概率压到 10⁻¹²,需要采样多少次?下载量大约是多少?
- 为什么"节点越多越安全"?请说明轻节点的采样如何共同覆盖全部数据。
- 攻击者故意错误编码会怎样?分别说明二维纠删码和 KZG 各自如何解决它,并比较代价。
- 为什么 blob 数据不让 EVM 读取?如果允许读取会带来什么问题?
- 一个 L2 宣称"我们用 ZK 证明,数据由一个 8 人委员会保管,其中 5 人签名即可"。请给出它的安全性上限,并说明它是不是 L2。