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 定义了一种在信标节点之间同步轻客户端数据的机制。
动机
轻客户端数据由信标节点收集,以协助轻客户端与网络同步。同步协议定义了一种在时间上向前同步的机制。但是,它不能用于向后同步。
收集轻客户端数据具有挑战性,因为信标节点需要访问相应的 BeaconState
和 SignedBeaconBlock
。BeaconState
在最初同步的检查点状态之前不可用,并且 SignedBeaconBlock
在 libp2p 上的保留期限有限。
此外,每个同步委员会周期由 EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH
个槽组成。为了支持诸如 Portal network 之类的归档服务以提供与后端无关的一致视图,有必要选择一个规范槽,以便为该周期导出代表性的轻客户端数据。应该以分散和独立的方式验证此类数据是否为规范和最佳数据。
为了支持轻客户端数据回填,此 EIP 建议在 BeaconState
中跟踪规范和最佳的 SyncAggregate
。这个最小的添加允许证明导出的 LightClientUpdate
和 LightClientBootstrap
也是规范和最佳的。
规范
本文档中的关键词 “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
中可用,就可以定义一个轻客户端数据回填协议,该协议服务于过去的周期:
- 来自请求的
period
+ 1 的LightClientUpdate
证明period
的完整性已最终确定。 - (1) 的
attested_header.beacon.state_root
处的BeaconState.historical_summaries[period].block_summary_root
+ Merkle 证明。 - 对于请求的
period
内的每个 epoch 的槽 0 区块,相应的LightClientHeader
+ 用于将该区块包含到 (2) 的block_summary_root
中的 Merkle 多重证明。 - 对于 (3) 中
beacon.slot
在period
内的每个条目,用于构造LightClientBootstrap
的current_sync_committee_branch
+ Merkle 证明。 - 如果 (4) 不为空,则请求的
period
的current_sync_committee
。 - 来自
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.