教程区块链区块链基础知识chunk_21_ch08_scalability_pt1第 8 章 可扩展性三难困境与分片原理(8.1–8.2 节)

本页目录

目标:理解扩容的核心困境与所有主流技术路径,建立"分层/跨链"认知框架。

8.1 可扩展性三难困境(Scalability Trilemma)

8.1.1 三难困境的概念与起源

可扩展性三难困境(Scalability Trilemma)由以太坊创始人 Vitalik Buterin 于 2017 年系统提出,指出一条区块链在以下三个维度中最多只能同时满足两个

  • 去中心化(Decentralization):网络由大量独立节点共同维护,不存在单点控制。
  • 安全性(Security):系统在有恶意节点或攻击者时仍能保持一致性与活性。
  • 可扩展性(Scalability):系统能够高效处理更多交易(更高的 TPS)。

这一困境与分布式系统著名的 CAP 定理(一致性/可用性/分区容忍性)在思想上高度相似:三者无法兼得,工程的本质是在约束下做最优权衡

graph TD
    subgraph Trilemma
        A[去中心化
        Decentralization]
        B[安全性
        Security]
        C[可扩展性
        Scalability]
    end
    A --- B
    B --- C
    A --- C
    style A fill:#e1f5fe
    style B fill:#e8f5e9
    style C fill:#fff3e0
    A1[比特币、以太坊 L1] -- 安全+去中心化 --> A
    B1[联盟链、许可链] -- 安全+可扩展 --> B
    C1[Solana、Aptos 高 TPS 链] -- 去中心化+可扩展(争议) --> C

8.1.2 不同区块链的取舍与路径选择

现实世界中的主流公链恰好分布于三难三角形的各条边上:

系统类型去中心化安全性可扩展性典型代表说明
高去中心化 + 安全★★★★★★比特币、以太坊 L1~7 TPS / ~15 TPS,全网节点验证
高安全 + 可扩展★★★★★★联盟链(Hyperledger、R3 Corda)少量可信验证者
去中心化 + 可扩展(尝试)★★★★★★★Solana、Aptos硬件门槛较高,节点集中风险
graph LR
    subgraph 典型链的定位
        direction LR
        X1[比特币
        去中心化+安全
        牺牲可扩展] --- X2[联盟链
        安全+可扩展
        牺牲去中心化] --- X3[新兴 L1
        试图三者兼顾
        物理瓶颈限制]
    end
    style X1 fill:#e1f5fe
    style X2 fill:#e8f5e9
    style X3 fill:#fff3e0

8.1.3 物理与通信极限

三难困境并非纯粹的哲学命题,它有深刻的物理根基:

带宽瓶颈:若一条链要达到 NN 笔交易每秒(TPS),每个验证节点都需接收全部交易数据。数据量与 TPS 近似线性正相关。对于出块时间 TblockT_{block}、平均交易大小 StxS_{tx}、目标 TPS 为 λ\lambda,则节点所需的持续带宽为:

Breq=λStxB_{req} = \lambda \cdot S_{tx}

λ\lambda 达到数千甚至上万 TPS 时,普通家用宽带已无法胜任。

延迟限制:地理上分散的节点达成共识需要时间,其下界受光速约束。信息跨越半个地球(约 20,000km20{,}000\,\text{km})的最低时延约为:

TminDcnetwork_efficiency2×107m2×108m/s×0.5200msT_{min} \approx \frac{D}{c \cdot \text{network\_efficiency}} \approx \frac{2 \times 10^7\,\text{m}}{2 \times 10^8\,\text{m/s} \times 0.5} \approx 200\,\text{ms}

这仅是物理传输极限,叠加握手、验证、Gossip 传播,主网出块间隔通常以秒或分钟计。

验证者困境:在传统的全部节点广播验证模式下,若网络有 NN 个验证者,每出一个区块需进行 O(N2)O(N^2) 级别的 Gossip 通信。BLS 聚合签名可将签名验证的通信复杂度降到 O(N)O(N),但数据传播本身仍受限于 O(N)O(N) 的总带宽消耗。

graph TD
    P1[带宽瓶颈] --> P2[普通节点无法全量接收]
    P3[延迟限制] --> P4[光速下界约束共识速度]
    P5[存储膨胀] --> P6[链历史数据持续增长]
    P7[验证者困境] --> P8[N 节点 Gossip 开销]
    P2 & P4 & P6 & P8 --> C[单体链的可扩展性上限]

8.1.4 功能性分层的破局思路

面对三难困境,Celestia 等项目引入了模块化区块链(Modular Blockchain)的新视角:与其在单链内强行求解"三角不等式",不如将功能解耦后分层优化。

功能分层:一条链的工作可拆解为三层——

  • 数据可用性层(Data Availability, DA):确保交易数据可被下载和验证。
  • 执行层(Execution):运行交易并更新状态。
  • 结算层(Settlement):提供最终性、资产桥接和争议仲裁。
graph TD
    subgraph 单体链架构 Monolithic
        M1[执行] --- M2[数据可用性] --- M3[结算]
        M4[共识] --- M2
    end
    subgraph 模块化架构 Modular
        N1[Rollup 执行层] --- N2[Celestia DA 层]
        N1 --- N3[以太坊结算层]
        N2 --- N3
    end
    style M1 fill:#ffccbc
    style M2 fill:#ffccbc
    style M3 fill:#ffccbc
    style N1 fill:#b3e5fc
    style N2 fill:#c8e6c9
    style N3 fill:#fff9c4

Celestia 的核心洞察是:只要 DA 层足够去中心化且可扩展,Rollup 等执行层可以无限叠加,各自独立优化执行性能。此时"三难"从单链内部的硬约束,转化为跨层的工程调配

8.1.5 三难困境的现代再解读

时至今日,三难困境更应被理解为工程权衡的坐标系而非不可逾越的定理。当功能被分层后,每一层可以在其职责范围内"取二",通过组合逼近全局最优。

graph LR
    T[三难困境] --> E[工程权衡框架]
    E --> S1[链上扩容: 分片]
    E --> S2[链下扩容: Rollup / 状态通道]
    E --> S3[跨链扩容: 侧链 / 跨链桥]
    E --> S4[模块化分层: DA 层专业化]
    S1 & S2 & S3 & S4 --> Z[下一代高吞吐区块链生态]

【本节要点】

  • 可扩展性三难困境(去中心化/安全性/可扩展性最多取二)是区块链扩容的根本约束。
  • 物理瓶颈(带宽、延迟、存储、O(N2)O(N^2) 通信)使单体链的"三者兼得"极为困难。
  • 模块化思路将功能分层(DA/执行/结算),将"三难"从单链定理转化为跨层工程调配问题。

8.2 链上扩容:分片原理与以太坊设计

8.2.1 分片的本质思想

分片(Sharding) 最初源于传统数据库领域:当单台服务器无法承载全部数据与查询时,将数据集划分为多个子集(分片),由多台服务器并行处理。

移植到区块链中,分片的核心思想是将负载分散到多个并行子组,可分为三类:

  • 执行分片(Execution Sharding):不同分片各自处理一部分交易并维护子状态,最终跨片协调。
  • 数据分片(Data Sharding):所有分片共同承担数据存储与可用性,执行仍可在链下(如 Rollup)。
  • 共识分片(Consensus Sharding):验证者分组成委员会,各自负责对不同数据片段达成共识。
graph LR
    subgraph 单体链
        C1[节点1: 处理全部交易]
        C2[节点2: 处理全部交易]
        C3[节点3: 处理全部交易]
    end
    subgraph 分片链
        S1[分片A
        节点子集]
        S2[分片B
        节点子集]
        S3[分片C
        节点子集]
        S1 <-.->|跨片通信| S2
        S2 <-.->|跨片通信| S3
    end
    style C1 fill:#ffccbc
    style C2 fill:#ffccbc
    style C3 fill:#ffccbc
    style S1 fill:#c8e6c9
    style S2 fill:#c8e6c9
    style S3 fill:#c8e6c9

8.2.2 以太坊 2.0 的分片演进路线

以太坊的分片方案经历了重大转向:

  • 早期路线(2018–2020):计划部署 64 条执行分片链,每条有独立的 EVM 执行环境。跨片交易与状态同步极为复杂。
  • Danksharding 路线(2021 至今):放弃执行分片,转向数据可用性分片(Data Availability Sharding)。主链(信标链 + 以太坊 L1 EVM)负责结算与共识,而执行交给 Rollup。L1 的角色变为提供一个廉价、高吞吐的"数据仓库"——即 blobspace
gantt
    title 以太坊分片演进时间线
    dateFormat YYYY-MM
    section 阶段1
    执行分片 64 条链 :2018-01, 2021-06
    section 阶段2
    以 Rollup 为中心的路线图 :2020-11, 2021-11
    section 阶段3
    Proto-Danksharding (EIP-4844) :2022-01, 2024-03
    section 阶段4
    完整 Danksharding :2024-03, 2026-12

8.2.3 Proto-Danksharding(EIP-4844):Blob 交易

EIP-4844 于 2024 年 3 月 13 日(Dencun 升级)上线以太坊主网,引入了 blob 交易(Blob-carrying Transaction)。

Blob 与 Calldata 的区别

特性CalldataBlob
字节大小可变,逐字节定价固定 128KB(4096 字段元素 × 32B)
EVM 可访问性合约可直接读取合约不可直接读取,仅可获取 KZG 承诺
Gas 定价与普通 tx 竞争独立的 blob gas 市场
存储期限永久约 18 天后由共识节点丢弃
费用较贵便宜 5–10 倍
graph TD
    subgraph Blob 交易结构
        T1[以太坊交易头
        nonce, gas, to, value...]
        T2[Blob 数据
        128 KB 原始数据]
        T3[KZG 承诺
        48 字节]
        T4[KZG 证明
        48 字节]
        T1 --- T3
        T2 --- T3
        T3 --- T4
    end
    style T2 fill:#c8e6c9
    style T3 fill:#fff9c4
    style T4 fill:#e1f5fe

Python 模拟:Rollup 提交 blob 的基本流程

python
"""
模拟 Rollup 排序器向 L1 提交 blob 交易的基本流程。
仅展示概念性数据结构,不涉及真实密码学运算。
"""
import os
import hashlib
from dataclasses import dataclass
from typing import List, Tuple

# 模拟有限域元素(实际为 BLS12-381 标量域,此处用简化表示)
BLOB_SIZE = 4096  # 字段元素个数
FIELD_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001

@dataclass
class Blob:
    data: List[int]  # 4096 个有限域元素(0 ~ FIELD_MODULUS-1)

    @classmethod
    def from_bytes(cls, raw_bytes: bytes) -> "Blob":
        # 将任意数据填充后切分为 32 字节一组,映射为字段元素
        padded = raw_bytes.ljust(BLOB_SIZE * 32, b'\x00')
        elements = [
            int.from_bytes(padded[i*32:(i+1)*32], 'big') % FIELD_MODULUS
            for i in range(BLOB_SIZE)
        ]
        return cls(elements)

    def to_bytes(self) -> bytes:
        return b''.join(
            (el % FIELD_MODULUS).to_bytes(32, 'big') for el in self.data
        )

@dataclass
class KZGCommitment:
    """模拟 KZG 承诺:实际为 48 字节椭圆曲线点"""
    point: bytes  # 48 字节

@dataclass
class BlobTransaction:
    rollup_id: int
    blob: Blob
    kzg_commitment: KZGCommitment
    kzg_proof: bytes  # 评估证明
    versioned_hash: bytes  # 版本化哈希(用于 EVM 合约引用)

def mock_kzg_commit(blob: Blob) -> KZGCommitment:
    """模拟 KZG 承诺生成。真实实现需可信设置与 pairing 运算。"""
    h = hashlib.sha256(blob.to_bytes()).digest()
    return KZGCommitment(point=h[:48].ljust(48, b'\x00'))

def mock_kzg_proof(blob: Blob, commitment: KZGCommitment) -> bytes:
    """模拟生成评估证明。"""
    return hashlib.sha512(blob.to_bytes() + commitment.point).digest()[:48]

def versioned_hash(commitment: KZGCommitment) -> bytes:
    """EIP-4844 中:versioned_hash = hash(0x01 || commitment)"""
    return b'\x01' + hashlib.sha256(b'\x01' + commitment.point).digest()[1:]

def build_blob_tx(rollup_id: int, l2_block_data: bytes) -> BlobTransaction:
    blob = Blob.from_bytes(l2_block_data)
    commitment = mock_kzg_commit(blob)
    proof = mock_kzg_proof(blob, commitment)
    vh = versioned_hash(commitment)
    return BlobTransaction(
        rollup_id=rollup_id,
        blob=blob,
        kzg_commitment=commitment,
        kzg_proof=proof,
        versioned_hash=vh
    )

# 模拟 L1 合约对 blob 引用的解析
class L1RollupInbox:
    def __init__(self):
        self.blobs: List[BlobTransaction] = []

    def submit_blob(self, tx: BlobTransaction):
        # 真实合约验证:tx.kzg_proof 在预编译合约中验证通过
        assert len(tx.kzg_commitment.point) == 48
        self.blobs.append(tx)
        print(f"[L1] Rollup {tx.rollup_id} 提交 blob,versioned_hash={tx.versioned_hash.hex()[:20]}...")

    def get_blob_reference(self, index: int) -> Tuple[bytes, bytes]:
        tx = self.blobs[index]
        return tx.versioned_hash, tx.kzg_commitment.point

# 运行示例
if __name__ == "__main__":
    l2_data = b"Rollup batch: 1000 L2 txs from users A,B,C..." * 100
    tx = build_blob_tx(rollup_id=42, l2_block_data=l2_data)
    inbox = L1RollupInbox()
    inbox.submit_blob(tx)
    ref = inbox.get_blob_reference(0)
    print(f"[L1] 合约可访问的引用: versioned_hash={ref[0].hex()[:20]}..., commitment(len={len(ref[1])})")

8.2.4 数据可用性采样(DAS)原理

当 blob 数据量大(数 MB 级区块)时,要求每个节点下载全量数据既不现实也不去中心化。Danksharding 引入 数据可用性采样(Data Availability Sampling, DAS),让轻客户端通过随机采样极小片段来高概率确认全部数据已被发布。

编码方式:原始数据按 N×NN \times N 矩阵排列,对每行和每列应用 Reed–Solomon 纠删码扩展(例如从 NN 扩展到 2N2N),形成 2N×2N2N \times 2N 的二维矩阵。只要接收到超过 50%50\% 的行和列,即可重构全部数据。

DAS 概率模型:设恶意的出块者隐藏了比例为 qq 的数据,每个轻客户端随机采样 ss 个坐标,网络中有 LL 个独立采样的轻客户端。则所有轻客户端都未检测到隐藏的概率为:

Pmiss=qsLP_{miss} = q^{s \cdot L}
Pavailable=1qsLP_{available} = 1 - q^{s \cdot L}

qq25%25\%\~50%50\%(例如 q=0.25q=0.25),s=15s=15L=10,000L=10{,}000 时:

Pmiss=0.251500001090309P_{miss} = 0.25^{150000} \approx 10^{-90309}

这是一个天文数字级别的确信度。

graph TD
    subgraph 2D 纠删码矩阵
        direction TB
        M1[原始数据 N×N] --> M2[行 RS 扩展 → 2N] --> M3[列 RS 扩展 → 2N]
        M3 --> M4[扩展矩阵 2N×2N]
    end
    M4 --> DAS
    DAS[轻客户端随机采样少量坐标] -->|验证 Merkle 分支 / KZG 证明| OK{所有坐标可用?}
    OK -- 是 --> SAFE[高置信确认数据可用]
    OK -- 否 --> ALERT[发出数据不可用警报]

Python 模拟:DAS 检测概率

python
"""
模拟数据可用性采样(DAS)的概率计算与可视化。
展示:不同采样数 s 和轻客户端数量 L 下,数据隐藏被检测到的概率。
"""
import numpy as np
import matplotlib.pyplot as plt

def detection_probability(q_hide: float, samples_per_client: int, num_clients: int) -> float:
    """
    计算:在隐藏比例 q_hide 下,至少有一个轻客户端检测到缺失的概率。
    P_available = 1 - q_hide^(s * L)
    """
    total_samples = samples_per_client * num_clients
    return 1.0 - (q_hide ** total_samples)

if __name__ == "__main__":
    # 场景:出块者隐藏了 30% 的数据(q=0.3)
    q = 0.30
    sample_counts = np.arange(1, 31, 1)
    client_counts = [1, 10, 100, 1000, 10000]

    plt.figure(figsize=(10, 6))
    for L in client_counts:
        probs = [detection_probability(q, s, L) for s in sample_counts]
        plt.plot(sample_counts, probs, label=f'L={L} clients', lw=2)

    plt.axhline(y=0.9999999999, color='r', linestyle='--', label='1 - 1e-10 (极可信)')
    plt.xlabel('每个轻客户端的采样数 s', fontsize=12)
    plt.ylabel('检测到数据缺失的概率', fontsize=12)
    plt.title(f'DAS 检测概率(隐藏比例 q={q})', fontsize=14)
    plt.ylim(0, 1.05)
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.savefig('/home/hermes/workspace/07_tutorial/chunks/chunk_21_ch08_scalability_pt1/das_probability.png', dpi=150)
    print("图表已保存到 das_probability.png")

    # 打印关键数值参考
    print("\n关键数值参考(q=0.3, 每个客户端采样 s=15):")
    for L in [1, 10, 100, 1000, 10000]:
        p = detection_probability(q, 15, L)
        print(f"  L={L:>6}: P_detect = {p:.15f}")
graph LR
    subgraph DAS 流程
        D1[轻客户端1] -->|采样坐标 (3,7), (12,45)...| V[验证节点 / P2P 网络]
        D2[轻客户端2] -->|采样坐标 (8,2), (55,12)...| V
        D3[轻客户端 L] -->|采样坐标 (33,19), (4,88)...| V
        V -->|返回对应数据片段 + KZG 证明| C[客户端验证]
        C -->|全部通过| OK[置信度呈指数级收敛]
    end
    style V fill:#e1f5fe
    style OK fill:#c8e6c9

8.2.5 KZG 承诺(Kate, Zaverucha, Goldberg)

在 Danksharding 中,每个 blob 使用 KZG 承诺 替代传统的 Merkle 根作为数据的向量承诺(Vector Commitment)。KZG(以 Kate、Zaverucha、Goldberg 命名)基于椭圆曲线配对,具备以下关键优势:

  • 承诺大小固定:无论数据量多大,承诺始终为 48 字节(单个椭圆曲线点)。
  • 评估证明大小固定:证明任意一个点的取值仅需 48 字节
  • 验证高效:通过一次配对(pairing)运算完成验证。

数学原理:设多项式 f(X)=i=0dfiXif(X) = \sum_{i=0}^{d} f_i X^i 插值自 blob 数据(d+1=4096d+1 = 4096)。在可信设置生成秘密参数 τ\tau 后:

C=[f(τ)]1=i=0dfi[τi]1C = [f(\tau)]_1 = \sum_{i=0}^{d} f_i \cdot [\tau^i]_1

其中 []1[\cdot]_1 表示椭圆曲线 G1\mathbb{G}_1 上的点。对任意查询点 zz,证明者计算评估证明:

π=[f(τ)f(z)τz]1\pi = \left[\frac{f(\tau) - f(z)}{\tau - z}\right]_1

验证者通过一次双线性配对验证:

e(C[f(z)]1,[1]2)=e(π,[τz]2)e(C - [f(z)]_1, [1]_2) = e(\pi, [\tau - z]_2)
{#eq:kzg-verify}
graph TD
    subgraph KZG 生成与验证流程
        P1[证明者] -->|插值多项式 f(X)| P2[计算承诺 C]
        P2 --> P3[对查询点 z 计算 f(z)]
        P3 --> P4[计算证明 π]
        P4 -->|发送 (C, f(z), π, z)| V1[验证者]
        V1 --> V2[配对验证: e(C-[f(z)]₁, [1]₂) =? e(π, [τ-z]₂)]
        V2 -->|通过| V3[接受]
        V2 -->|失败| V4[拒绝]
    end
    style P2 fill:#c8e6c9
    style V2 fill:#fff9c4
特性Merkle 树KZG 承诺
承诺大小O(1)O(1)(32 字节)O(1)O(1)(48 字节)
单点证明大小O(logN)O(\log N)(~320 字节 @ 4K 叶节点)O(1)O(1)(48 字节)
多点评证明多个 log 证明,较大可聚合(更优)
密码学假设抗碰撞哈希离散对数 + 配对 + 可信设置
量子安全部分假设成立否(需后量子替代方案)

注:以太坊的 KZG 可信设置通过公开的 MPC(多方计算)仪式完成,参与者只要有一方诚实删除秘密参数,整体安全性即可得到保证。

8.2.6 PBS:出块者-建设者分离(Proposer-Builder Separation)

Danksharding 的大区块(可聚合多笔 blob 交易)对出块节点(Proposer)的硬件与带宽要求极高,存在中心化风险。为此,以太坊引入 PBS(Proposer-Builder Separation) 架构:

  • 建设者(Builder):专业的高性能节点负责收集交易、构建最优区块(含 MEV 提取、blob 打包),并生成区块头承诺。
  • 中继(Relay):可信中间层,接收多个 Builder 的区块头,验证区块有效性后仅向 Proposer 透露头信息。
  • 出块者(Proposer):普通验证者从 Relay 选择最优区块头并签名广播,无需实际构建或下载完整区块内容
graph LR
    B1[Builder 1] -->|提交区块头 + 出价| R[Relay 中继]
    B2[Builder 2] -->|提交区块头 + 出价| R
    B3[Builder N] -->|提交区块头 + 出价| R
    R -->|披露最高出价区块头| P[Proposer 出块者]
    P -->|签名广播区块头| N[P2P 网络 / 信标链]
    N -->|请求完整区块 body| B_w[获胜 Builder]
    B_w -->|发布完整 body| N
    style R fill:#fff9c4
    style P fill:#e1f5fe

PBS 的核心价值在于:它解耦了"谁有权提议"与"谁有能力构建",使得资源有限的个人验证者仍可持续参与出块,避免了因硬件门槛导致的验证者集中化。

8.2.7 Blob 生命周期与 Danksharding 出块流程全景

将上述各环节串联,可得到一个完整的 blob 生命周期:

  1. Rollup 排序器生成 L2 交易批次,插值为多项式,生成 blob 数据与 KZG 承诺
  2. Rollup 提交者向以太坊发送 blob 交易(含 KZG 承诺与证明),支付 blob gas 费用。
  3. Builder 从 mempool 收集多笔 blob 交易,构建聚合区块,连同出价提交给 Relay
  4. Proposer 从 Relay 获取最优区块头并签名广播。
  5. 信标链在共识中确认该区块,blob 数据通过 P2P 网络分发。
  6. 轻客户端执行 DAS:随机采样 ss 个坐标,验证数据可用。
  7. 18 天后,blob 数据被共识节点丢弃(历史数据由 Rollup 项目方或第三方存档节点保留)。
graph TD
    R1[Rollup 排序器
    生成 L2 批次] -->|插值多项式| R2[生成 Blob + KZG 承诺]
    R2 -->|Blob 交易| M1[Mempool]
    M1 -->|多笔 blob| B[Builder 构建聚合区块]
    B -->|区块头 + 出价| R3[Relay 中继]
    R3 -->|最优头| P[Proposer 签名广播]
    P -->|信标链确认| C[共识达成]
    C --> D[Blob 数据 P2P 分发]
    D --> DAS1[轻客户端1 DAS 采样]
    D --> DAS2[轻客户端2 DAS 采样]
    DAS1 & DAS2 -->|确认可用| OK[数据可用性保证]
    OK --> EXP[约 18 天后过期丢弃]
    style B fill:#c8e6c9
    style R3 fill:#fff9c4
    style P fill:#e1f5fe
    style OK fill:#b3e5fc

Python 模拟:Danksharding 出块流程的端到端简化

python
"""
模拟 Danksharding 完整出块流程的简化端到端过程。
"""
from dataclasses import dataclass, field
from typing import List
import random

@dataclass
class RollupBatch:
    rollup_id: int
    tx_count: int
    blob_hash: str
    kzg_commitment: str = "mock_commitment_48b"

    def build_blob_tx(self):
        return BlobTransaction(
            rollup_id=self.rollup_id,
            blob=Blob(data=[0] * BLOB_SIZE),
            kzg_commitment=KZGCommitment(point=self.kzg_commitment.encode()),
            kzg_proof=b'mock_proof_48b',
            versioned_hash=hashlib.sha256(str(self.rollup_id).encode()).digest()
        )

@dataclass
class BuilderBlock:
    builder_id: int
    bids: float  # ETH 出价
    included_blobs: List[RollupBatch]
    block_header: str = "mock_header"

@dataclass
class Relay:
    blocks: List[BuilderBlock] = field(default_factory=list)

    def submit(self, block: BuilderBlock):
        self.blocks.append(block)

    def get_best_header(self) -> BuilderBlock:
        return max(self.blocks, key=lambda x: x.bids)

@dataclass
class Proposer:
    proposer_id: int

    def propose(self, relay: Relay) -> str:
        best = relay.get_best_header()
        print(f"[Proposer {self.proposer_id}] 选择 Builder {best.builder_id} 的区块,出价={best.bids} ETH")
        return f"signed_header_for_{best.block_header}"

@dataclass
class LightClient:
    client_id: int
    sample_count: int = 15

    def das_sample(self, total_coordinates: int = 10000) -> List[int]:
        coords = random.sample(range(total_coordinates), self.sample_count)
        print(f"[轻客户端 {self.client_id}] 随机采样坐标: {coords}")
        return coords

def simulate_danksharding_block():
    
    # 1. 多个 Rollup 生成批次
    rollups = [
        RollupBatch(rollup_id=i, tx_count=1000 * (i+1), blob_hash=f"hash_{i}")
        for i in range(5)
    ]
    print("=== 1. Rollup 生成 L2 批次 ===")
    for r in rollups:
        print(f"  Rollup {r.rollup_id}: {r.tx_count} 笔交易")

    # 2. Builder 竞争构建区块
    relay = Relay()
    print("\n=== 2. Builder 竞争构建区块 ===")
    for b in range(3):
        included = random.sample(rollups, k=random.randint(2, 4))
        block = BuilderBlock(
            builder_id=b,
            bids=random.uniform(0.01, 0.5),
            included_blobs=included
        )
        relay.submit(block)
        print(f"  Builder {b}: 包含 {len(included)} 个 blob,出价={block.bids:.4f} ETH")

    # 3. Proposer 选择最优
    print("\n=== 3. Proposer 选择并签名 ===")
    proposer = Proposer(proposer_id=99)
    signed = proposer.propose(relay)

    # 4. 轻客户端执行 DAS
    print("\n=== 4. 轻客户端 DAS 采样 ===")
    clients = [LightClient(client_id=i) for i in range(10)]
    for c in clients:
        c.das_sample()

    # 5. 共识确认(模拟)
    print("\n=== 5. 信标链确认,blob 数据分发完成 ===")
    print("=== 6. 约 18 天后 blob 过期,由 Rollup 存档节点保留历史 ===")

if __name__ == "__main__":
    simulate_danksharding_block()

8.2.8 分片架构的安全性与攻击面分析

Danksharding 架构面对三类主要威胁:

攻击类型风险描述防御机制
数据扣留(Data Withholding)出块者承诺发布数据但只发布部分,导致 Rollup 无法重构状态二维 RS 纠删码 + DAS:只要少数诚实节点采样即可触发警报
无效数据(Invalid Data)Blob 中数据格式错误或无法被 Rollup 解析Rollup 自身的状态承诺 + 欺诈/有效性证明;L1 不验证执行正确性
KZG 可信设置风险若 MPC 仪式所有参与者合谋保留 τ\tau 的秘密,可伪造虚假承诺大规模公开 MPC 仪式(数万人参与),仅需至少一个诚实参与者销毁秘密
graph TD
    A[分片架构攻击面] --> A1[数据扣留]
    A1 --> A1D[防御: 2D-RS + DAS]
    A --> A2[无效数据]
    A2 --> A2D[防御: Rollup 自身欺诈/有效性证明]
    A --> A3[KZG 可信设置]
    A3 --> A3D[防御: 大规模 MPC 仪式]
    A --> A4[Builder 审查]
    A4 --> A4D[缓解: 抗审查列表 crList + 强制包含]
    style A1D fill:#c8e6c9
    style A2D fill:#c8e6c9
    style A3D fill:#c8e6c9
    style A4D fill:#fff9c4

【本节要点】

  • 分片的本质是将负载分散到并行子组;以太坊从"执行分片"转向"数据可用性分片(Danksharding)",执行由 Rollup 负责。
  • Blob 交易(EIP-4844)为 Rollup 提供廉价的数据空间,EVM 不可直接读取 blob,仅通过 48 字节 KZG 承诺引用。
  • 数据可用性采样(DAS)让轻客户端以指数级置信度确认大数据块的可用性,无需全量下载。
  • KZG 承诺提供定长(48 字节)的向量承诺与单点证明,是 Danksharding 高效性的密码学基石。
  • PBS 分离出块权与构建权,避免硬件门槛导致验证者中心化。

8.3 衔接预告:侧链与跨链桥

分片(第 8.2 节)是在同一安全域内通过协议层扩容。另一种思路是引入完全独立的侧链(Sidechain),通过跨链桥与主链交互。侧链可以拥有更快的出块速度、不同的共识算法,甚至独立的验证者集——但它也引入了桥的安全假设。第 8.3 节将从跨链桥的设计出发,分析侧链、多链互操作性与跨链通信协议的安全模型。

评论

0

评论加载中…

发表评论

0/2000