模块化区块链与数据可用性层:Celestia、EigenDA、Avail 与 Rollup 的 DA 选型

从单体链的困境出发,系统拆解执行、结算、共识、数据可用性四层解耦的模块化架构。深入讲解 Celestia 的 1D/2D Reed-Solomon 编码与数据可用性采样 DAS 的采样安全性论证,EigenDA 基于 KZG 承诺与纠删码的设计及其与 EigenLayer 再质押的关系,Avail 的有效性证明与轻客户端方案。最后给出 Rollup 的 DA 选型路径:calldata、EIP-4844 blob 与外部 DA 层的成本量级对比、桥与 DA 承诺的安全边界,以及工程落地中的真实踩坑。

导语:把区块链拆成可以单独替换的零件

比特币和以太坊早期都是单体链(monolithic blockchain):一个节点同时负责执行交易、达成共识、保存状态、广播数据。这带来极简的安全模型,也带来了难以调和的扩容矛盾——想让吞吐翻十倍,就得让每个全节点多下载十倍数据、多验证十倍计算。模块化(modular)的思路是把这个整体拆成四层:执行(Execution)、结算(Settlement)、共识(Consensus)、数据可用性(Data Availability,DA),每层独立演进、独立扩容,彼此通过明确的接口连接。Rollup 就是最早的模块化实践:执行搬到链下,结算与共识留在以太坊。而拆层之后,最先撞到天花板的不是执行,而是数据可用性——如果没人能拿到交易数据,执行再快也无法验证状态,桥也无法安全提款。

一句话总结:模块化的价值在于把「不可能三角」拆成三个各自独立的三角;而 DA 层是模块化架构的信任基石,它决定了 Rollup 的安全下限到底由谁承担。


1. 从单体链到模块化:四层解耦

1.1 单体链的困境

单体链把四件事绑在一台机器上。它的优势非常明确:原子性。一笔交易从执行到最终确认只涉及一条链,不需要跨系统通信,不需要额外的信任假设。这也是为什么比特币与以太坊的安全模型如此干净——你运行一个全节点,就独立验证了一切。代价同样明确:

  • 执行扩容受限于最慢的全节点。要提高 TPS 只能提高区块 gas 上限,而 gas 上限越高,全节点的状态与带宽压力越大。
  • 无法局部优化。共识层想换一个更快的 BFT 算法,会牵动执行层的最终性语义;DA 想用纠删码降低存储,又会被共识层的区块传播逻辑限制。
  • 同质化竞争。所有单体链都在做同一件事:把通用计算塞进一个全局状态机,然后在「更去中心化」与「更快」之间反复取舍。

1.2 执行、结算、共识、数据可用性四层

模块化把职责切开,每层只回答一个问题:

层次回答的问题典型实现
执行层交易如何改变状态EVM、zkVM、SVM、Move VM
结算层状态承诺的最终性与争议裁决以太坊 L1、Rollup 结算合约、Sovereign Rollup 自结算
共识层交易顺序由谁决定Tendermint、以太坊 PoS、Celestia 的 CometBFT
数据可用性层数据是否发布且人人可取calldata、EIP-4844 blob、Celestia、EigenDA、Avail

关键在于接口而非实现。结算层只需要一个「状态根 + 数据承诺」的输入,至于这个状态根来自 EVM 还是 zkVM,来自单一排序器还是去中心化排序网络,结算层并不关心。

1.3 单体与模块化的对比

单体链(Monolithic):共识 + 执行 + 结算 + DA 全在一个节点
  优点:原子性、简单、安全假设少
  缺点:扩容只能靠堆硬件,无法局部替换

模块化(Modular):
  执行层 A ┐
  执行层 B ┼─ 状态根 + 数据承诺 ─▶ 结算层(争议裁决 / 有效性证明验证)
  执行层 C ┘                            │ 区块 + 数据承诺
                                        ▼
                          共识层 + DA 层(排序 + 发布 + 可采样)
  优点:各层独立扩容、可替换、可组合
  缺点:跨层信任假设、DA 成为新瓶颈、故障域变多

一句话总结:单体链用「一台机器做所有事」换取最简信任模型;模块化用「多套系统协作」换取可扩展性——代价是每一层的接口都变成新的攻击面。


2. 数据可用性:模块化架构的真正瓶颈

2.1 DA 到底承诺了什么

数据可用性包含两个不可分割的部分:

  1. 数据发布(Data Publishing):交易数据确实被写进了某个共识系统,且任何人都能读到。
  2. 数据可检索(Data Retrieval):在足够长的时间窗口内,任何诚实的参与者都能完整下载这些数据。

只满足第一条是不够的。如果排序器把数据的哈希发到链上,但把原始数据藏在自己手里,那么状态根无法被任何人独立重算、欺诈证明无法被构造、用户无法从 Rollup 合约中自行提取资金。这就是数据可用性问题,也是模块化架构中最隐蔽的风险:链上一切看起来正常,区块在出,哈希在更新,但数据已经丢失。

2.2 数据可用性攻击

一个典型的 DA 攻击流程:

1. 恶意排序器打包一批交易,计算出正确的状态根 R
2. 把状态根 R 提交到 L1 结算合约,但数据只发给少数共谋节点
3. 其他验证者看到 R 是合法的(哈希正确、签名正确)
4. 但没有人能重算 R,因为拿不到输入数据
后果:
  - 用户无法证明自己的余额(无法构造提款证明)
  - Optimistic Rollup 的挑战者无法构造欺诈证明
  - 数据在共识层「名义存在」,但事实上不可得

注意攻击的关键:数据缺失在链上是不可见的。L1 合约只能看到「某个承诺被提交了」,它无法判断这个承诺背后的数据是否真的可达。这正是为什么需要 DA 层,也是为什么 DA 层必须提供可验证的可用性证明,而不是仅仅提供一个存储服务。

三类 DA 方案的光谱:按信任假设从强到弱排列:

方案可用性由谁保证信任假设成本量级
链上 calldata以太坊全节点无需额外假设最高
EIP-4844 blob以太坊共识层(约 18 天保留)无需额外假设,但有时间窗低
数据可用性委员会 DAC委员会多数诚实需要信任 N 个节点极低
DA 层(Celestia/EigenDA/Avail)密码学采样 + 轻节点采样安全性 + 少数诚实节点低

DAC(Data Availability Committee)是最便宜也最脆弱的方案:它把「数据是否发布」变成了「委员会是否诚实」的人为判断。相比之下,Celestia 这类 DA 层试图用纠删码 + 采样把这个判断变成数学问题。

一句话总结:DA 层的核心任务是把「数据是否真的发布了」这个链上不可见的问题,转化为一个可以被轻节点用极少带宽概率验证的问题——这就是纠删码与数据可用性采样的全部意义。


3. Celestia:Reed-Solomon 编码与数据可用性采样

3.1 Celestia 的定位

Celestia 是一条只做共识与数据可用性的链:它不执行智能合约,不维护通用状态,只负责把交易按字节排序、发布,并让轻节点能够以极低成本验证「数据确实发布了」。执行交给 Rollup,结算可以由 Rollup 自己在以太坊上完成。这种极简定位让它能做一件单体链做不到的事:让区块大小随轻节点数量而不是全节点数量扩展——因为轻节点只需要下载极少量的随机采样,不需要下载整个区块。

3.2 1D Reed-Solomon 编码

Reed-Solomon(RS)是一种纠删码:把 k 个原始数据分片编码成 n 个分片(n > k),只要拿到其中任意 k 个就能还原原始数据。

1D Reed-Solomon 编码(扩展因子 2),原始数据 k = 4:
  把数据看作多项式 f(x) 在 x=0..3 处的取值:
    f(0)=d0, f(1)=d1, f(2)=d2, f(3)=d3
  在额外的 x=4..7 处求值,得到校验分片:
    扩展后 [d0, d1, d2, d3, p0, p1, p2, p3]   n = 8
性质:
  - 任意 4 个分片即可还原全部 8 个(含原始 4 个)
  - 需要隐藏超过 4 个分片,才能阻止还原
  - 冗余率 = n / k = 2,存储放大 2 倍

RS 编码的数学基础是有限域上的多项式插值:k 个点唯一确定一个次数 < k 的多项式,而任意 k 个点都能插值还原它。这是所有纠删码方案(包括 EigenDA、Avail、Celestia)的共同基石。

3.3 2D Reed-Solomon 与数据方块

一维编码有一个致命弱点:攻击者只需要隐藏 k 个特定分片(例如后半段)就能阻止还原,而采样节点如果恰好只采样到前半段,就无法察觉。二维编码解决了这个问题。

2D Reed-Solomon(扩展因子 2,k=4 示例)

步骤 1:原始数据排列成 k×k 方块
        d00 d01 d02 d03
        d10 d11 d12 d13
        d20 d21 d22 d23
        d30 d31 d32 d33

步骤 2:对每一行做 RS 扩展(横向补 4 列 r)
步骤 3:对每一列做 RS 扩展(纵向补 4 行)
        得到 2k×2k = 8×8 的扩展方块(右下角由行列共同决定)

关键性质:
  只要扩展方块中有 1/4 以上的分片可用,
  就能通过行列插值还原出整个方块。

这个「1/4 阈值」是整个 DAS 安全性论证的支点。攻击者想要阻止数据还原,必须隐藏超过 3/4 的扩展方块——而这会让任何随机采样以 3/4 的概率命中缺失分片。

3.4 数据可用性采样 DAS

DAS(Data Availability Sampling)让轻节点用 O(1) 的带宽获得 O(n) 级别的安全性保证:

轻节点(Light Node)的采样流程:
  1. 从网络获取区块头,读取数据方块的根承诺(data root)
  2. 随机挑选 s 个 (行, 列) 坐标
  3. 对每个坐标,向网络请求该分片
     - 若拿到分片,用 Merkle/NMT 证明校验它确实属于该根
     - 若在超时时间内拿不到,立即判定「数据不可用」,拒绝该区块
  4. 若 s 个分片全部成功获取,则接受该区块
  5. 采样结果通过 gossip 网络广播给其他轻节点
带宽成本:
  每个分片约 512 字节,s = 15 → 单次采样约 7.5 KB
  对比:下载整个 1 MB 的区块,成本高两个数量级

关键点在于轻节点不做任何全局判断:它只知道自己采样的那几个分片是否可得,然后把「我拿到了」这个事实广播出去。全网的轻节点各自独立随机采样,只要有一个轻节点采样失败并广播,网络就会拒绝这个区块。

3.5 采样安全性论证

把上面的直觉写成概率:

假设攻击者隐藏了扩展方块中比例为 h 的分片。
若要阻止数据还原(1/4 阈值),必须 h > 3/4。
因此每个随机采样「命中缺失分片」的概率 p ≥ 3/4。
单个轻节点采样 s 次全部命中可用分片(被欺骗)的概率:
  P(被欺骗) ≤ (1 - p)^s ≤ (1/4)^s
采样次数 s 与安全级别:
  s = 10  →  (1/4)^10  ≈ 2^-20  ≈ 百万分之一
  s = 15  →  (1/4)^15  ≈ 2^-30  ≈ 十亿分之一
  s = 20  →  (1/4)^20  ≈ 2^-40  ≈ 万亿分之一
网络级安全:只要全网有 N 个诚实轻节点独立采样,
攻击者要欺骗全网络的概率 ≤ (1/4)^(s·N)(独立采样假设下)

这套论证有两个必须强调的假设:网络同步假设——轻节点必须在超时窗口内完成采样,如果网络分区或对手能阻断特定轻节点的连接,采样会退化为「无法判断」,Celestia 的策略是无法判断时拒绝区块(fail-closed),这保证了安全性但会牺牲活性;以及诚实轻节点数量——DAS 的安全性依赖「至少存在一个诚实轻节点在执行采样并广播失败结果」,如果全网只有攻击者自己的节点在采样,安全性论证就失效了。

一句话总结:DAS 把「数据是否可用」这个全局问题,转化成「随机采样是否命中」这个局部问题——(1/4)^s 的概率下界让 7.5 KB 的带宽换来数十亿分之一的安全级别,代价是引入了网络同步与诚实节点存在性两个新假设。


4. EigenDA:KZG 承诺、纠删码与再质押安全

4.1 从 EigenLayer 说起

EigenLayer 的核心创新是再质押(Restaking):让已经质押在以太坊上的 ETH(或其流动性质押代币)再次被用于为其他协议提供经济安全。这些协议被称为 AVS(Actively Validated Services),EigenDA 就是 EigenLayer 生态中最重要的 AVS 之一。这带来一个与 Celestia 截然不同的安全模型:Celestia 是独立的一条链,有自己的验证者集合与代币,安全性来自自身共识;而 EigenDA 没有自己的链,安全性租用自以太坊的质押 ETH——作恶会被罚没(slashing)真实的 ETH。

4.2 EigenDA 的数据流

Rollup 排序器
     │  (1) 提交 blob(最大 16 MB)
     ▼
  Disperser(分发器)
     │  (2) 纠删码编码:把 blob 切分并 RS 扩展
     │  (3) 为每个分片生成 KZG 承诺 / 证明
     ├──(4) 把分片分发给 EigenLayer 运营商(Operators)
     │        每个运营商只存储自己负责的那部分分片
     ├──(5) 把 blob 头(KZG 承诺 + 长度 + 编码率)发布到链上
     ▼
  验证者 / 任意节点
        (6) 向运营商请求分片,用 KZG 证明验证分片与承诺一致
        (7) 若运营商签名不足或分片不可得 → 判定 DA 失败

与 Celestia 的对比是本质性的:Celestia 的轻节点采样,EigenDA 的验证者向运营商请求并验证承诺。前者靠概率,后者靠密码学 + 经济质押。

4.3 KZG 承诺如何让分片可验证

KZG(Kate-Zaverucha-Goldberg)承诺是一个多项式承诺方案:它允许承诺者把多项式 f 压缩成一个 48 字节的承诺 C,然后对任意点 z 给出一个简短的证明 π,证明「f(z) = y」。

在 EigenDA 中,这个性质被用来证明编码的正确性:

EigenDA 的 KZG 用法:

1. Disperser 把 blob 数据解释为多项式 f 的系数
2. 计算承诺 C = commit(f),发布到链上(48 字节)
3. 对第 i 个分片,Disperser 计算:
     证明 π_i = prove(f, x_i)   // 证明 f(x_i) = chunk_i
4. 运营商只存储 (chunk_i, π_i),不存储整个 blob
5. 任意验证者拿到 (chunk_i, π_i) 后:
     verify(C, x_i, chunk_i, π_i) → true/false

效果:
  - 验证者不需要下载整个 blob 就能验证分片是否属于承诺
  - Disperser 无法「承诺 A 却分发 B」——KZG 的绑定性阻止了这一点
  - 分片验证是 O(1) 的常数时间操作
// EigenDA 风格的 KZG 分片验证(伪代码,示意验证流程)
package da

import (
	"fmt"

	"github.com/ethereum/go-ethereum/crypto/kzg4844"
)

// Chunk 是运营商持有的数据分片及其 KZG 证明
type Chunk struct {
	Index uint64        // 分片在编码矩阵中的位置
	Data  []byte        // 分片数据
	Proof kzg4844.Proof // KZG 求值证明(48 字节)
}

// VerifyChunk 验证分片确实属于某个 blob 承诺
// 这是验证者对抗「承诺与分发不一致」的核心检查
func VerifyChunk(commitment kzg4844.Commitment, c Chunk) error {
	// 把分片数据映射到有限域上的求值点 y = f(x_index)
	point := kzg4844.Point(domainPoint(c.Index))
	var value kzg4844.Scalar
	copy(value[:], c.Data[:32])

	// KZG 求值验证:e(C - y*G1, G2) == e(π, x*G2 - H)
	// 一次 pairing 检查即可完成,无需下载整个 blob
	ok, err := kzg4844.VerifyProof(commitment, point, value, c.Proof)
	if err != nil {
		return fmt.Errorf("kzg verify error: %w", err)
	}
	if !ok {
		return fmt.Errorf("chunk %d 不属于该承诺,Disperser 存在欺诈", c.Index)
	}
	return nil
}

// VerifySampled 抽查一部分分片而非全量下载,与采样安全性同构
func VerifySampled(commitment kzg4844.Commitment, chunks []Chunk, n int) error {
	if n > len(chunks) {
		n = len(chunks)
	}
	// 注意:生产实现须使用密码学安全的随机源
	for _, c := range sampleRandom(chunks, n) {
		if err := VerifyChunk(commitment, c); err != nil {
			return err
		}
	}
	return nil
}

EigenDA 的安全边界:EigenDA 的信任假设与 Celestia 完全不同,理解这一点比记住参数更重要:分片可验证不等于数据可用——KZG 只能保证运营商拿到的分片与承诺一致,不能保证运营商真的保存了分片,可用性最终由「运营商签名集合的质押规模」保证,如果持有 2/3 以上质押的运营商串谋隐藏数据,DA 就失效了;罚没是事后惩罚——EigenLayer 的 slashing 需要经过争议期与治理流程,不是即时生效,攻击者在罚没生效前有一个时间窗口;安全成本随质押量线性增长——要让 EigenDA 的安全级别接近以太坊 L1,需要租用接近 L1 规模的质押,成本是持续性的。

一句话总结:Celestia 用纠删码 + 采样把可用性变成概率问题,EigenDA 用 KZG + 再质押把它变成经济问题——前者假设「至少一个诚实轻节点在采样」,后者假设「多数质押不会串谋」。


5. Avail:有效性证明与轻客户端

5.1 Avail 的架构

Avail 是另一条独立的 DA 链,定位与 Celestia 接近(只做共识与 DA),但在两个地方做了不同的工程选择:使用 KZG 承诺而非 Merkle 根作为数据承诺,从而可以用有效性证明(validity proof)替代欺诈证明来保证编码正确性;同时提供面向应用链的 DA 抽象,强调「应用链只需要把数据交给 Avail,Avail 保证数据可得且有序」。

5.2 有效性证明与 KZG 承诺

在 Celestia 的 2D RS 设计中,如果某个恶意区块生产者提交了一个没有正确做 RS 编码的数据方块(例如直接把随机数据当作校验分片),轻节点在采样时无法立刻识别——因为采样只能判断「分片是否可得」,不能判断「分片是否是正确的编码结果」。传统上这需要编码欺诈证明:有人下载整行数据,验证其不满足 RS 约束,然后提交证明。

Avail 用 KZG 把这个过程变成了主动的有效性证明:

Avail 的编码有效性保证:
  区块生产者提交数据时,必须同时提交:
    1. 扩展后数据方块的 KZG 承诺 C
    2. 对每个分片位置 i 的 KZG 求值证明 π_i
  验证者 / 轻客户端可以:
    - 对任意分片做 O(1) 的承诺验证,确认它是 C 所定义的编码的一部分
    - KZG 承诺绑定了一个低次多项式,而 RS 编码正是
      「在更多点上求值同一个低次多项式」,
      于是承诺本身就把编码正确性编码进了密码学假设
  效果:不需要下载整行、不需要欺诈证明窗口,
        编码正确性在分片层面即可验证

注意这里的关键洞察:RS 编码 = 同一个多项式在更多点上求值。因此只要承诺的多项式次数足够低(次数 < k),那么它在任意点的求值必然是「正确编码」的分片。KZG 承诺天然绑定了多项式次数,编码正确性就被免费获得了。

Avail 轻客户端与采样:Avail 的轻客户端同样是采样型的:

Avail 轻客户端流程:
  1. 只下载区块头(含 KZG 承诺、数据根、扩展参数)
  2. 随机采样 s 个分片位置
  3. 对每个位置:从 DHT 请求分片 → 用区块头里的承诺验证(O(1) 群运算)
     验证失败 → 立即广播「区块无效」
  4. 采样全部成功 → 接受区块头,信任其数据可用
与 Celestia 的差异:
  - Celestia:采样分片后用 NMT 证明校验位置(Merkle 路径,O(log n))
  - Avail:采样分片后用 KZG 承诺校验(常数时间,但依赖配对运算)
  - Celestia 需要编码欺诈证明兜底;Avail 用有效性证明前置规避

5.4 三家 DA 层的横向对比

维度CelestiaEigenDAAvail
架构定位独立 DA 链EigenLayer 上的 AVS独立 DA 链
共识机制CometBFT复用以太坊共识BABE/GRANDPA 系
编码方案2D Reed-SolomonReed-Solomon + KZG2D Reed-Solomon + KZG
数据承诺命名空间 Merkle 树KZG 承诺KZG 承诺
可用性验证采样 + 编码欺诈证明运营商签名 + KZG 分片验证采样 + KZG 有效性证明
安全来源自身验证者 + 采样概率再质押 ETH 的经济安全自身验证者 + 采样概率
出块间隔量级秒级分钟级批次秒级
典型适用场景通用 Rollup / 主权 Rollup高吞吐 Rollup、成本敏感应用链、需要有效性证明的场景

一句话总结:Celestia 与 Avail 都在解决「编码是否正确」这个采样无法覆盖的盲区,只是路径不同——Celestia 用欺诈证明事后兜底,Avail 用 KZG 有效性证明事前绑定;EigenDA 则干脆把可用性外包给有真金白银质押的运营商集合。


6. Rollup 的 DA 选型与成本对比

6.1 三种 DA 模式

对 Rollup 而言,DA 选型本质上是在「成本」与「安全假设」之间做权衡:

模式 A:Calldata(EIP-4844 之前的主流)
  数据写入 L1 交易的 calldata;成本每字节 16 gas(非零字节),最贵
  安全:完全继承以太坊 L1,无额外假设
  限制:与 L1 普通交易争抢区块空间,gas 费高时成本爆炸

模式 B:Blob(EIP-4844 之后)
  数据写入 blob,承诺(versioned hash)放进区块头
  成本:独立的 blob gas 市场,价格极低
  安全:完全继承以太坊共识,但数据约 18 天后被剪枝
  限制:每区块 6 个 blob 上限(目标 3),单 blob 128 KB

模式 C:外部 DA 层(Celestia / EigenDA / Avail)
  数据发布到独立 DA 层,只把承诺写入 L1
  成本:比 blob 更低,且不占以太坊区块空间
  安全:引入 DA 层自身的信任假设(采样安全性或再质押经济安全)
  限制:桥与提款逻辑需要额外验证 DA 承诺

6.2 EIP-4844 blob 的机制细节

理解 blob 的定价与生命周期是选型的前提:

EIP-4844 关键参数(Dencun 硬分叉引入):
  BLOB_SIZE            = 4096 个 field element × 32 字节 = 131072 字节(128 KB)
  GAS_PER_BLOB         = 131072(2^17)
  TARGET_BLOB_PER_BLOCK = 3
  MAX_BLOB_PER_BLOCK   = 6
  MIN_BLOB_GASPRICE    = 1 wei
  保留期               = 4096 个 epoch(约 18 天)
  定价机制:与 EIP-1559 同构,但使用独立的 blob gas 市场
    blob_base_fee 随超额 blob gas 指数上升;
    目标 3 个 blob / 区块 → 超出则价格指数上涨,低于则回落
  链上访问方式:
    - BLOBHASH 操作码(0x49):读取当前交易引用的 blob versioned hash
    - point evaluation 预编译合约(地址 0x0a):验证 KZG 求值证明
    - 执行层无法直接读取 blob 内容,只能验证承诺与求值证明

6.3 成本模型与量级对比

用一个具体的 Rollup 场景估算:每个批次发布 1 MB 数据。

场景:每个批次 1 MB 数据,ETH = 3000 美元,base fee = 20 gwei

【模式 A:calldata】
  1 MB = 1048576 字节,按 16 gas/字节:
    gas = 1048576 × 16 = 16,777,216 gas
    成本 = 16777216 × 20e-9 ETH = 0.3355 ETH ≈ 1006 美元
  → 每 MB 约 1000 美元量级

【模式 B:blob(EIP-4844)】
  1 MB 数据 = 8 个 blob(每个 128 KB)
    blob gas = 8 × 131072 = 1,048,576 blob gas
    最低价(1 wei/blob gas):成本 ≈ 1.05e-12 ETH ≈ 0.000003 美元
    blob base fee = 20 gwei 的紧张情况:成本 ≈ 0.021 ETH ≈ 63 美元
  → 常态下几乎免费,拥堵时约为 calldata 的 1/16
  → 相比 calldata 的降幅:常态下 5~8 个数量级,拥堵时约 16 倍

【模式 C:外部 DA 层】
  Celestia / EigenDA 的每 MB 成本通常在亚美元量级,
  且不占用以太坊区块空间,但需要额外支付 L1 上的承诺提交成本
  (一个 versioned hash / 承诺约 20~50 字节 calldata,可忽略)
  → 成本最低,但引入 DA 层信任假设

注意这里必须诚实地指出:blob 在最低价附近几乎免费是 EIP-4844 的设计结果(MIN_BLOB_GASPRICE = 1 wei),这在实践中造成了一个副作用——blob 空间长期处于极低利用率状态下的「免费」,而一旦出现批量发布的需求(如铭文类应用),blob base fee 会指数级飙升。成本估算必须同时考虑常态与拥堵两个区间。

6.4 blob 与 Celestia 的对比表

维度EIP-4844 blobCelestia DA
数据容量每 blob 128 KB,每区块最多 6 个(约 768 KB)区块大小可调,理论吞吐远高于 blob
定价市场独立 blob gas 市场,最低 1 wei独立手续费市场(TIA 计价)
数据保留约 18 天后剪枝长期保留(由 DA 层共识决定)
安全来源完全继承以太坊 L1 共识Celestia 验证者集合 + DAS 采样概率
桥的验证成本低:验证 blob versioned hash 即可需额外验证 DA 承诺与采样结果
提款安全假设与 L1 相同需信任 Celestia 的可用性保证
适用场景主流 Rollup 默认选择高吞吐应用链、成本极度敏感场景

6.5 合约侧的 DA 适配器

无论选哪种 DA,Rollup 的结算合约都需要一个统一的「DA 承诺校验」入口。下面是一个可切换 DA 后端的最小接口:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @notice DA 承诺的统一表示
/// @dev 不同 DA 后端的承诺形态不同,用 kind 区分解析方式
struct DACommitment {
    uint8 kind;         // 0 = calldata, 1 = blob, 2 = external DA
    bytes32 commitment; // calldata: keccak 哈希; blob: versioned hash; 外部: DA 层承诺
    uint64 dataLength;  // 原始数据长度(字节)
}

interface IDABackend {
    /// @notice 校验该批次的 DA 承诺是否有效
    function verifyCommitment(DACommitment calldata c) external view returns (bool);
    /// @notice 返回该后端的数据保留窗口(秒),用于桥的提款延迟设置
    function retentionWindow() external view returns (uint64);
}

/// @notice 基于 EIP-4844 blob 的 DA 后端
contract BlobDABackend is IDABackend {
    error BlobHashMismatch(uint256 index, bytes32 expected, bytes32 actual);

    function verifyCommitment(DACommitment calldata c) external view returns (bool) {
        if (c.kind != 1) return false;
        // 批次交易中第 0 个 blob 的 versioned hash 必须与承诺一致
        bytes32 h = blobhash(0);
        if (h != c.commitment) revert BlobHashMismatch(0, c.commitment, h);
        return true;
    }

    function retentionWindow() external pure returns (uint64) {
        // EIP-4844 保留期约 4096 epoch,按 12 秒/槽位、32 槽位/epoch 估算
        return 4096 * 32 * 12; // 约 18 天
    }
}

/// @notice 基于外部 DA 层(Celestia / EigenDA / Avail)的后端
/// @dev 需要 DA 层提供轻客户端或预言机把「采样结果」喂进合约
contract ExternalDABackend is IDABackend {
    address public immutable daAttester;
    uint64 private immutable _retention;
    mapping(bytes32 => bool) public attested;

    error UnauthorizedAttester(address caller);
    error CommitmentNotAttested(bytes32 commitment);

    constructor(address attester_, uint64 retention_) {
        daAttester = attester_;
        _retention = retention_;
    }

    /// @notice DA 层轻客户端把采样通过结果提交到链上
    /// @dev 生产实现须验证 proof(多签聚合 或 DA 层的有效性证明)
    function attest(bytes32 commitment, bytes calldata) external {
        if (msg.sender != daAttester) revert UnauthorizedAttester(msg.sender);
        attested[commitment] = true;
    }

    function verifyCommitment(DACommitment calldata c) external view returns (bool) {
        if (c.kind != 2) return false;
        if (!attested[c.commitment]) revert CommitmentNotAttested(c.commitment);
        return true;
    }

    function retentionWindow() external view returns (uint64) { return _retention; }
}

这段代码暴露了一个容易被忽略的设计要点:外部 DA 的 retentionWindow() 必须参与桥的提款延迟设置。如果 DA 层只保留 30 天数据,而 Optimistic Rollup 的挑战期是 7 天,那么任何依赖「数据在挑战期内可得」的提款逻辑都必须显式校验这个时间约束。

一句话总结:DA 选型不是「越便宜越好」——calldata 最贵但零额外假设,blob 便宜且继承 L1 安全但只有 18 天保留,外部 DA 最便宜但把安全外包给了另一个系统;正确做法是把 DA 后端抽象成可替换接口,并让保留窗口显式参与桥的安全参数。


7. 工程落地与踩坑

7.1 DA 适配器接口设计

从上面的合约可以看出,一个可维护的 DA 抽象需要满足三点:承诺格式统一(用 kind 字段区分后端,避免为每种 DA 写一套结算逻辑)、保留窗口可查询(让桥、挑战期、数据同步任务都能读取并据此调整参数)、验证可组合(把「承诺有效」与「数据可用」分成两个函数——前者是纯链上检查,后者依赖外部证明)。常见的架构错误是把这两件事混在一个 require 里,导致升级 DA 后端时必须重新部署整个结算合约。

7.2 blob 的过期与历史数据可用性

这是从 calldata 迁移到 blob 后最容易踩的坑:

问题:blob 数据约 18 天后被以太坊节点剪枝。
影响面:
  1. 新加入的全节点无法通过 blob 重放历史状态
     → 必须依赖其他节点提供的历史数据快照
  2. 需要历史数据的应用(区块浏览器、索引器、审计工具)
     必须在保留期内把 blob 数据落地到自己的存储
  3. 桥的提款验证如果依赖「重新下载 blob 数据」,18 天后会直接失效
正确做法:
  - 索引器在 blob 提交后立即拉取并持久化(含 KZG 证明校验)
  - 桥的验证逻辑只依赖「状态根 + 承诺」,不依赖重新下载原始数据
  - 明确记录每个批次的 blob 保留到期时间,作为运维指标

7.3 桥、DA 承诺与提款安全

DA 承诺与桥的安全耦合是最容易出事故的地方。三条必须遵守的原则:承诺必须绑定到批次,不能是全局变量——如果一个 DA 承诺可以被复用(例如只校验「某个根存在」而不校验「该根属于这个批次」),攻击者就能用旧批次的合法承诺为新的恶意批次背书;提款延迟必须不小于 DA 保留窗口的交集——当 Rollup 同时使用 blob 和外部 DA 时,取两者的最小值作为安全边界;DA 失败必须 fail-closed——轻节点在采样超时或网络异常时应判定「不可用」,而不是「乐观接受」,Celestia 与 Avail 的轻客户端都遵循这一原则,自研 DA 校验逻辑时必须显式实现。

7.4 采样安全性论证背后的假设

论文里的 (1/4)^s 很漂亮,但工程实现中有几个会削弱它的现实因素:

假设现实偏差缓解方式
采样位置真随机客户端 PRNG 被污染或复用种子使用系统级 CSPRNG,每次采样重新取种子
网络请求不可被阻断对手可对特定轻节点做连接级封锁多路复用请求、随机对等节点、fail-closed 策略
分片请求的诚实响应恶意节点可返回错误数据用 Merkle/KZG 证明校验每个分片
数据承诺绑定编码承诺与实际分发不一致KZG 绑定(EigenDA/Avail)或编码欺诈证明(Celestia)

生产踩坑清单:

  1. blob 数量硬编码。MAX_BLOB_PER_BLOCK 会随硬分叉调整,把 6 写死在合约或客户端里会在下一次分叉后失效。
  2. 忽略 blob base fee 的指数上涨。在拥堵期,blob 成本可能从近乎免费涨到超过 calldata 的估算值,成本模型必须有降级策略(例如回退到外部 DA 或延迟批次)。
  3. 把 DA 层的手续费代币与 ETH 混算。Celestia 的 TIA 价格与 ETH 独立波动,跨系统成本比较必须按实时汇率并做敏感性分析。
  4. 采样次数与安全级别不匹配。s = 5 时 (1/4)^5 ≈ 0.1% 的漏检概率在金融场景下不可接受,生产环境通常需要 s ≥ 15。
  5. 未验证分片的 Merkle/KZG 证明。只从网络拿到分片就当作有效数据,会让恶意节点用垃圾数据污染采样结果。
  6. DA 承诺与状态根分离提交。如果两者在不同的交易中提交,中间存在一个「状态根已确认但 DA 未确认」的窗口,攻击者可利用该窗口发起提款。
  7. 忽视 blobhash 的索引语义。blobhash(0) 读取的是当前交易引用的第 0 个 blob,在批次交易之外调用会返回 0,导致校验静默通过。
  8. 索引器未在保留期内落地数据。18 天窗口一旦错过,历史数据就永久丢失。

一句话总结:DA 层的工程风险几乎都集中在「承诺与数据的绑定关系」上——承诺必须绑定批次、分片必须验证证明、提款延迟必须覆盖保留窗口、失败必须 fail-closed,这四条守住了,模块化的信任假设才站得住。


8. 总结

  1. 模块化的本质是接口标准化:执行、结算、共识、DA 四层各自独立演进,Rollup 是最早的模块化实践,而 DA 层是拆层之后最先撞到的瓶颈。
  2. 数据可用性是链上不可见的风险:区块在出、哈希在更新,但数据可能已经丢失;DA 层的任务是把这个问题变成轻节点可概率验证的问题。
  3. Celestia 用 2D Reed-Solomon + DAS 采样:1/4 阈值让攻击者必须隐藏 3/4 的数据,从而让 s 次采样以 (1/4)^s 的漏检概率换取极高的安全级别。
  4. EigenDA 用 KZG + 纠删码 + 再质押:把可用性从概率问题变成经济问题,安全成本随租用的质押量线性增长,罚没是事后惩罚而非即时生效。
  5. Avail 用 KZG 有效性证明规避编码欺诈证明:因为 RS 编码就是「同一个低次多项式在更多点求值」,KZG 承诺天然绑定了编码正确性。
  6. Rollup 的 DA 选型是成本与信任假设的权衡:calldata 最贵但零假设,blob 近乎免费但只有约 18 天保留,外部 DA 最便宜但引入新的信任依赖。
  7. 工程落地的核心是承诺绑定:DA 承诺必须绑定批次、分片必须验证证明、提款延迟必须覆盖保留窗口、采样失败必须 fail-closed。

相关阅读


延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「blockchain」更多文章

  1. Rollup 序列器、L3 与应用链
  2. 账户抽象:ERC-4337、智能合约钱包与 Paymaster
  3. 零知识证明:zk-SNARKs、zk-STARKs、电路与隐私应用