Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-7658: 轻客户端数据回填

信标节点同步历史轻客户端数据的机制

Authors Etan Kissling (@etan-status)
Created 2024-03-21
Discussion Link https://ethereum-magicians.org/t/eip-7658-light-client-data-backfill/19290

摘要

此 EIP 定义了一种在信标节点之间同步轻客户端数据的机制。

动机

轻客户端数据由信标节点收集,以协助轻客户端与网络同步。同步协议定义了一种在时间上向前同步的机制。但是,它不能用于向后同步。

收集轻客户端数据具有挑战性,因为信标节点需要访问相应的 BeaconStateSignedBeaconBlockBeaconState 在最初同步的检查点状态之前不可用,并且 SignedBeaconBlock 在 libp2p 上的保留期限有限。

此外,每个同步委员会周期EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH 个槽组成。为了支持诸如 Portal network 之类的归档服务以提供与后端无关的一致视图,有必要选择一个规范槽,以便为该周期导出代表性的轻客户端数据。应该以分散和独立的方式验证此类数据是否为规范和最佳数据。

为了支持轻客户端数据回填,此 EIP 建议在 BeaconState 中跟踪规范和最佳的 SyncAggregate。这个最小的添加允许证明导出的 LightClientUpdateLightClientBootstrap 也是规范和最佳的。

规范

本文档中的关键词 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, 和 “OPTIONAL” 按照 RFC 2119 和 RFC 8174 中的描述进行解释。

容器

新容器

SyncData
class SyncData(Container):
    # Sync committee aggregate signature
    sync_aggregate: SyncAggregate
    # Slot at which the aggregate signature was created
    signature_slot: Slot

扩展容器

BeaconState

从激活的分叉开始,新的字段被添加到 BeaconState 的末尾,以跟踪当前和前一个同步委员会周期的最佳同步数据。

class BeaconState(Container):
    ...
    # Sync history
    previous_best_sync_data: SyncData
    current_best_sync_data: SyncData
    parent_block_has_sync_committee_finality: bool

辅助函数

default_sync_data

def default_sync_data() -> SyncData:
    return SyncData(
        sync_aggregate=SyncAggregate(
            sync_committee_bits=Bitvector[SYNC_COMMITTEE_SIZE]()
            sync_committee_signature=G2_POINT_AT_INFINITY,
        ),
        signature_slot=GENESIS_SLOT,
    )

信标链状态转换函数

Epoch 处理

修改后的 process_sync_committee_updates

在同步委员会边界上,当前周期数据被移动到前一个周期。这允许证明前一个周期的轻客户端数据是规范的。

def process_sync_committee_updates(state: BeaconState) -> None:
    next_epoch = get_current_epoch(state) + Epoch(1)
    if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
        ...
        state.previous_best_sync_data = state.current_best_sync_data
        state.current_best_sync_data = default_sync_data()
        state.parent_block_has_sync_committee_finality = False

区块处理

区块处理被扩展以跟踪当前周期的最佳轻客户端数据。由于存在空槽的可能性,因此必须在覆盖块头之前对其进行跟踪;这允许跟踪在 next_sync_committee 最终确定后的确切块。

def process_block(state: BeaconState, block: BeaconBlock) -> None:
    process_best_sync_data(state, block)
    process_block_header(state, block)
    ...
新的 process_best_sync_data
def process_best_sync_data(state: BeaconState, block: BeaconBlock) -> None:
    signature_period = compute_sync_committee_period_at_slot(block.slot)
    attested_period = compute_sync_committee_period_at_slot(state.latest_block_header.slot)

    # Track sync committee finality
    # 跟踪同步委员会的最终性
    old_has_sync_committee_finality = state.parent_block_has_sync_committee_finality
    if state.parent_block_has_sync_committee_finality:
        new_has_sync_committee_finality = True
    elif state.finalized_checkpoint.epoch < ALTAIR_FORK_EPOCH:
        new_has_sync_committee_finality = False
    else:
        finalized_period = compute_sync_committee_period(state.finalized_checkpoint.epoch)
        new_has_sync_committee_finality = (finalized_period == attested_period)
    state.parent_block_has_sync_committee_finality = new_has_sync_committee_finality

    # Track best sync data
    # 跟踪最佳同步数据
    if attested_period == signature_period:
        max_active_participants = len(block.body.sync_aggregate.sync_committee_bits)
        new_num_active_participants = sum(block.body.sync_aggregate.sync_committee_bits)
        old_num_active_participants = sum(state.current_best_sync_data.sync_aggregate.sync_committee_bits)
        new_has_supermajority = new_num_active_participants * 3 >= max_active_participants * 2
        old_has_supermajority = old_num_active_participants * 3 >= max_active_participants * 2
        if new_has_supermajority != old_has_supermajority:
            is_better_sync_data = new_has_supermajority
        elif not new_has_supermajority and new_num_active_participants != old_num_active_participants:
            is_better_sync_data = new_num_active_participants > old_num_active_participants
        elif new_has_sync_committee_finality != old_has_sync_committee_finality:
            is_better_sync_data = new_has_sync_committee_finality
        else:
            is_better_sync_data = new_num_active_participants > old_num_active_participants
        if is_better_sync_data:
            state.current_best_sync_data = SyncData(
                sync_aggregate=block.body.sync_aggregate,
                signature_slot=block.slot,
            )

理由

如何对 SyncAggregate 进行排名?

该 EIP 重用了现有规范中的 is_better_update 函数。

回填协议如何使用它?

一旦数据在 BeaconState 中可用,就可以定义一个轻客户端数据回填协议,该协议服务于过去的周期:

  1. 来自请求的 period + 1 的 LightClientUpdate 证明 period 的完整性已最终确定。
  2. (1) 的 attested_header.beacon.state_root 处的 BeaconState.historical_summaries[period].block_summary_root + Merkle 证明。
  3. 对于请求的 period 内的每个 epoch 的槽 0 区块,相应的 LightClientHeader + 用于将该区块包含到 (2) 的 block_summary_root 中的 Merkle 多重证明。
  4. 对于 (3) 中 beacon.slotperiod 内的每个条目,用于构造 LightClientBootstrapcurrent_sync_committee_branch + Merkle 证明。
  5. 如果 (4) 不为空,则请求的 periodcurrent_sync_committee
  6. 来自 period 的最佳 LightClientUpdate(如果存在)+ Merkle 证明,证明其 sync_aggregate + signature_slot 被选择为 (1) 的 attested_header.beacon.state_root 中的规范最佳值。

只有 (6) 中的证明取决于 BeaconState 跟踪最佳轻客户端数据。此修改将确立 is_better_update 子集的逻辑,但不需要向 BeaconState 添加任何 LightClientXyz 数据结构。

向后兼容性

此 EIP 需要硬分叉,因为它引入了新的共识验证规则。

只有在硬分叉之后的轻客户端数据才能被证明是规范和最佳的。但是,在分叉转换块最终确定后,较早的轻客户端数据将无法再更改,并且可以使用哈希锁定。

安全考虑

版权

版权和相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Etan Kissling (@etan-status), "EIP-7658: 轻客户端数据回填 [DRAFT]," Ethereum Improvement Proposals, no. 7658, March 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7658.