Rollup 序列器、L3 与应用链

深入探讨 Rollup 序列器中心化风险与去中心化方案(Espresso、Astria、Metis),分析强制交易与逃生舱机制、L3 架构(Validium / 隐私链)与应用链设计权衡,并梳理数据可用性采样 DAS、排序器 MEV 与 PBS 以及 Base / Optimism 序列器架构。

导语:Rollup 的中心化之踵与去中心化的漫漫长路

Rollup 扩容方案解决了以太坊的吞吐瓶颈,但也引入了一个新的单点故障——序列器(Sequencer / 定序器)。目前大多数 Rollup(Optimism、Arbitrum、Base、zkSync)的序列器都由项目方中心化运营,负责接收 L2 交易、排序、执行并生成批次提交到 L1。这个中心化的角色拥有巨大的权力:审查交易、抢跑用户、提取 MEV。

与此同时,Rollup 的演进并未止步于 L2。L3(Layer3)和应用链(App Chain)正在把模块化区块链的粒度进一步拆分:稳定币项目可能想要自己的执行链,游戏项目可能需要秒级确认且零 gas 的专属环境。理解序列器、L3 与应用链的图景,是把握以太坊扩容路线图下一阶段的关键。

一句话总结:序列器是 Rollup 的"软肋"——当前绝大多数序列器都是中心化的,而去中心化、共享排序、L3 与应用链的探索,正在把以太坊的多层架构推向更深更细的模块化未来。


1. 序列器中心化问题

1.1 序列器的职责与权力

序列器的角色:

  用户提交交易      序列器                   L1 链上 Rollup 合约
       │             │                             │
       │ ── tx ─────►│  1. 接收交易并排序              │
       │             │  2. 在本地状态模拟执行            │
       │             │  3. 确认交易(soft confirmation) │
       │◄─ receipt ─ │  4. 构建批次                    │
       │             │  5. 压缩发布到 L1(calldata/blob)│─────►
       │             │  6. 提交新的状态根                │─────►

序列器拥有的权力包括:

  • 交易排序:决定哪些交易先执行,哪些后执行,哪些被叉掉重排
  • 审查:可以拒绝接收特定用户的交易
  • 抢跑:看到用户交易后,插入自己的交易获利(MEV)
  • 延迟:故意延迟某笔交易的确认
  • 软确认:在 L1 提交之前,序列器的确认虽然快但非最终(可被回滚)

1.2 中心化序列器的风险矩阵

风险描述后果
审查拒绝处理特定地址的交易用户无法与 L2 交互
MEV 提取序列器利用排序权抢跑/夹击用户滑点增加,资金损失
活性丧失序列器宕机或离线L2 无法处理任何新交易
状态回滚序列器提交错误状态根正确状态被覆盖,资金风险
监管合规序列器运营方被强制要求过滤去中心化承诺名存实亡

一句话总结:序列器的中心化是 Rollup 的"原罪"——它用单点控制换来了 UX 的极致优化,但也把 Rollup 的安全模型从"密码学保证"降级为"信任运营方"。


2. 去中心化序列器方案

2.1 Espresso Sequencer

Espresso 是一个共享的碎片化排序层,多个 Rollup 可以共用它来去中心化自己的序列器。

Espresso 架构:

  Rollup A   Rollup B   Rollup C   (多个 L2 共享同一排序层)
     │          │          │
     └──────────┴──────────┘
                │
        ┌───────▼────────┐
        │ Espresso HotShot │  HotShot 共识协议
        │   共识层          │  拜占庭容错 + 快速最终性
        └───────┬────────┘
                │
        ┌───────▼────────┐
        │ Espresso DA 层  │  数据可用性保证
        └───────┬────────┘
                │
                ▼
          L1(以太坊或其他 DA 层)

Espresso 的核心设计:

  • HotShot 共识:基于 HotStuff 的 BFT 共识协议,支持数千 TPS 的排序吞吐
  • 共享安全:所有连接 Rollup 共享同一组验证者,验证者经济激励互通
  • 可组合性:不同 Rollup 间的跨 Rollup 原子事务成为可能
  • Rollup 主权:Rollup 仍保留执行层和状态转换规则的自主权

2.2 Astria Sequencer

Astria 是一个构建在 Celestia DA 之上的去中心化共享序列器网络:

Astria 架构:

  用户交易
    │
    ▼
  Astria 序列器网络(基于 Tendermint 共识)
    │  对交易排序,生成"排序区块"
    ▼
  Celestia DA 层
    │  保证排序数据的可用性
    ▼
  L1(以太坊或其他结算层)
    │  验证 Rollup 的状态根和 fraud proof / validity proof
    ▼
  Rollup 执行节点
       从 Celestia 拉取排序交易,本地执行,维护状态

Astria 的独特之处在于排序与执行解耦:

  • Astria 只负责排序(sequencing),不负责执行
  • Rollup 执行节点自己从 DA 层读取交易顺序并执行
  • 这意味着不同的rollup 可以对同一笔排序数据采用不同的执行规则

2.3 Metis 去中心化序列器池

Metis 是率先在去中心化序列器方向落地的 L2 项目之一,采用**序列器池(Sequencer Pool)**机制:

Metis 序列器池:

  多个序列器节点组成一个轮换池
    │
    ├─ 质押 Metis 代币成为候选序列器
    ├─ 按质押权重或轮询机制选出当前活跃序列器
    ├─ 活跃序列器负责排序并提交批次到 L1
    └─ 如果活跃序列器作恶或离线,池子投票选出接替者

经济激励:
  - 序列器收取交易费(L2 gas 的一部分)
  - 作恶被检测会被质押罚没
  - 离线会被替换,质押可能被部分罚金

2.4 去中心化序列器方案对比

方案共识机制DA 层共享性成熟度
EspressoHotShot BFT自建 DA共享(多 Rollup)测试网阶段
AstriaTendermintCelestia共享(多 Rollup)测试网/早期主网
Metis轮询 + 质押投票以太坊专用(Metis 独占)主网上线
OP Stack 共享排序自定义以太坊共享(OP Chains)开发中

一句话总结:去中心化序列器的三种路线——共享排序层(Espresso/Astria)让多个 Rollup 共同使用去中心化基础设施,专用序列器池(Metis)让单个 Rollup 自治轮换——共同的瓶颈在于共识延迟和跨 Rollup 协调的难度。


3. 强制交易与逃生舱

3.1 逃生舱机制(Force Transactions / Escape Hatch)

在去中心化序列器完全成熟之前,Rollup 必须在合约层面保留一个"逃生舱":即使中心化序列器宕机或审查,用户仍然可以直接通过 L1 提交交易到 L2。

// Optimism Bedrock 风格的强制交易入口(概念简化)
contract L1Portal {
    // 用户直接向 L1 合约提交 L2 交易
    function sendMessageToL2(
        address target,
        uint256 gasLimit,
        bytes calldata data
    ) external payable {
        // 1. 从 L1 msg.value 中扣除足够的 gas 储备
        uint256 gasCost = gasLimit * L2_BASE_FEE;
        require(msg.value >= gasCost, "Insufficient ETH for gas");

        // 2. 生成唯一的消息哈希
        bytes32 messageHash = keccak256(abi.encode(
            msg.sender, target, gasLimit, data, block.timestamp
        ));

        // 3. 存入消息队列,等待 L2 序列器或服务节点纳入
        messageQueue.push(messageHash);

        emit MessageSent(msg.sender, target, messageHash, gasLimit, data);
    }

    // L2 序列器必须定期从 L1 读取此队列,否则证明系统无法闭合
}

3.2 逃生舱的延迟与安全

强制交易的时序(以 Optimism 为例):

时间 0:用户调用 L1Portal.sendMessageToL2()
    │
  ↓ ~L1 出块时间(12 秒)
    │
  消息写入 L1 区块
    │
  ↓ L2 序列器必须读取 L1 状态
    │
  序列器将消息纳入 L2 批次
    │
  ↓ L2 内部执行
    │
  交易在 L2 执行完成

延迟分析:
  - 最佳情况:1-2 个 L1 区块(约 15-30 秒)
  - 如果序列器离线:消息在 L1 上永久可查询,任何"恢复节点"都可以读取并执行
  - 资金安全性:用户可以确信,只要消息上了 L1,最终一定能在 L2 上执行
Rollup逃生舱机制延迟
OptimismL1→L2 Message Passing~15 秒(序列器在线)
ArbitrumRetryable Tickets~10 分钟
BaseL1→L2 标准桥~15 秒
zkSyncPriority Queue~数分钟

一句话总结:逃生舱是中心化序列器的"安全绳"——它不解决审查问题,但保证在序列器宕机时用户仍能取回资金;它的延迟虽然长,却给了 Rollup 安全模型一个不可被移除的底线。


4. L3 架构:Validium、隐私链与递归 Rollup

4.1 为什么是 L3

L2 解决了以太坊的吞吐问题,但引入了新的限制:

  • L2 的 gas 仍比理论上可能的最低成本高(需要考虑 L1 数据发布成本)
  • L2 需要服务所有 dApp,无法为特定用例优化
  • L2 的序列器和数据可用性是公共资源

L3(在 L2 之上构建的 Rollup)进一步分层:

模块化堆栈:

  L1(以太坊):结算 + 最终性 + 安全经济
    │
    ▼
  L2(通用 Rollup):继承 L1 安全,解决吞吐问题
    │  例如:Arbitrum One、Optimism、Base、zkSync Era
    ▼
  L3(应用链 / Validium / 隐私 Rollup):
    │  使用 L2 作为结算层,享受更低的成本
    │  可以高度定制:隐私、游戏引擎、特殊共识
    │  代表:Arbitrum Orbit、OP Stack Superchain 链、Starknet L3

4.2 Validium:链下数据存储

Validium 是 L3 的一种重要形态:它在链下(通常由数据可用性委员会或外部提供商)存储交易数据,只在链上提交状态根。

Rollup vs Validium:

Traditional Rollup:
  交易数据 → 压缩 → L1 calldata/blob(永久/半永久)
  任何人都可以从 L1 数据重放执行 → 高安全
  L1 gas 成本 → TPS 受限于 L1 数据带宽

Validium:
  交易数据 → 链下存储(DA 委员会、IPFS、Celestia)
  链上只提交零知识证明 + 状态根
  数据可用性依赖外部委员会 → 信任假设更强
  成本极低,TPS 极高 → 适合高频场景(游戏、支付)
维度RollupValidium
数据存储L1(calldata/blob)链下
安全性L1 等价(无额外信任)依赖 DA 委员会/外部层
成本中低极低
TPS数千数万
数据重放任何人可从 L1 重放需要委员会存活
适用场景DeFi、通用 dApp游戏、社交、高频支付

4.3 L3 递归证明架构

Starknet L3 / Polygon CDK 递归 Rollup:

  L3 交易
    │
    ▼
  L3 证明生成(L3 的 zk-prover)
    │  包含 N 笔 L3 交易的有效性证明
    ▼
  L2 验证 L3 证明 + 执行 L2 自身操作
    │
    ▼
  L2 证明生成(L2 的 zk-prover,包含 L3 证明)
    │  递归证明:证明"L2 状态正确"且"包含的 L3 证明也正确"
    ▼
  L1 验证 L2 证明

结果:
  L1 的一次验证 = 证明了 L2 的所有状态 + L2 中包含的所有 L3 的状态
  递归压缩了多层证明为一个简洁证明

一句话总结:L3 是"Rollup 之上的 Rollup"——用 L2 作为起点进一步缩减成本和提升定制性;Validium 用"弱 DA 假设"换取极致性能,适合不需要金融级安全的场景。


5. 应用链(App Chain)与通用 Rollup 的权衡

5.1 应用链的设计动机

为什么要为单个应用建一条链?

通用 Rollup 的限制:
  - 状态竞争:N 个 dApp 共享同一状态树,高峰期相互挤占 gas
  - 升级耦合:Rollup 的硬分叉/升级会影响所有 dApp
  - MEV 分享:通用序列器从所有交易中提取 MEV,dApp 无法独享
  - 定制困难:无法修改 opcode gas 表、预编译合约等

应用链的优势:
  - 完全控制:自定义虚拟机、自定义 gas 模型、自定义共识
  - 收入归属:交易费直接归应用方,不与其他 dApp 分享
  - UX 优化:可用账户抽象原生实现、原生 Session Key、零 gas 交易
  - 品牌独立:独特的区块浏览器、独特的用户体验

5.2 应用链技术栈对比

技术栈特点代表项目
Arbitrum Orbit基于 Arbitrum Nitro,一键发链Cometh, XAI
OP Stack基于 Optimism Bedrock,Superchain 愿景Base, Zora, Worldcoin
Polygon CDK支持 zkEVM 和 Validium 模式Astar, ImmutableX
Cosmos SDK + Celestia DA主权链 + 共享 DAdYdX v4, Neutron
Avalanche Subnets子网独立共识DeFi Kingdoms
Starknet StackCairo VM + 递归证明Madara, Kakarot

5.3 应用链 vs L3 的关系

应用链 ≈ L3(在以太坊扩容语境下)

细微差别:
  - L3 强调"Rollup on Rollup",使用 L2 作为结算层
  - 应用链可以是 L2、L3,甚至侧链(不完全继承 L1 安全)
  - "应用链"更强调"专用"而非"层级"

趋势:
  - 以太坊 L2 正从"通用为王"走向"专用链簇"
  - OP Stack 的 Superchain 和 Arbitrum Orbit 都在推动 One-Click Chain Launch

一句话总结:应用链不是 Rollup 的竞争对手,而是通用 Rollup 生态的补充——当 dApp 的规模大到足以支撑独立链的成本时,迁移到自有链可以释放 UX 和经济的全部潜力。


6. 数据可用性采样 DAS

6.1 L3 中的 DA 挑战

L3 和应用链大量使用链下 DA 以降低成本,但如何确保链下数据的可用性?

数据可用性方案演进:

链上 DA(安全性最高):
  L1 calldata → 永久存储,但贵
  L1 blob(4844)→ 临时存储,便宜 5-10 倍
  L2 calldata → 不适用于 L3

链下 DA(成本最低,但有信任假设):
  DA 委员会(DAC):N 选 M 机制
  Celestia / EigenDA / Avail:模块化 DA,轻节点采样

6.2 数据可用性采样(DAS)

Celestia 是模块化 DA 的标杆。它的 DAS(Data Availability Sampling)机制让轻节点无需下载全部数据即可高概率确认数据完整:

DAS 工作流程:

区块数据(例如 2 MB)
  │
  ▼
Erasure Coding(Reed-Solomon 编码)
  将 2 MB 扩展为 4 MB(2 倍冗余)
  任意 2 MB 即可恢复原数据
  │
  ▼
数据块分散到网络
  │
  ▼
轻节点随机采样 K 个 chunk(例如 30 个,每个只有几十字节)
  │
  ├─ 如果所有 chunk 都存在 → 高概率数据完整 → 接受区块
  └─ 如果某个 chunk 缺失 → 请求更多 chunk 或拒绝区块

安全性分析:
  - 攻击者要隐藏 2 MB 数据,必须隐藏超过 2 MB(因为冗余)
  - 随机采样的 K 个 chunk 全部"幸运"来自被隐藏部分的概率极低
  - K 越大,错误接受的置信度指数下降

一句话总结:DAS 用"随机采样 + 纠删码"的经济学保证替代了"全量下载"的性能消耗,让轻节点也可以独立验证 DA 而不信任任何全节点——这是模块化区块链信任假设最小化的关键使能技术。


7. 排序器 MEV 与 PBS

7.1 L2 中的 MEV

Rollup 序列器的排序权带来了与 L1 相同的 MEV(最大可提取价值)问题:

L2 MEV 类型:

三明治攻击(Sandwich):
  用户:买入 Token A
  序列器:先买入 → 推高价格 → 用户成交 → 序列器卖出套利

抢跑(Fronto-running):
  预言机更新交易 → 序列器提前执行套利交易

审查 MEV(Censorship MEV):
  拒绝包含竞争对手的交易

统计排序(Statistical Ordering):
  优先处理自家相关交易以最大化利润

7.2 PBS(Proposer-Builder Separation)在 L2 的适用

以太坊 L1 PBS:
  Builder 构建区块 → Proposer 选择出价最高的区块
  分离了"构建"和"提议"的角色,减少提议者的集权

L2 中的潜在方案:

方案一:共享排序层内置 PBS
  Espresso / Astria 等共享排序层:
    - 多个 Builder 竞标对交易包的排序权
    - 排序共识节点(Proposer)选择最优出价
    - 序列器本身成为 PBS 基础设施

方案二:Rollup 内部拍卖
  Rollup 运营方开放序列器权拍卖:
    - 谁出价高谁获得下一轮的排序权
    - 收入与 Rollup 代币持有者分享
    - 但需要信任拍卖机制本身

方案三:强制包含 + 延迟排序
  交易先提交到 L1(强制包含),排序在之后确定:
    - 序列器无法看到完整交易内容后再决定排序
    - 类似于加密 mempool(encrypted mempool)

7.3 Base 与 Optimism 的序列器架构

OP Stack(Base / Optimism)序列器架构:

  用户交易
    │
    ▼
  L2 Sequencer(中心化)
    │  - 排序交易
    │  - 执行并生成区块
    │  - 提供快速 soft finality
    │
    ├──► Batch Inbox(L1 合约)
    │      提交压缩交易批次
    │
    └──► Output Oracle(L1 合约)
           提交输出根(状态根承诺)

  未来路线图:
    - 阶段 1:中心化序列器(当前)
    - 阶段 2:多序列器轮询(Multi-sequencer rotation)
    - 阶段 3:去中心化共享排序(OP Stack Superchain 共享)
    - 阶段 4:社区治理的排序决策

一句话总结:L2 的 MEV 问题比 L1 更隐蔽但同样严重——序列器的垄断排序权是 MEV 的温床;PBS 和加密 mempool 是以太坊 L2 社区正在探索的方向,但技术和治理挑战仍很大。


8. 总结

  1. 序列器中心化:当前几乎所有 Rollup 的核心瓶颈,带来了审查、MEV 和活性风险
  2. 去中心化方案:Espresso(共享 BFT)、Astria(Celestia + Tendermint)、Metis(质押轮换)三条路线并进
  3. 逃生舱:中心化序列器的安全底线,强制交易保证用户始终能从 L1 与 L2 通信
  4. L3 与 Validium:Rollup 之上的分层,用信任换性能,游戏和高频场景优先
  5. 应用链:从"大一统 Rollup"到"千链齐发",OP Stack 和 Arbitrum Orbit 降低了发链门槛
  6. DAS:让链下 DA 可被轻节点验证,是模块化区块链信任最小化的基础设施
  7. PBS 与 MEV:序列器的排序权天然产生 MEV,PBS、加密 mempool 和去中心化排序是长期解法

相关阅读


延伸阅读


以下是一个 L3 / 应用链通信桥接架构的伪代码描述,演示 L3 如何通过 L2 与 L1 通信,以及去中心化序列器节点的交互机制。

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

// ═══════════════════════════════════════════════════════════════
// L3 ↔ L2 通信桥接与去中心化序列器协调(概念实现)
// ═══════════════════════════════════════════════════════════════

// L2 上的桥接合约:接收 L3 消息并转发到 L1
contract L2Bridge {
    address public sequencerRegistry;    // 去中心化序列器注册表
    mapping(bytes32 => bool) public processedMessages; // 防重放
    bytes32[] public messageQueue;

    event L3ToL1Message(bytes32 indexed messageHash, bytes payload, uint256 timestamp);

    // 仅允许注册的序列器提交 L3 批次
    modifier onlyRegisteredSequencer() {
        require(ISequencerRegistry(sequencerRegistry).isActiveSequencer(msg.sender), "Not sequencer");
        _;
    }

    // 序列器提交 L3 状态根和消息队列
    function submitL3Batch(
        bytes32 l3StateRoot,
        bytes32[] calldata newMessages,
        bytes calldata signature
    ) external onlyRegisteredSequencer {
        // 验证序列器签名
        require(
            ISequencerRegistry(sequencerRegistry).verifySequencerSignature(
                msg.sender,
                keccak256(abi.encodePacked(l3StateRoot, newMessages)),
                signature
            ),
            "Invalid sequencer sig"
        );

        // 添加到消息队列
        for (uint256 i = 0; i < newMessages.length; i++) {
            if (!processedMessages[newMessages[i]]) {
                processedMessages[newMessages[i]] = true;
                messageQueue.push(newMessages[i]);
            }
        }

        emit L3ToL1Message(newMessages[0], "", block.timestamp);
    }

    // 用户强制包含(逃生舱):绕过序列器直接提交
    function forceInclude(bytes calldata l3Transaction) external payable {
        require(msg.value >= FORCE_INCLUSION_FEE, "Insufficient fee");
        bytes32 hash = keccak256(l3Transaction);
        require(!processedMessages[hash], "Already processed");
        processedMessages[hash] = true;
        messageQueue.push(hash);
    }

    // 提款到 L1:用户在 L2 燃烧 L3 资产,到 L1 提取
    function initiateWithdrawal(address l1Recipient, uint256 amount) external {
        // 锁定 L2 上的 L3 桥接资产
        // 生成提款证明
        // 用户稍后到 L1 合约用证明提取
    }
}

// 去中心化序列器注册表
interface ISequencerRegistry {
    function isActiveSequencer(address sequencer) external view returns (bool);
    function verifySequencerSignature(address sequencer, bytes32 hash, bytes calldata sig)
        external view returns (bool);
}

contract SequencerRegistry is ISequencerRegistry {
    struct Sequencer {
        address addr;
        uint256 stakedAmount;
        uint256 lastActiveRound;
        bool isActive;
    }

    mapping(address => Sequencer) public sequencers;
    address[] public activeSequencerList;
    uint256 public currentRound;
    uint256 public constant MIN_STAKE = 1000 ether;
    uint256 public constant ROUND_DURATION = 100; // 区块数
    mapping(uint256 => address) public roundToSequencer;

    modifier onlyGovernance() {
        require(msg.sender == governance, "Not governance");
        _;
    }

    address public governance;

    constructor() {
        governance = msg.sender;
    }

    // 注册成为序列器候选
    function register() external payable {
        require(msg.value >= MIN_STAKE, "Insufficient stake");
        require(sequencers[msg.sender].addr == address(0), "Already registered");

        sequencers[msg.sender] = Sequencer({
            addr: msg.sender,
            stakedAmount: msg.value,
            lastActiveRound: 0,
            isActive: false
        });
    }

    // 轮询选择活跃序列器
    function electNextSequencer() external {
        require(block.number >= (currentRound + 1) * ROUND_DURATION, "Too early");

        currentRound++;
        uint256 index = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), currentRound)))
            % activeSequencerList.length;
        address selected = activeSequencerList[index];
        roundToSequencer[currentRound] = selected;
        sequencers[selected].lastActiveRound = currentRound;
    }

    function isActiveSequencer(address sequencer) external view returns (bool) {
        return sequencers[sequencer].isActive;
    }

    function verifySequencerSignature(address sequencer, bytes32 hash, bytes calldata sig)
        external pure returns (bool)
    {
        // ECDSA 签名验证
        return true; // 简化示意
    }

    // 惩罚作恶的序列器
    function slashSequencer(address sequencer, uint256 amount) external onlyGovernance {
        Sequencer storage s = sequencers[sequencer];
        require(s.stakedAmount >= amount, "Insufficient stake");
        s.stakedAmount -= amount;
        if (s.stakedAmount < MIN_STAKE) {
            s.isActive = false;
        }
    }
}

// L1 提款验证合约(L3 → L2 → L1 提款路径)
contract L1WithdrawalVerifier {
    mapping(bytes32 => bool) public withdrawals;

    // 验证 Merkle Proof 证明提款已在 L2 上发起
    function verifyAndWithdraw(
        address l3Token,
        uint256 amount,
        address recipient,
        bytes32[] calldata merkleProof,
        bytes32 l2StateRoot
    ) external {
        bytes32 leaf = keccak256(abi.encodePacked(l3Token, amount, recipient));
        require(_verifyMerkleProof(leaf, merkleProof, l2StateRoot), "Invalid proof");
        require(!withdrawals[leaf], "Already withdrawn");

        withdrawals[leaf] = true;
        // 释放 L1 上的对应资产给 recipient
        // IERC20(l1Token).transfer(recipient, amount);
    }

    function _verifyMerkleProof(bytes32 leaf, bytes32[] calldata proof, bytes32 root)
        internal
        pure
        returns (bool)
    {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }
        return computedHash == root;
    }
}

继续阅读

探索更多技术文章

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

全部文章 返回首页

「blockchain」更多文章

  1. 账户抽象:ERC-4337、智能合约钱包与 Paymaster
  2. 零知识证明:zk-SNARKs、zk-STARKs、电路与隐私应用
  3. 模块化区块链与数据可用性层:Celestia、EigenDA、Avail 与 Rollup 的 DA 选型