本文档详细介绍了ePBS( enshrined Proposer-Builder Separation)的规范,旨在解决以太坊当前PBS实现中,提议者和构建者必须信任中间人的问题,通过移除“必须”这一强制性要求,并最小化改动,保持与共识层和执行层客户端的现有工作方式尽可能接近。
本文档配合此处的 ePBS 规范。它大量依赖于此处概述的设计约束。该文档中的一些定义和符号贯穿始终,尽管我们将尝试在此处回顾它们,以使本文档尽可能自包含。
由于下文详述的许多原因,ePBS 需要 EIP 7251 和 EIP 7002,适应这两个 EIP 所需的更改很简单,但将它们包含在这个简化的规范中会使阅读过于混乱,以至于很难区分实际由于 ePBS 导致的更改。我们将注意到需要在这方面进行更改的相关区域。
该规范解决了设计约束中详细说明的主要问题。
主要问题是,在以太坊中 PBS 的当前实现中
- 想要出售其构建 payload 权利的提议者必须信任中介。
- 想要购买构建 payload 的权利的构建者必须信任中介。
20%,但攻击者会丢失完整的 payload,这使得这种攻击毫无用处。
Slot的分配更加均匀,共识验证发生在第 0 秒,payload 验证发生在第 6 秒,包含列表验证发生在整个Slot中。
Blob 数据可以在信标区块揭示后立即广播,在看到证明之前以及 payload 揭示之前。数据可用性不再绑定到信标区块,而是绑定到 payload,从而针对由于数据不可用而导致的头部拆分视图提供更强的分叉选择保证。
允许(并鼓励)构建者打开与提议者的直接通信线路,从而避免了受信任中继跳的额外延迟。这些现在可以是无信任的,而无需构建者方面的任何投资。投标请求可以选择性地进行混淆,从而使拍卖有效地成为盲拍,并阻止使用中心化的受信任中继网络。
构建者 API 减少了一半的复杂性,因为不需要通过构建者进行盲区块流水线处理和完整区块的重新组装。构建者 API 简化为直接请求投标。
通过与构建者建立直接连接,验证者可以直接选择那些宣传为非审查的构建者。
客户端可以直接将影响主网的特定构建者列入活跃度事件的黑名单。
所有涉及的软件都由核心开发人员维护,并且可以在当前基础设施中测试所有边缘情况:spectests、kurtosis、CI 等,而无需依赖外部团队或黑盒的闭源软件。
在简要说明中,我们概述了主要的更改。在Slot解剖中,我们描述了Slot期间发生的事件。我们介绍了主要的新结构以及验证者需要生成区块和 payload 的方式的主要更改。在信标状态中,我们描述了信标状态结构中新增的字段。在信标区块的时间线中,我们描述了同步共识层区块的完整过程,从 Gossip 验证开始,直到区块被信标节点完全验证。在包含列表的时间线中,我们将介绍包含列表的必要验证,这是执行层参与的主要领域。在执行 payload 的时间线中,我们介绍了执行区块的验证流水线。在Payload 证明的时间线中,我们介绍了新的 payload 及时性证明验证。在诚实验证者的行为中,我们描述了验证者需要如何履行其职责,我们特别关注于如何选择链头以提议和证明 payload 的及时性的变化。在诚实构建者的行为中,我们描述了诚实构建者需要如何准备其投标并广播其 payload 或 payload 扣留消息。在分叉选择考虑中,我们包括了几个示例,说明在存在 PTC 证明,payload 提升和包含列表可用性条件的情况下,如何在分叉选择中计算 LMD 投票。在安全分析中,我们证明了上述关于在某些重组和扣留攻击下构建者和提议者的安全性的陈述。在无信任的优势中,我们描述了为什么该系统激励构建者打开自己的无信任端点,而不是依赖受信任的网络。在无条件支付中,我们证明了此属性,并深入探讨了本规范中未包含 EIP 7002 和 EIP 7251 的简化。在可选更改中,我们简要提及了一些可能对本提案进行的更改,而不会影响其核心属性。在与其他方法的比较中,我们提到了当前 ePBS 提案相对于将来可能应用的其他一些全面更改的优势。我们以快速的 FAQ结尾。
本规范中几乎没有任何内容最初归因于作者。这项工作的核心可以追溯到几年前,几乎没有变化。无数的研究人员和核心开发人员多年来一直在帮助积累关于我们面临的问题和不同设计权衡的知识。如果我们试图全部命名他们,肯定会侮辱到一些人。你们知道你们是谁!
目前的提案给验证者带来了新的职责或属性。这些是
提议者从构建者那里收集投标,并提交其信标区块,其中包含构建者揭示 payload 的已签名承诺。验证者立即从构建者那里扣除投标金额,并支付给提议者。证明者仅证明共识层区块。构建者稍后在Slot中揭示并广播其完整的执行 payload,从而履行共识区块的承诺。
Slot可以是错过的(未生成信标区块),空的(已生成信标区块但未揭示相应的执行 payload)和完整的(已生成两个区块)。共识层证明者在前两个和后两个之间进行选择,而 PTC 在后两个之间进行选择。
提议者将包含列表与其区块一起提交,这些包含列表包含下一个区块的构建者必须包含的交易,以使该区块有效。这些通常被称为 前向强制包含列表。
在 ePBS 中添加了三个新组件,并从 ePBS 中的信标区块提议中删除了两个组件。新增内容是 包含列表、执行 Payload 投标 和 Payload 证明。删除的内容是完整的执行 Payload 和 Blob 侧车(现在由构建者广播)。
在提议者预计构建并揭示其区块的Slot开始之前,提议者可以开始准备这三个新增内容。
一旦提议者知道它将提议下一个Slot,并且已经确定了他的头部,例如,如果当前Slot已满并且是规范的,这可能会在Slot开始前 6 秒发生,他可以请求完整的包含列表。这是一个 包含列表
对象。
class InclusionListSummary(Container)
proposer_index: ValidatorIndex
slot: Slot
summary: List[ExecutionAddress, MAX_TRANSACTIONS_PER_INCLUSION_LIST]
class SignedInclusionListSummary(Container):
message: InclusionListSummary
signature: BLSSignature
class InclusionList(Container)
signed_summary: SignedInclusionListSummary
parent_block_hash: Hash32
transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST]
交易列表和地址摘要是从本地 EL 通过引擎 API 获取的。然后,提议者填写共识信息并签署摘要。
提议者可以在Slot开始之前立即广播其 IL,以进行网络的快速验证。如果他愿意,他可以提交多个冲突的 IL。
在Slot开始之前,构建者可以开始通过 p2p 网络发送投标,或者提议者可以开始直接从构建者那里请求投标。投标包括 SignedExecutionPayloadHeader
对象。
class SignedExecutionPayloadHeader(Container):
message: ExecutionPayloadHeader
signature: BLSSignature
class ExecutionPayloadHeader(Container):
parent_block_hash: Hash32
parent_block_root: Root
block_hash: Hash32
builder_index: ValidatorIndex
slot: Slot
value: Gwei
blob_kzg_commitments_root: Root
它们包含足够的信息来:
需要父区块哈希和父区块根,因为在父完整区块和当前区块之间可能存在成功的 空的 共识区块。提议者的共识区块可以将它们中的任何一个作为有效区块,并且相应的状态根计算在每种情况下都会有所不同。
ePBS 中有一个新的委员会,由 PTC_SIZE
(512) 个验证者组成,如下所示,每个Slot都会进行证明。他们广播他们的证明作为 PayloadAttestationMessage
对象。
class PayloadAttestationData(Container):
beacon_block_root: Root
slot: Slot
payload_status: uint8
class PayloadAttestationMessage(Container):
validator_index: ValidatorIndex
data: PayloadAttestationData
signature: BLSSignature
我们选择使用与区块中包含的聚合版本不同的类型:
class PayloadAttestation(Container):
aggregation_bits: BitVector[PTC_SIZE]
data: PayloadAttestationData
signature: BLSSignature
下一个Slot的提议者侦听这些 payload 证明消息,并将它们聚合到 PayloadAttestation
对象中,以便打包到他们的 SignedBeaconBlock
中。
在Slot开始时,分配给该Slot的提议者准备并广播 SignedBeaconBlock
。为此,他们首先需要选择构建者的投标,并在其信标区块中包含相应的 SignedExecutionPayloadHeader
。提议者从其 EL 请求包含列表,如果他尚未这样做,则广播它。
在此期间,网络已经 Gossip 了 SignedBeaconBlock
和 InclusionList
。验证者将验证提议者的 SignedInclusionListSummary
签名,并将完整的包含列表转发给 EL 进行验证。验证者独立地在共识区块上运行状态转换函数以验证它。
在Slot的 3 秒时(或者一旦他们验证了共识区块和包含列表),验证者就会证明相应的信标区块和包含列表的存在。由于此时没有要验证的执行,因此此区块的验证在前合并时期很快。由于在此阶段不需要 blob 并且没有执行 payload 的区块本身更轻,因此传播也更快。
对于验证者而言,在证明方面没有新的要求。
在Slot时间的一半,同时发生两件事。
对于聚合器而言,除了截止日期从 8 秒缩短到 6 秒之外,没有任何变化。
另一方面,构建者一直在监视所有子网,并且到 6 秒时,应该清楚地知道网络是否已看到共识层区块的很大一部分。
如果诚实的构建者已经看到一个承诺其 payload 的共识区块,但该区块尚未被彻底投票,他们可以选择扣留他们的 payload。有关此的更多信息,请参见下文。
构建者将其执行 payload 作为 SignedExecutionPayloadEnvelope
对象发送。
class ExecutionPayload(Container):
# 执行区块头字段
parent_hash: Hash32
fee_recipient: ExecutionAddress # yellow paper 中的 'beneficiary'
state_root: Bytes32
receipts_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
prev_randao: Bytes32 # yellow paper 中的 'difficulty'
block_number: uint64 # yellow paper 中的 'number'
gas_limit: uint64
gas_used: uint64
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
base_fee_per_gas: uint256
# 额外的 payload 字段
block_hash: Hash32 # 执行区块的哈希
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
blob_gas_used: uint64
excess_blob_gas: uint64
inclusion_list_summary: List[ExecutionAddress, MAX_TRANSACTIONS_PER_INCLUSION_LIST]# [ePBS 中的新增内容]
class ExecutionPayloadEnvelope(Container):
payload: ExecutionPayload
builder_index: ValidatorIndex
beacon_block_root: Root
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
inclusion_list_proposer_index: ValidatorIndex
inclusion_list_slot: Slot
inclusion_list_signature: BLSSignature
payload_withheld: bool
state_root: Root
class SignedExecutionPayloadEnvelope(Container):
message: ExecutionPayloadEnvelope
signature: BLSSignature
信封包含与 EL 无关的所有信息,信标节点需要此信息才能在共识端处理 payload。本质上,它包含足够的信息来重新组装 SignedInclusionListSummary
以验证提议者的 BLS 签名,以及验证 CL 上 blob 数据可用性所需的 blob_kzg_commitments
列表。至关重要的是,信封包含一个新字段 payload_withheld
,以允许构建者诚实地扣留他们的执行 payload 并发出信号,表明他们已经看到一个不及时的共识区块。
执行 payload 本身与 Cancun 相比基本没有变化:我们添加了一个包含列表摘要(仅地址列表),EL 可以使用它来检查此摘要是否满足当前 payload。
需要 state_root
,因为处理执行 payload 现在是信标执行中的一个新的独立状态转换函数。这是从 payload 标头中取出的,因为它只能在共识区块成功同步后才能计算。这也意味着构建者无法广播他们的 payload,直到他们看到并完全验证了共识区块。
每个Slot,都会选择 512 个验证者来成为 payload 及时性委员会 (PTC) 的一部分。这些验证者在Slot的 9 秒时证明他们是否及时看到了预期的执行 payload。该委员会可以通过三种不同的方式进行投票。
payload_withheld = False
及时看到了相应的 payload,则他们投票 PAYLOAD_PRESENT
。payload_withheld = True
及时看到了相应的 payload,则他们投票 PAYLOAD_WITHHELD
。PAYLOAD_ABSENT
。这些证明会在全局主题上进行 Gossip。
因此,到Slot结束时,验证者已经导入并验证了包含列表、共识区块、单个位证明和聚合证明、payload 证明和完整的执行 payload。他们可以评估区块链的新头部。现在可以是以下三个选项之一:
每次我们同步信标区块和执行 payload 标头时,信标链状态都会被修改。主要结构 BeaconState
在 ePBS 中进行了修改,添加了以下内容并删除了一项:
class BeaconState(Container):
...
# latest_execution_payload_header: ExecutionPayloadHeader # [在 ePBS 中已删除]
...
# PBS
previous_inclusion_list_proposer: ValidatorIndex # [ePBS 中的新增内容]
previous_inclusion_list_slot: Slot # [ePBS 中的新增内容]
latest_inclusion_list_proposer: ValidatorIndex # [ePBS 中的新增内容]
latest_inclusion_list_slot: Slot # [ePBS 中的新增内容]
latest_block_hash: Hash32 # [ePBS 中的新增内容]
latest_full_slot: Slot # [ePBS 中的新增内容]
execution_payload_header: ExecutionPayloadHeader # [ePBS 中的新增内容]
last_withdrawals_root: Root # [ePBS 中的新增内容]
前四个条目是处理前向包含列表所必需的。新的条目 latest_block_hash
替代了旧的 latest_execution_payload_header
,后者从未完全使用。条目 latest_full_slot
记录此状态已处理执行 payload 的最后一个Slot。条目 signed_execution_payload_header
保留承诺到状态的最后一个构建者的投标,以强制对提议者进行无条件支付。最后一项新增内容是 last_withdrawals_root
,它记录了最新的提款消息的哈希树根,这些消息已在信标链中扣除,但尚未在执行层中兑现。每个字段的必要性将在接下来的部分中得到适当的解释。
一个 SignedBeaconBlock
首先通过它的 Gossip(或 RPC)流水线进入客户端。区块上没有进行新的验证,并且删除了与执行 payload 或 KZG 承诺有关的所有验证。唯一的添加项是父信标区块有效的要求。这在 Bellatrix 中由于乐观同步而被移除,但我们可以再次要求这样做,因为一个乐观同步的节点仍然会有一个有效的共识区块作为父区块。对于完全同步的节点,我们要求父执行 payload 得到完全验证。
on_block
处理程序在 Gossip 验证之后,节点对信标区块执行额外的验证。一个区块有两个不同的父区块,它有一个父共识层区块,由 block.parent_root
引用,并且它有一个父执行层区块,可以从信标区块体中的 signed_execution_payload_header
条目中提取。此结构已按如下方式更改:
class BeaconBlockBody(Container):
randao_reveal: BLSSignature
eth1_data: Eth1Data # Eth1 数据投票
graffiti: Bytes32 # 任意数据
# 操作
proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS]
attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS]
attestations: List[Attestation, MAX_ATTESTATIONS]
deposits: List[Deposit, MAX_DEPOSITS]
voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
sync_aggregate: SyncAggregate
# 执行
# 删除了 execution_payload [在 ePBS 中已删除]
# 删除了 blob_kzg_commitments [在 ePBS 中已删除]
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES]
# PBS
signed_execution_payload_header: SignedExecutionPayloadHeader # [ePBS 中的新增内容]
payload_attestations: List[PayloadAttestation, MAX_PAYLOAD_ATTESTATIONS] # [ePBS 中的新增内容]
从 header.parent_block_hash
条目中,我们找到哪个执行区块是当前区块的父 payload。从父共识区块的已提交执行 payload 标头中,我们检索两个不同的哈希,parent_header.block_hash
和 parent_header.parent_block_hash
。header.parent_block_hash
有两种可能的场景:
parent_header.block_hash
,在这种情况下,这个区块的父区块是一个 完整 区块。parent_header.parent_block_hash
,在这种情况下,这个区块的父区块是一个空的区块。任何其他结果都意味着传入的区块无效。如果父区块是一个 完整区块(分别是 空的 区块),我们会在同步父 payload(分别是父信标区块)之后获取后状态,这是我们传入信标区块的预状态。
在获取父状态之后,我们可以执行状态转换函数。ePBS 中修改了以下函数
def process_block(state: BeaconState, block: BeaconBlock) -> None:
process_block_header(state, block) #
removed process_withdrawals(state) [在 ePBS 中已修改]
process_execution_payload_header(state, block) # [在 ePBS 中已修改,删除了 process_execution_payload]
process_randao(state, block.body)
process_eth1_data(state, block.body)
process_operations(state, block.body) # [在 ePBS 中已修改]
process_sync_aggregate(state, block.body.sync_aggregate)
提款分两个步骤处理。在处理共识区块时,在状态转换期间,验证者的余额会扣除他们的提款金额。包含的下一个执行 payload 必须满足这些提款。
这种两步方法的原因,而不是简单地使用执行 payload 处理提款,是因为提款是基于信标状态的,并且只能在准备 payload 时才知道。但是,payload 的哈希值是在信标区块体中提交的,该区块体是在知道 payload 的预状态之前揭示的。
因此,提款直接从信标状态而不是从信标区块中获取,并在共识区块上立即处理。
如果父区块是空的,则不处理任何提款,因为上次处理的提款尚未兑现。否则,处理方式与 Capella 完全相同。
已处理的提款列表的 hash_tree_root
记录在信标状态中,以便以后与需要满足它们的执行 payload 进行比较。
def process_withdrawals(state: BeaconState) -> None:
## 如果父区块为空,则提前返回
if !is_parent_block_full(state):
return
withdrawals = get_expected_withdrawals(state)
state.last_withdrawals_root = hash_tree_root(withdrawals)
for withdrawal in withdrawals:
decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
...
信标区块不再具有完整的执行 payload,而是仅包含一个已签名的执行 payload 标头。验证此标头基本上包括以下内容
上述立即转移是本规范的简化版本,从 EIP 7002 和 EIP 7251 中剥离。通过 Max EB 大的验证者转移可以通过此机机制实现,这可以被利用来转移例如来自被削减的验证者(或即将被削减的验证者)的资金。一个简单的修改是立即扣除构建者的资金,但将金额添加到提议者的存款队列中。如果构建者被削减,则可以在 epoch 处理中添加额外的机制。
执行 payload 标头处理的最后一步是在信标状态中记录包含列表提议者和已签名的执行 payload 标头:
def process_execution_payload_header(state: BeaconState, block: BeaconBlock) -> None:
# 验证标头签名
...
# 如果父区块已满,则缓存包含列表提议者
if is_parent_block_full(state):
state.latest_inclusion_list_proposer = block.proposer_index
state.latest_inclusion_list_slot = block.slot
# 缓存已签名的执行 payload 标头
state.signed_execution_payload_header = signed_header
以下部分 包含列表 中详细介绍了这些步骤。
区块处理中的其余更改与信标区块体中包含的新 PayloadAttestation
s 有关。这包括两个更改,我们更改了函数 process_attestations
,以便忽略来自 PTC 的任何证明。
这并不是严格必需的,PTC 是通过从每个证明委员会的末尾选取一些验证者来构建的。这是在新函数 get_ptc
中执行的:
def get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]:
"""
获取给定 ``slot`` 的 ptc
"""
epoch = compute_epoch_at_slot(slot)
committees_per_slot = bit_floor(min(get_committee_count_per_slot(state, epoch), PTC_SIZE))
members_per_committee = PTC_SIZE/committees_per_slot
validator_indices = []
for idx in range(committees_per_slot)
beacon_committee = get_beacon_committee(state, slot, idx)
validator_indices += beacon_committee[:members_per_commitee]
return validator_indices
我们可以修改函数 get_beacon_committee
以不返回 PTC 成员,我们决定使用这个简化的版本来最小化规范差异。
信标区块中的 payload 证明按如下方式处理。我们强制证明来自前一个Slot,并且是针对父信标区块根的。
在信标区块中包含 payload 证明主要是为了奖励/惩罚 PTC 证明者,从而激励他们按顺序行动。它们还用于提议者断言他们对父头的看法,以防他们包括足够多的 PTC 投票以获得法定人数。后者仅在父区块的情况下有用。至于前者,这种 1 Slot强制惩罚 PTC 成员,只要错过一个Slot,但我们认为获得的额外简洁性和区块大小的减少超过了 512 个验证者在这些情况下将收到的单个证明惩罚。
处理函数的核心由两个分支组成,如果 payload 证明与信标状态状态一致或不一致。我们说 payload 证明是一致的,例如,如果它投票支持 PAYLOAD_PRESENT
,并且最后一个Slot已满,即 data.slot == state.latest_full_slot
。如果投票支持 PAYLOAD_ABSENT
或 PAYLOAD_WITHHELD
并且最后一个完整Slot为空,那么我们认为它们是一致的。在这种情况下,提议者会因包含证明而获得奖励,而证明者会获得完整的证明奖励:
# 奖励提议者并在正确证明的情况下设置所有参与标志
proposer_reward_numerator = 0
for index in indexed_payload_attestation.attesting_indices:
for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
if not has_flag(epoch_participation[index], flag_index):
epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
proposer_reward_numerator += base_reward * weight
# 奖励提议者
proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
increase_balance(state, proposer_index, proposer_reward)
如果证明不一致,我们会对提议者和证明者处以完整的证明惩罚:
# 如果标志是由等价的 ptc 证明设置的,则取消设置标志
proposer_penalty_numerator = 0
for index in indexed_payload_atterstation.attesting_indices:
for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
if has_flag(epoch_participation[index], flag_index):
epoch_participation[index] = remove_flag(flag_index)
proposer_penalty_numerator += get_base_reward(state, index) * weight
# 惩罚提议者
proposer_penalty = Gwei(2*proposer_penalty_numerator // proposer_reward_denominator)
decrease_balance(state, proposer_index, proposer_penalty)
return
采用这种方法的原因是,PTC 证明中的等价性没有削减条件。证明者将被激励提交 PAYLOAD_PRESENT
和 PAYLOAD_ABSENT
两种证明,提议者也被激励同时包含两种证明,以便在任何一种情况下都获得奖励。
对提议者处以双倍惩罚的原因是,否则提议者和证明者仍然可以串通发送等价物,并首先订购不一致的证明,然后再订购一致的证明。在这种情况下,提议者将被同时惩罚和奖励,净结果为零。而证明者将获得奖励,因为第一次传递会清除标志,而第二次传递会设置标志。通过对提议者处以两倍的金额,我们将激励措施调整为不包含无论如何都会对证明者处以全部惩罚的错误证明。
包含列表是任何已实现的 PBS 系统中所需的抗审查性的核心。本规范采用的是 前向包含,其设计与 EIP 7547 的设计类似。该系统相对简单:提议者广播单独的 InclusionList
对象,如 包含列表 部分所述,下一个区块的构建者必须满足它们。但是,需要考虑几个边缘情况。
包含列表首先通过 Gossip 进入我们的验证流水线。InclusionList
对象在 inclusion_list
全局主题中传播。执行的 Gossip 验证都很简单
MAX_TRANSACTIONS_PER_INCLUSION_LIST
。在 Gossip 阶段没有 EL 验证。
提议者存在广播下一个Slot的 IL 的风险,并且头部在第 0 秒发生变化。由于 Gossip 规则,可能没有人拥有新的 IL。该 IL 仍将被视为可用。
on_inclusion_list
处理程序一旦包含列表通过了发布/订阅验证过程,其余步骤主要在 EL 中执行。分叉选择 on_inclusion_list
处理程序本质上是对执行引擎 API 调用的包装器。验证者可以 (并且应该) 通过针对头部状态检查提议者索引和相应的Slot来验证在相应的信标区块之前到达的包含列表。python 规范中的处理程序假定信标区块已经过处理并且可以在存储中找到。如果父区块是 空的,则任何包含列表都将被忽略并自动被视为可用。这样做的原因是每次有一个空区块时,最后一个包含列表尚未完成,如果我们允许空区块之后的提议者提交包含列表,我们将创建一个无法清除的未完成包含列表的积压。
因此,我们要求包含列表和完整区块之间存在一一对应的关系。
这就是我们保留以下条目的原因
previous_inclusion_list_proposer: ValidatorIndex # [ePBS 中的新增内容]
previous_inclusion_list_slot: Slot # [ePBS 中的新增内容]
latest_inclusion_list_proposer: ValidatorIndex # [ePBS 中的新增内容]
latest_inclusion_list_slot: Slot # [ePBS 中的新增内容]
```在信标链状态中。当我们处理一个信标块,**其父块为满**时,会存储`latest`条目,这是我们已验证的最新包含列表。`previous`条目是包含列表中仍需要满足的条目。当我们处理满足它们的执行负载时,我们将`previous = latest`。
如果父块是满的,那么我们会将包含列表发送给EL进行验证。
### EL 验证
EL 必须对包含列表执行多项验证。我们让当前状态为就在导入包含`inclusion_list.parent_block_hash`区块之后的执行状态。
- 检查`inclusion_list.transactions`中的每个交易是否可以在当前状态下被包含。
- 检查列表`inclusion_list.signed_summary.message.summary`是否由`inclusion_list.transactions`中那些交易的“from”地址的有序列表组成。
- 检查这些交易指定的总`gas_limit`是否小于`MAX_GAS_PER_INCLUSION_LIST`。
- 检查地址 "from" 列表中的帐户是否有足够的资金来支付 `(base_fee_per_gas + base_fee_per_gas / BASE_FEE_MAX_CHANGE_DENOMINATOR)*gas_limit`,这是 EIP 1559 可能发生的最大变化。
## 执行负载的时间线
处理执行负载变成了共识层和执行层上完全独立的状态转换函数。因此,发送的消息是 `SignedExecutionPaylaodEnvelope`,除了传递给 EL 进行验证的执行负载之外,它还携带了共识验证所需的所有信息。
### Gossip
执行负载在全局 `execution_payload` pubsub 主题中传播,这是 ePBS 中的新特性。执行的验证如下:
- 已经看到此负载对应的信标区块,并且该区块有效。
- 构建者索引与信标区块中已提交的头部对应。
- 负载哈希与已提交的负载头部区块哈希对应。
- 构建者的签名是有效的。
不存在因负载伪造而进行的罚没。 这是这个版本的 ePBS 中的一个小问题,因为完整的负载哈希被提交在信标区块根中,该根可以因为伪造而被罚没。这意味着如果没有罚没,就不可能存在两个不同的有效执行负载。 在 ePBS 的版本中,例如插槽拍卖,没有承诺,处理伪造和头部拆分视图似乎在技术上更加困难。
### 共识状态转换
在通过 Gossip 验证后,执行负载进入 forkchoice 处理程序 `on_execution_payload` 中的共识验证管道。 这个包装器简单地检查相应的信标区块和 Blob 侧车数据是否可用,恢复相应信标区块的后状态,然后调用 `process_execution_payload`。
在共识方面,有一些变化:
- 我们需要验证信封的签名(客户端在常规同步期间不会这样做,因为他们已经在 Gossip 中完成了)。
- 我们验证包含的提款的哈希树根是否与信标状态中已提交的提款根匹配。 也就是说,我们验证负载是否满足 CL 中已经扣除的提款。
- 验证包含列表的提议者索引和插槽是否与信标状态中已提交的索引和插槽对应,也就是说,此负载声明满足正确的包含列表
我们需要将提议者索引**和**插槽都提交到信标状态和提议者,以避免提议者为某个插槽签署一个空的包含列表,并且以后构建者在未来的插槽中重复包含它的情况。
- 我们从负载和信封中重新组装 `SignedInclusionListSummary` 并检查签名
我们需要重新组装它而不是将其包含在负载中的原因是为了使 EL 不需要接收无用的信息。 我们保持 EL 在负载中接收严格验证所需的信息的不变性。
- 我们验证负载的信标区块根承诺是否与信标状态中承诺的那个相同,并且负载哈希、父区块哈希和 kzg承诺以及构建者索引与信标状态中的先前承诺一致。
- 我们将负载发送给 EL 进行验证
- 我们使用此负载更新信标状态 `latest_block_hash`、`latest_full_slot`
- 我们更新信标状态 `previous` 包含列表信息,使其成为 `latest` 列表,因为此负载需要满足先前的 IL。
- 我们验证已提交的信标状态根
执行负载对信标状态执行更改(关于包含列表和负载哈希)这一事实要求我们检查新的 state root。 我们选择遵循与当前共识状态转换函数相同的系统,并在信封中提交信标状态的 resulting hash\_tree\_root。
### 执行状态转换
除了通常的负载执行验证之外,EL 还需要在 ePBS 中执行一项新任务,即验证包含的 **包含列表摘要** 的满足情况。
为了执行此验证,EL 需要执行以下操作:
- 存储并保存当前负载中发送交易的地址列表。
- 存储并保存当前负载中减少其余额的地址列表。
- 对于 `inclusion_list_summary` 中的每个地址,检查以下内容:
- 当前负载中是否存在具有该 "from" 地址的交易。
- 如果没有,则在先前存储的父区块地址列表中是否存在具有该 "from" 地址的条目。
- 如果没有,则在先前存储的当前负载中减少余额的地址列表中是否存在该地址的条目 。
- 如果没有,则在先前存储的先前负载中减少余额的地址列表中是否存在该地址的条目。
以上验证保证此负载确实满足了正确的提议者和插槽广播的包含列表。 这并不能保证每个人都可以使用此包含列表,因为提议者可能专门将此列表提供给此构建者,而没有提供给其他人。 余额的存储是为了处理 EIP 3074 的特殊情况,该情况允许来自地址 `0xA` 的交易花费来自地址 `0xB` 的 ETH,这可能会使包含列表中的某些交易无效,从而使其无法包含在当前负载中。
## 负载证明的时间线
PTC 成员将他们的证明广播为 `PAYLOAD_ATTESTATION_MESSAGE` 对象
### Gossip
在 Gossip 上,`payload_attestation_message` 执行以下检查:
- 我们只传播当前插槽的证明
- 我们只传播在投票中具有有效负载状态的证明。
- 我们只传播来自任何 PTC 成员的此类证明
- 我们只传播在我们看到信标区块根的插槽中的证明。
- 我们检查验证者是否确实在 PTC 中。
- 我们检查签名
### Forkchoice 处理程序
一旦证明通过 Gossip 验证,我们就在 forkchoice 中处理它,在处理程序 `on_payload_attestation_message` 中,这类似于处理程序 `on_attestation`。
执行以下检查,其中一些与 Gossip 重复,这是因为其中一些证明可以直接从区块中处理
- 我们检查信标区块是否在 forckhoice 存储中
- 我们检查证明者是否在该插槽的 PTC 中
- 我们检查信标区块是否用于该插槽
- 如果证明不是来自区块:
- 我们检查证明是否用于当前插槽
- 我们检查证明的签名
- 我们更新在 forkchoice 上跟踪的给定 blockroot 的 ptc 投票。
## 诚实验证者的行为
验证者有几个职责, 他们可以是**提议者**、**PTC 成员**、**证明者**、**聚合者**和**同步委员会成员**。与后三个相关的职责在 ePBS 中没有改变。 但是,由于 ePBS 中技术上最复杂的变化之一与 forkchoice 考虑和头部确定有关,因此我们在本节中包含一些基本示例,作为下面更全面的部分 [Forkchoice 考虑](#forkchoice-considerations) 的准备。
### 提议者
如上面[插槽剖析](#Anatomy-of-a-slot)中所述,提议者,在他们需要的插槽的时间,除了准备 `SignedBeaconBlock` 的通常职责之外,他们还需要
- 从构建者处选择一个 `SignedExecutionPayloadHeader`
- 请求并构建一个 `InclusionList`。
两者都可以在该插槽开始之前完成。理性的验证者有动力尽早广播他们的包含列表,以最大限度地提高他们的区块被证明的机会。
验证者可以是他们自己的构建者,但这样做仍然需要他们签署自己的 `SignedExecutionPayloadHeader`。
允许验证者直接通过链下方法从构建者处请求投标。 经济上理性的验证者有动力这样做,因为这种机制允许构建者在那个精确的时间提供他们拥有的最佳投标。
与外部构建者相比,自构建验证者更有机会将负载包含在链上。自构建验证者可以在插槽开始后 3 秒钟将其区块与其执行负载一起广播,从而使负载有 6 秒钟的时间到达 PTC 成员,而外部构建验证者只有 3 秒钟(构建者只能在他们看到并验证共识区块**之后**广播他们的负载)
为了最大限度地提取 MEV,理性的验证者有理由推迟请求或选择构建者的投标,直到他们可以广播其区块的最后一刻。以下事实减轻了这些时间安排游戏:
- 存在`(block,slot)`投票,并且 **需要** 诚实验证者重新组织延迟的区块。
- 在 ePBS 分叉中,证明截止日期从当前的 4 秒减少到 3 秒。
#### 确定头部
在处理一个区块之前,提议者需要确定他们的链的头部。在本节中,我们包括了一些提议者将面临的常见情况的基本示例。在所有情况下,我们都处于插槽 `N` 的开始阶段,并且将要提议一个区块,来自 `N` 的箭头显示了诚实的提议者应该选择什么头部。
浅蓝色节点表示它们已满,白色节点是跳过的插槽。橙色节点是**空的**节点。
##### 快乐情形
没有分叉,所有块都存在并且已满
G
C
N
B
N-1
C->B
D
...
B->D
##### 跳过的插槽
上一个区块被跳过了
G
A
N
B
N-1
C
N-2
A->C
B->C
D
...
C->D
##### 遗漏的负载
上一个插槽的构建者没有揭示负载
G
A
N
B
N-1
A->B
C
N-2
B->C
D
...
C->D
##### 负载迟到了
上一个插槽的构建者揭示了负载,提议者迟到了,`N-1` 的 PTC 投票 `PAYLOAD_ABSENT`
G
A
N
B
N-1
A->B
C
N-2
B->C
L
N-1
L->C
D
...
C->D
##### 诚实地保留了负载
上一个插槽的提议者揭示了他的区块,但提议者迟到了。此外,也迟到了的构建者揭示了一条及时的 **负载保留** 消息。`N-1` 的 PTC 投票 `PAYLOAD_WITHHELD`
G
A
N
B
N-1
L
N-1
C
N-2
A->C
B->C
L->C
D
...
C->D
##### 负载保留失败
上一个插槽的提议者揭示了他的区块,而迟到了的构建者揭示了一条 **负载保留** 消息。但是,`N-1` 的 PTC 没有及时看到该消息,因此投票 `PAYLOAD_ABSENT`
G
A
N
B
N-1
A->B
L
N-1
C
N-2
B->C
L->C
D
...
C->D
### 证明者
证明职责没有任何改变,但是由于 ePBS 中确定头部发生了变化,因此我们在此处包含一些常见示例。当前插槽是插槽 `N`,颜色编码与之前相同,圆形的红色节点是证明者将投票的 blockroot。请注意,在这些示例中,插槽 `N` 不是满的,因为我们假设构建者将在证明截止日期之后揭示。请注意,这些示例有时在同一插槽高度有多个节点,例如,插槽 `N-1` 可以是满的或空的(延迟负载)。我们在红色中舍入了证明者的头部视图。诚实验证者的证明仅指向信标区块根。但是,forkchoice 权重仅应用于与 PTC 投票一致的分支。
#### 快乐情形
所有节点都存在并且已满,该区块提前到达
G
C
N
B
N-1
C->B
D
...
B->D
#### 没有包含列表
所有节点都存在并且已满,该区块提前到达,但包含列表未到达
G
C
N
B
N-1
C->B
D
...
B->D
#### 延迟区块
所有节点都存在并且已满,该区块延迟到达
G
C
N
B
N-1
C->B
D
...
B->D
#### 试图重新组织负载
`N-1` 的 PTC 投票 `PAYLOAD_PRESENT`。当前区块提前到达但重新组织了负载
G
A
N
B
N-1
A->B
L
N-1
C
N-2
B->C
L->C
D
...
C->D
#### 试图重新组织区块
上一个区块的构建者延迟揭示了负载,`N-1`的 PTC 投票 `PAYLOAD_ABSENT`。当前区块提前到达但重新组织了完整的区块
G
A
N
B
N-1
L
N-1
C
N-2
A->C
B->C
L->C
D
...
C->D
#### 延迟负载
`N-1`的 PTC 投票 `PAYLOAD_ABSENT`。当前区块提前到达并且基于上一个完整区块
G
A
N
B
N-1
A->B
L
N-1
C
N-2
B->C
L->C
D
...
C->D
#### 延迟负载和区块
`N-1`的证明委员会没有看到该区块并投票给`N-2`。`N-1`的 PTC 投票 `PAYLOAD_ABSENT`。当前区块提前到达并且基于上一个完整区块(或空区块,这就是为什么来自 N 的两个箭头)
G
A
N
B
N-1
A->B
L
N-1
A->L
C
N-2
B->C
L->C
D
...
C->D
### PTC 成员
每个插槽选择 512 个验证者,以证明相应负载的及时性。_负载证明_在语义上由以下消息之一组成
- 我已经看到了一个根据我当前的委员会改组**用于当前插槽**的有效共识区块以及相应的执行负载。
- 我已经看到了一个用于当前插槽的有效共识区块,并且我看到了来自相应构建者的有效“负载保留”消息
- 我已经看到了一个用于当前插槽的有效共识区块,但我没有看到相应的执行负载。
- 我还没有看到根据我的改组用于当前插槽的任何共识区块。
在短时间分叉的情况下,PTC 成员除了在提议等效的情况下不会看到两个不同的共识区块。在这种情况下,PTC 成员只会导入第一个共识区块,并将根据该区块采取行动。
在影响改组的长期运行分叉的情况下,对于同一插槽实际上可能存在不同的有效区块。但是,在这种情况下,同一个验证者实际上不可能同时成为分叉的两个分支中的 PTC 成员,因此在这种情况下,从当前 PTC 成员的改组的角度来看,仍然只有一个有效的共识区块。
### 构建负载证明
PTC 成员不证明头部负载的及时性。他们证明**当前插槽的负载**的及时性。以下图表可能有助于解释诚实的 PTC 成员行为。当前插槽是 `N`,PTC 成员将在该插槽的 9 秒后投出他们的证明。
#### 快乐情形
所有区块都已满,并且负载是及时的
G
B
N
D
...
B->D
在这种情况下,PTC 成员将投票 `PAYLOAD_PRESENT`
#### 负载迟到了
所有区块都是及时的,但当前负载未及时收到
G
C
N
B
N-1
C->B
D
...
B->D
在这种情况下,PTC 成员将投票 `PAYLOAD_ABSENT`。
如果信标区块是及时的,并且构建者仍然决定保留。PTC 成员将投票 `PAYLOAD_WITHHELD`。这使得更容易进行后反重组(尽管丢失了负载),但同时也提供了更强的构建者的保留安全性。
#### 成功保留 (延迟区块)
G
C
N
B
N-1
C->B
D
...
B->D
当前的共识区块收到较晚,构建者的负载是及时的,并且具有 `payload_withheld=True` 标志。在这种情况下,PTC 成员将投票 `PAYLOAD_WITHHELD`。
#### 成功保留 (不是头部)
这是前一个案例的严格概括
G
C
N
B
N-1
E
N-2
C->E
B->E
D
...
E->D
当前的共识区块收到及时(或较晚),但它不是链的头部。在此示例中,它试图重新组织上一个区块。构建者的负载是及时的,并且具有 `payload_withheld=True` 标志。在这种情况下,PTC 成员将投票 `PAYLOAD_WITHHELD`。
前一个示例是这种情况的特殊情况,因为如果 `N` 仅仅是延迟的,那么链的头部将继续是如上所述的 `N-1`。
请注意,如果传入块 `N` 仅仅试图重新组织先前的负载,则可以制作类似的图表,例如:
G
C
N
B
N-1
L
N-1
C->L
E
N-2
B->E
L->E
D
...
E->D
只要 PTC 成员及时看到 `payload_withheld=True` 信封,他们就会投票 `PAYLOAD_WITHHELD`。
#### 没有看到共识区块
如果 PTC 成员没有看到当前插槽的任何共识区块,那么它将不会提交任何负载证明。无论如何,任何此类负载证明都将被忽略。即使 PTC 成员已经及时看到了一些信封并声称属于当前插槽,PTC 成员也不会证明。
或者,我们可以让 PTC 成员投票 `PAYLOAD_ABSENT`,因为不可能存在可以针对不存在的执行负载头部进行验证的执行负载。或者我们甚至可以为这种情况创建一个特定的投票,以允许奖励这些成员。但是,PTC 成员在区块丢失的情况下受到的惩罚是最小的(仅错过了一个证明),并且它仅影响每个丢失区块的 512 个验证者。
## 诚实构建者的行为
构建者可以并且应该为不同的可能的父头部准备不同的负载。他们可以在预期的插槽之前提交多个投标。但是,验证者只会传播构建者、插槽组合的第一个看到的有效消息。
允许构建者打开链下服务以根据请求提供投标。这允许构建者更新他们自己的最佳投标,而无需将其广播到网络并冒着包含不太理想的负载的风险。
### 直接构建者的投标请求
规范的可选非共识部分是指定共识客户端支持直接从构建者请求投标。这将是对当前构建者 API 规范的微小修改,并且可以重用客户端中现有的代码。验证者将通过发送 `SignedBidRequest` 对象来请求执行头部
```wrap python hljs
class BidRequest(container):
slot: Slot
proposer_index: Validator_index
parent_hash: Hash32
parent_block_root: Root
class SignedBidRequest(container):
message: BidRequest
signature: BLSSignature
我们可以以加密方式绑定构建者的消息,以防止构建者知道当时其他构建者的投标是什么,从而不允许构建者格局中的卡特尔。请注意,即使构建者确实将投标提交给受信任的中继,构建者也无法保证通过上述机制私下直接发送给提议者的另一个更好的投标。
验证者始终可以自行构建,并且可以通过几乎可以保证比在 P2P 网络中传播的投标更好的链下机制直接请求投标。因此,有人可能会争辩为什么要保持一个全局主题。一方面,这在中心化构建者出现故障时提供了一个后备,以允许在低端硬件上运行的验证者可以访问更大的社区运行构建者。另一方面,它为审查和卡特尔垄断设置了一个低门槛,因为某些社区成员可能希望运行普通的软件,并为每个插槽生成公开投标,迫使中心化构建者出价超过他们以审查否则将包含在这些区块中的交易。
全局主题可以很容易地加强以防止垃圾邮件,因为我们可能只会传播我们为给定的父区块哈希收到的最高价值投标,并且还限制每个构建者一条消息。
ePBS 需要对引擎 API 进行一些更改:
ExecutionPayloadV4
来添加一个新字段 inclusionListSummary
。 这是与 EL 验证相关的唯一更改。PayloadAttrivutesV3
以包括包含列表父区块哈希和提议者索引。 EL 客户端应该保留一个有效的完整包含列表交易的映射,键为父区块哈希和提议者索引的对。该密钥由 CL 客户端通过调用 engine_forkchoiceUpdated
期间的负载属性发送,以触发区块生产。 这些字段允许 EL 选择它被迫包含的正确的包含列表交易。engine_newInclusionListV1
是一种新方法,用于通知 EL 新的完整包含列表。 当接收到完整的包含列表时,CL 调用此方法以将其传递给 EL 进行验证。 该方法采用一个新结构 InclusionListV1
作为参数,该结构由一组交易、摘要和上述对组成。也许 ePBS 分叉中技术上最复杂的变化之一是关于 forkchoice 和头部确定。 在本节中,我们考虑主要的高级变化。
ePBS 的核心是构建者的安全性概念。 回顾设计约束中的定义
(构建者揭示安全)诚实的构建者在他的回合中及时揭示了他的负载,他的区块将被包含在链上。
及其保留版本
(构建者保留安全)如果在当前插槽的 CL 区块没有被网络的大多数人看到或迟到,并且构建者决定不揭示他的负载,那么他不能被迫支付。
因此,我们需要实施一种方法,以在区块迟到的情况下(或者我们将在我们的设计中免费获得的:当到达的区块不是链的头部时)允许构建者诚实地保留他们的负载。 为此,我们实施(区块,插槽)投票。 在高层次上,这个想法是,如果插槽 N
的委员会中的验证者没有看到插槽 N
的区块到达,并且投票给它的父项 N-1
,那么它的权重支持 N-1
和任何从它降下来的链不包含 N
。 这里有些例子:
在这种情况下,所有区块都是及时的,每个委员会中都有一名证明者,并且每个证明者的权重为 10。这里weight
表示该节点的总支持权重,而“vote”表示投票给该节点的总直接权重。
G
A
weight:30
vote:10
B
weight:20
vote:10
B->A
C
weight:10
vote:10
C->B
链中的最后一个区块到达较晚,因此该插槽的证明者投票给它的父项。
G
A
weight:30
vote:10
B
weight:20
vote:20
B->A
C
weight:0
vote:0
C->B
效果是复合的,让我们分析一下连续延迟区块的简单情况。当第一个区块出现时,它被证明
G
A
weight:10
vote:10
在下一个插槽期间,子项出现较晚,因此验证者将投票给父区块,我们将有以下情况:
G
A
weight:20
vote:20
B
weight:0
vote:0
B->A
在投他们的票之前,这些验证者别无选择,他们没有看到最后一个区块到达。在下一个插槽期间,委员会现在看到了子项,并且他们可以选择头部:
G
A
Slot N-1
weight:20
vote:20
B
Slot N
weight:0
vote:0
B->A
C
Slot N-1
weight:20
vote:20
C->A
因此,如果他们将投票给 blockroot N-1
而不是 N
的 blockroot。
如果在插槽 N+1
期间 N
的子项到达并且及早到达,验证者将面临这种情况
G
A
Slot N-1
weight:20+PB
vote:20
B
Slot N
weight:PB
vote:0
B->A
C
Slot N-1
weight:20
vote:20
C->A
D
Slot N+1
weight:PB
vote:0
D->B
E
Slot N-1
weight:20
vote:20
E->C
其中 PB
是分配给早期区块的提议者提升。支持 blockroot N+1
的链的权重是 PB
,并且支持 N-1
作为头部根的权重是 20
,因此,如果 PB < 20
,诚实验证者将继续投票给 N-1
作为头部。
除了(区块、插槽)投票之外,我们在为 LMD 权重计数投票时还必须考虑负载的状态。节点不仅由插槽/blockroot 标记,而且可以是缺失、空或已满。我们遵循简单的规则
对 N
的 blockroot 的投票仅支持包含 N
且负载状态与 N
的 PTC 投票一致的链。 通过 一致,我们在这里指的是如果 PTC 已在 PAYLOAD_AVAILABLE
上达到法定人数,则对 N
的投票仅计算包含 N
负载的链。 如果 PTC 已达到 PAYLOAD_ABSENT
的法定人数,则对 N
的投票仅支持任何在 N
上不包含任何负载的链。 在 PTC 达到 PAYLOAD_WITHHELD
的法定人数的情况下,存在一种特殊情况,在这种情况下,我们将仅对不包含 N
负载的链的支持视为法定人数是 PAYLOAD_ABSENT
。
这个规则有点难以解释,所以让我们深入研究一些例子
我们使用与上一节相同的颜色编码,其中橙色表示空区块。 所有区块都已满,PTC 每个区块都投票给 PAYLOAD_PRESENT
G
A
Slot N-2
weight:30
vote:10
B
Slot N-1
weight:20
vote:10
B->A
C
Slot N
weight:10
vote:10
C->B
N-1
的 PTC 投票 PAYLOAD_PRESENT
,但插槽 N
对应的区块提前到达并在插槽 N-1
的空区块上构建。 在 N
的证明截止日期时,委员会会看到这个
G
A
Slot N-2
weight:20+PB
vote:10
B
Slot N-1
weight:10
vote:10
B->A
C
Slot N
weight:PB
vote:0
D
Slot N-1
weight:PB
vote:0
C->D
D->A
E
Slot N-1
weight:10
vote:10
E->B
因此,如果在 N
期间 PB < 10
验证者将投票给 N-1
作为头部,在 N+1
开始时,情况将是
G
A
Slot N-2
weight:30
vote:10
B
Slot N-1
weight:20
vote:20
B->A
C
Slot N
weight:0
vote:0
D
Slot N-1
weight:0
vote:0
C->D
D->A
如果 N-1
缺失而不是空,N
在 N-2
之上构建也会发生完全相同的情况。
在这种情况下,N-1
的区块被一些验证者(占委员会总股份的 x
部分)提前看到,其余的则较晚看到。 构建者及时发送了 负载保留消息。 在插槽 N-1
结束时,PTC 达到了 PAYLOAD_WITHHELD
的法定人数,情况如下(在此图表中,我们使用总委员会的单位进行投票)
G
A
Slot N-2
weight:2
vote:1
B
Slot N-2
weight:1-x
vote:1-x
B->A
D
Slot N-1
weight:x
vote:x
D->A
如果 PTC 在 PAYLOAD_ABSENT
中达到了法定人数,那么在此阶段的情况将完全相同。
存在一个边缘情况,其中当构建者实际上发送了消息负载保留时,PTC 可以达到 PAYLOAD_PRESENT
的法定人数。 这只能通过提议者的同等行为(因为不同的负载哈希)或构建者的同等行为来实现。 仅当构建者发送具有相同负载的不同信封时,才会发生构建者的同等行为。 这只会在它包含不同的 payload_withheld
字段时发生。 这种同等行为不会造成任何严重问题。
使 forkchoice 复杂化的另一个组成部分是包含列表的可用性。 我们已经在上面看到,当导入一个父项为空白的区块时,我们将该区块的包含列表标记为可用。 但是,如果它的父项已满,我们需要等待并验证它的包含列表。 当计算链的头部时,我们遵循以下简单规则:
这里有些例子:
没有任何诚实的验证者在 N-1
期间看到其共识区块的包含列表。 在 N-1
的证明截止日期时,情况是这样的
G
A
Slot N-2
weight:10+PB
vote:10
B
Slot N-1
weight:PB
vote:0
B->A
诚实验证者将通过通常的规则计算他们的规范头部并找到 N-1
,但是由于他们没有看到有效的 IL,他们将投票给 N-2
作为头部。 在下一个插槽 N
开始时,情况是这样的
G
A
Slot N-2
weight:20
vote:20
B
Slot N-1
weight:0
vote:0
B->A
C
Slot N-2
weight:20
vote:20
C->A
N
的区块提前到达,并且它具有完全有效的 IL,而且它在 N-1
上构建并且是一个有效的负载。 特别是,这意味着 N-1 的有效 IL 可用 至少对构建者可用。 在 N
的证明截止日期时,情况是这样的
G
A
Slot N-2
weight:20+PB
vote:20
B
Slot N-1
weight:PB
vote:0
B->A
C
Slot N-2
weight:20
vote:20
C->A
D
Slot N
weight:PB
vote:0
D->B
E
Slot N-2
weight:20
vote:20
E->C
```因此,如果 `PB>20`,诚实的验证者实际上会投票支持 `N` 并重新组织链。假设在这种情况下我们选择 `PB = 25`,诚实的验证者会投票支持 `N`,并且在 `N+1` 开始时的情形如下:
G
A
Slot N-2 weight:30 vote:20
B
Slot N-1 weight:10 vote:0
B->A
C
Slot N-2 weight:20 vote:20
C->A
D
Slot N weight:10 vote:10
D->B
E
Slot N-2 weight:20 vote:20
E->C
因此,下一个提议者会立即重新组织并继续在 `N-2` 之上提议。请注意,`N-1` 永远不是 head 的选项。
#### 共谋后的延迟区块
在类似于上述的情形中,假设 slot `N` 没有及时到来。在这种情况下,即使我们知道有人(例如 `N` 的构建者)拥有完整的 IL,`N-1` 也不会成为 head。规范的 head 将继续是 `N-2`。
#### 孤立节点
可能会发生这样的情况:将成为 `N` 的提议者的节点根本没有看到 `N-1` 的 IL,但它及时看到了区块,并且链的其余部分已经看到了 IL,因此传入的区块获得了大量的投票。在这种情况下,提议者会计算 head,并收到 `N-2` 作为 head,而不是 `N-1`。因此,它将尝试重新组织区块,并且验证者(在正常情况下)不会投票支持 `N`,而是投票支持 `N-1`。
在这种情况下,对于孤立的提议者/证明者,情况与提议者将 IL 可用性视为区块的有效性条件完全相同。验证者仍然可以通过 RPC 从 peer 请求 IL,特别是当他们看到区块被投票时。
### Payload 提升
Payload 提升将在下一节 [安全分析](#Security-analysis) 中进行分析,但我们在此处包含一些示例。如果 payload 及时显示,并且 PTC 在 `PAYLOAD_PRESENT` 的投票中达到法定人数,则完整区块的 forkchoice 节点会收到一个构建者的显示提升(RB),该提升从显示的 slot 到下一个 slot 的证明截止日期有效。相反,如果构建者显示一条payload 被诚实地扣留消息,并且 PTC 在 `PAYLOAD_WITHHELD` 上达到法定人数,则缺失区块的 forkchoice 节点会获得构建者的扣留提升(WB),这意味着此提升应用于父节点,并且仅支持不包含当前区块的链。
扣留提升应用于父节点,而不是将其从节点及其后代中删除,以避免溢出。使用减法的分析类似。
以下是一些基本示例
#### 快乐情况
所有区块都是及时的且完整的。PTC 在 `PAYLOAD_AVAILABLE` 上达到法定人数。在 slot `N` 的证明截止日期,我们有
G
A
Slot N-2 weight:20+PB+RB vote:10
B
Slot N-1 weight:10+PB+RB vote:10
B->A
D
Slot N weight:PB+RB vote:0
D->B
#### 尝试进行 payload 重组
PTC 已在 `N-1` 的 `PAYLOAD_AVAILABLE` 上达到法定人数,但 `N` 的提议者在空区块之上构建。在 `N` 的证明截止日期,情况是
G
A
Slot N-2 weight:20+PB+RB vote:10
B
Slot N-1 weight:10+RB vote:10
B->A
C
Slot N-1 weight:PB vote:0
C->A
D
Slot N weight:PB vote:0
D->C
#### 尝试构建者的恶意行为
`N-1` 的 PTC 已在 `PAYLOAD_WITHHELD` 上达到法定人数,构建者及时显示了一条payload 扣留消息,但 `N` 的提议者仍然在 `N-1` 之上构建。在 `N` 的证明截止日期,我们有
G
A
Slot N-2 weight:20+PB+WB vote:20
B
Slot N-2 weight:10+WB vote:10
B->A
C
Slot N-1 weight:PB vote:0
C->A
D
Slot N weight:PB vote:0
D->C
这种情况的时间线如下。在 `N-2`,诚实的验证者投票支持它。在 `N-1` 期间,所有诚实的验证者也投票支持它。但是,这些投票仅支持没有 payload 的链。因此,对 `N-2` 的 `10` 个直接投票将支持包含 `N` 的链,但来自 `N-1` 委员会的 `10` 个投票将不支持,这些投票在虚线节点中高亮显示。
## 安全分析
在本节中,我们分析所提出的设计在多大程度上满足 [epbs 设计约束](https://ethresear.ch/t/epbs-design-constraints) 中列出的所有约束。
这些部分的相关条件是
- 构建者显示安全性
- 构建者扣留安全性
- 提议者安全性
在本节中,我们使用 [ePBS 中的 payload 提升](https://ethresear.ch/t/payload-boosts-in-epbs/18769) 中推导出的相同值,即
\\\[ WB = RB = 40\\%, \\qquad PB = 20\\%.\\\]
在以下所有示例中,假设攻击者控制着委员会股份的 \\(\\beta\\) 部分。我们假设 PTC 是诚实的(即 \\(\\beta < 50\\%\\))。
### 构建者显示安全性
> (构建者显示安全性) 诚实的构建者在他的回合期间及时显示他的 payload,他的区块将被包含在链上。
#### 重新组织 payload
在本节中,我们证明两个连续提议者的共谋无法重新组织已显示的构建者的 payload。在这种攻击中,`N-1` 和 `N` 的提议者正在共谋,并且想要重新组织 `N-1` 的构建者的 payload。进一步假设 `N-1` 的提议者能够随意控制证明投票的分裂。让我们假设他们的目标是有 \\(x\\) 比例的委员会提前看到该区块,而 \\(1-x-\\beta\\) 的比例会延后看到该区块(他们也可能会扣留价值 \\(\\beta\\) 的证明)
在构建者显示时,构建者视图中的 forkchoice 状态是(我们没有计算提议者提升,因为所有证明都已经在这个阶段发生)。在最坏的情况下,如果提议者想要欺骗构建者进行显示并尝试重新组织它,因此他们将发布他们对 `N-1` 的证明,但会从 \\(N-2\\) 中扣留它们。请注意,整个委员会都在 \\(N-2\\) 期间进行了投票,这些投票是无关紧要的,我们在这里不将其计入此分析中。
G
A
Slot N-2 weight:1-β vote:0
C
Slot N-1 weight:x vote:x
C->A
B
Slot N-2 weight:1-x-β vote:1-x-β
B->A
构建者只有在 \\(1-x-β < x\\) 时才会显示,等效地,如果
\\\[1 - 2x < \\beta. \\qquad \\qquad \\qquad \\qquad (1)\\\]
构建者显示他的 payload,并且诚实的 PTC 在 `PAYLOAD_PRESENT` 上达到法定人数。下一个 `N` 的提议者尝试使用早期区块重新组织 payload。证明截止日期时的状态是
G
A
Slot N-2 weight:1-β+RB+PB vote:0
D
Slot N-1 weight:PB vote:0
D->A
C
Slot N-1 weight:x+RB vote:x
C->A
B
Slot N-2 weight:1-x-β vote:1-x-β
B->A
E
Slot N weight:PB vote:0
E->D
此时,没有来自 N-1 的证明可以支持包含 `N` 的链,因此攻击者唯一可以做的就是显示对 `N-2` 的证明。将较低节点的权重从 \\(1-x-\\beta\\) 更改为 \\(1-x\\)。包含 `N` 的链永远无法从构建者的链中获胜,原因是
\\\[ RB > PB \\Rightarrow x + RB > PB.\\\]
只有当
\\\[ RB < 1 - 2x < \\beta, \\\]
来自 `N-2` 的链(重新组织整个区块)才会获胜,我们在这里使用了 (1)。因此,对于 \\(RB = 40\\%\\) 的值,构建者可以免受控制高达 \\(40\\%\\) 股份的利益相关者的攻击。
#### 重新组织区块
我们在上一节中看到,攻击者没有机会仅重新组织 payload,他们不妨尝试重新组织整个区块,为此,他们不是在空区块之上显示 payload,而是在错过的区块之上显示 `N`。在 `N` 的证明截止日期,情况将是
G
A
Slot N-2 weight:1+RB+PB vote:0
C
Slot N-1 weight:x+RB vote:x
C->A
B
Slot N-2 weight:1-x + PB vote:1-x
B->A
E
Slot N weight:PB vote:0
E->B
现在,如果
\\\[ PB + 1 - x > x + RB,\\\]
或等效地,如果
\\\[ RB - PB < 1 - 2x < \\beta\\\]
则诚实的验证者将投票支持攻击者的分支,这只要 \\(\\beta < 20\\%\\) 就永远不会发生。我们看到,只要提议者不控制超过 \\(20\\%\\) 的股份,构建者就不会被控制分裂的串通行为者重新组织。
请注意,如果提议者没有如此精确地控制网络拆分,那么这些数字会明显上升。
### 构建者扣留安全性
来自 [设计约束](https://ethresear.ch/t/epbs-design-constraints):
>(构建者扣留安全性)如果网络的大部分没有看到当前 slot 的 CL 区块,或者已经滞后看到,并且构建者决定不显示他的 payload,那么他不能被迫支付。
鉴于我们有(区块、slot)投票,我们实际上在相同的攻击者股份参数下获得了更强的安全性
(构建者扣留安全性)如果当前 slot 的 `SignedBeaconBlock` 区块不是链的 head,并且构建者决定不显示他的 payload,那么他不能被迫支付。
#### 试图进行构建者的恶意行为
在这种攻击中,`N-1` 和 `N` 的提议者都在共谋以恶意对待 `N-1` 的构建者。他们的意图是使构建者扣留 payload,但同时让他支付出价。为此,`N` 的提议者像以前一样针对拆分,其中 \\(x-\\beta\\) 部分会及早看到该区块,而 \\(1-x\\) 部分会延迟看到该区块(攻击者将扣留他们对 \\(N-1\\) 的投票,以最大限度地提高构建者扣留的机会)
就像以前一样,在 `N-1` 的构建者需要显示 payload 之前的情况是,他们看到以下 forkchoice 状态:
G
A
Slot N-2 weight:1-β vote:0
C
Slot N-1 weight:x-β vote:x-β
C->A
B
Slot N-2 weight:1-x vote:1-x
B->A
如果
\\\[ x - \\beta < 1- x \\Leftrightarrow 2x - 1 < \\beta. \\\]
则它们将扣留它们的 payload。
PTC 是诚实的,并在 `PAYLOAD_WITHHELD` 上达到法定人数,但是 `N` 的提议者将其区块基于缺失的 payload 之上。攻击者还将公开他们对空 `N-1` 区块的证明。在 `N` 的证明截止日期,情况如下
G
A
Slot N-2 weight:1+WB+PB vote:0
C
Slot N-1 weight:x+PB vote:x
C->A
B
Slot N-2 weight:1-x + WB vote:1-x
B->A
E
Slot N weight:PB vote:0
E->C
因此,如果
\\\[ PB + x > 1 - x + WB \\Leftrightarrow WB - PB < 2 x - 1\\\]
攻击成功,使用以上公式,这意味着
\\\[ WB - PB < \\beta. \\\]
这在使用所选参数的情况下是不可能的。我们看到,构建者受到网络控制以及高达 \\(20\\%\\) 的股份的串通提议者的攻击的保护。
#### 错误的父区块
试图恶意对待构建者的另一种尝试是通过拆分 `N-2` 本身的视图,在这种攻击中,`N-1` 的提议者通过在非规范区块(而不是像先前示例中的 `N-2`)之上进行提议来构建弱区块。但是,这需要构建者本身不诚实,因为构建者在 `ExecutionPayloadHeader` 中同时指定了父区块哈希**和**父区块根。
### 提议者安全性
来自 [设计约束](https://ethresear.ch/t/epbs-design-constraints/18728#h-33-proposer-safety-11):
>(提议者安全)如果提议者诚实地行事并及时显示他的区块,它将被包含在链上。
#### 事前重新组织
在这种攻击中,`N-1` 的提议者和 `N-1` 的构建者正在共谋,以延迟显示他们的区块并试图重新组织来自 `N` 的提议者的区块
该攻击的时间线如下。`N-1` 的提议者以如上所述的目标分裂来显示他的区块。验证者的 \\(x - \\beta\\) 部分将及时看到该区块 `N-1`(攻击者将扣留他们对 `N-1` 的证明)。他们的目的是让 `N` 的提议者在 `N-2` 之上构建他们的区块,以便稍后重新组织它。
在 `N` 开始时,提议者的观点是
G
A
Slot N-2 weight:1-β vote:0
C
Slot N-1 weight:x-β vote:x-β
C->A
B
Slot N-2 weight:1-x vote:1-x
B->A
只要 \\(x < 1/2\\),PTC 将在 `PAYLOAD_ABSENT` 上达到法定人数,否则将在 `PAYLOAD_PRESENT` 上达到法定人数。在 \\(x < 1/2\\) 的情况下,且 PTC 投票支持 `PAYLOAD_ABSENT`,只要
\\\[ 1 - x > x - \\beta \\Leftrightarrow \\beta > 2x - 1. \\\]
`N` 的提议者将基于 `N-2` 的区块。请注意,如果 \\(x < 1/2\\),则始终满足此条件,因此只要 PTC 投票支持 `PAYLOAD_ABSENT`,`N` 的提议者就会在 `N-2` 之上进行提议。
另一方面,如果 \\(x > 1/2\\),并且 PTC 已在 `PAYLOAD_PRESENT` 中达到法定人数,则 `N-1` 的提议者将在 `N` 开始时看到不同的 forkchoice 图:
G
A
Slot N-2 weight:1-β+RB vote:0
C
Slot N-1 weight:x-β+RB vote:x-β
C->A
B
Slot N-2 weight:1-x vote:1-x
B->A
在这种情况下,他们仅会在
\\\[ 1-x > x - \\beta + RB \\Leftrightarrow RB + 2x - 1 < \\beta.\\\]
的情况下在 `N-2` 之上进行提议。
##### 第一种情况,缺少 payload。
我们处于 \\(x < 1/2\\) 且 PTC 同意 `PAYLOAD_ABSENT` 的情况。在这种情况下,在 `N` 的证明期限结束时,forkchoice 状态为
G
A
Slot N-2 weight:1+PB vote:0
C
Slot N-1 weight:x vote:x
C->A
B
Slot N-2 weight:1-x vote:1-x
B->A
D
SlotN weight:PB vote:0
D->B
如果
\\\[ x > PB + 1 - x \\\]
则重新组织成功,这永远不会发生。
##### 第二种情况,存在 payload
我们处于 \\(x > 1/2\\) 且 \\(RB + 2x - 1 < \\beta\\) 的情况。在这种情况下,PTC 在 `PAYLOAD_PRESENT` 中达到了法定人数,但是提议者仍然会将他的区块基于 `N-2` 之上。这是攻击者想要触发的范围,因为他们希望包含 `N-1` payload。
在 `N` 的提议者显示他们的区块后,攻击者会显示他们对 `N-1` 的证明,并在 `N` 的证明期限结束时,forkchoice 状态为:
G
A
Slot N-2 weight:1+RB+PB vote:0
C
Slot N-1 weight:x+RB vote:x
C->A
B
Slot N-2 weight:1 - x vote:1-x
B->A
E
Slot N weight:PB vote:0
E->B
如果
\\\[ x + RB > PB + 1 - x \\Leftrightarrow PB < RB + 2x - 1\\\]
则重新组织将有效,根据以上条件,这意味着 \\(PB < \\beta\\),鉴于我们的约束,这是荒谬的。因此,我们看到,提议者在与拥有高达 \\(20\\%\\) 股份的串通攻击者进行事前重新组织时是安全的。
#### 事后重新组织
在这种攻击中,`N-1` 的构建者和 `N` 的提议者正在勾结,试图重新组织 `N-1` 的提议者的共识区块。`N-1` 的构建者不希望 PTC 在 `PAYLOAD_PRESENT` 上达到法定人数,因为这会给 `N-1` 赋予权重。构建者扣留了,然后 PTC 将在 `PAYLOAD_WITHHELD` 上达成共识。在 `N` 的证明期限结束时,forkchoice 状态为
G
A
Slot N-2 weight:1+PB+WB vote:0
B
Slot N-2 weight:PB + WB + β vote:0
B->A
C
Slot N-1 weight:1-β vote:1-β
C->A
E
Slot N weight:PB vote:0
E->B
只有在 \\(PB + WB + \\beta > 1 - \\beta\\) 的情况下,重新组织才有效,这在使用我们选择的参数情况下不会发生,最高可达 \\(20 \\%\\) 的股份的利益相关者。
### 解绑
MEV-Boost 面临的攻击之一是解绑。本质上,这对应于欺骗构建者显示 payload,但 CL 区块提交到同一区块上的不同 payload。我们在上面关于构建者显示安全的分析中看到,这种情况至少在串通的提议者的某些情况下不会发生。但是,我们在此处包括在提议者犯错的情况下进行的分析,这更符合 [low carb crusader](https://collective.flashbots.net/t/post-mortem-april-3rd-2023-mev-boost-relay-incident-and-related-timing-issue/1540) 的原始攻击。想法是,提议者会犯错并提交两个不同的区块 `N` 和 `N'`,并让构建者显示 `N` 的 payload,并以某种方式重用交易并显示不同的 payload 以用于 `N'`,从而利用构建者的原始 payload。这种情况的时间线是不可能的,因为 `N'` 的提议者甚至无法构造该区块,直到它尚未看到通过 `N` 的 payload 为止。这意味着 `N'` 永远无法获得 PTC 的法定人数。如果 `N` 获得了足够的投票,则构建者的显示安全性将保证原始 payload 是规范的。如果它没有获得足够的投票,那么构建者扣留的安全性将保证构建者可能根本不会显示(从而使尝试无用),并且构建者不需要为此支付出价。
## 无信任优势
所提出的规范解决了使提议者和构建者能够公平地交换提议执行 payload 的权利的问题,而它们之间没有任何信任假设。但是,要使系统有效,我们需要不存在任何信任优势。来自 [设计约束](https://ethresear.ch/t/epbs-design-constraints/18728#h-35-no-trusted-advantage-14):
> 对于提议者来说,以非协议方式将他们的区块出售给构建者,不应该有固有的优势。
该规范允许构建者像当前的垂直集成中继一样运作。他们可以进行出价取消,直到最后一刻更新他们的 payload 等,而无需与单独的中继进行通信的任何额外延迟。他们无需担心解绑。因此,对于构建者而言,此机制使他们能够在没有额外延迟或处理运行中继的外部组织的可能的治理/财务方面的情况下,以无需信任的方式进入市场。
对于提议者而言,这增加了他们可以获得的出价范围。我们可以通过使出价请求以加密方式绑定到构建者来混淆出价,这样构建者甚至无法看到已经有哪些出价。这消除了中心化中继可能具有的任何优势,只要整个构建者集合不是卡特尔,也就是说,只要构建者集合确实在竞争。
## 无条件支付
我们已经看到,在处理共识区块时(特别是在处理区块体内的已签名执行 payload 标头时),出价的支付在信标链上得到了保证。这保证了只要他的共识区块没有被重新组织,提议者就能获得报酬。
当前提案中有两个由于简化而产生的限制:
#### 构建者需要锁定资金
构建者需要在提交出价之前提前将他们的资金抵押。如果他们想提交超过 32 ETH 的最大有效余额的大额出价,这会带来更大的效率低下。由于相应的验证者甚至不会从超过余额中获得抵押利润。对此的一种缓解措施是 EIP 7251,它增加了最大有效余额。此更改的副产品是当前提案的以下限制:
#### 构建者可以进行任意大的转账
验证者(因此也是构建者)可以具有任意大的余额,并且构建者的出价不受最大有效余额的约束。在当前机制中,验证者可以通过简单地签署区块,将任意大的转账转移给其他验证者。为避免这些在出现 EIP 7251 时变得特别危险的大变化,我们还可以使用 EIP 7002 存款流失机制。这需要一个简单的更改,即在处理执行 payload 标头时,不是立即转移金额,而是立即从构建者中扣除金额,但总金额会在提议者的存款队列中流失。
## 可选更改
### 不需要包含列表
在具有大量抵押的构建者的早期设计中,前向强制包含列表是强制性的成分。在当前设计中,对审查的抵抗力比现状更好,我们可以推迟包含列表的添加,直到未来的 分叉。
### PTC 不证明有效性
一个看起来很有希望并且与当前规范相比是一个简单更改的功能是,仅仅允许 PTC 证明 `SignedExecutionPayloadEnvelope` 的及时性和基本检查(例如 CL 当前所做的),但不要求 EL 进行完整执行。如果诚实的 验证者在导入执行 payload 时发现这一点,他们无论如何都不会认为 payload 有效。此更改还需要在应用 payload 提升时对 forkchoice 中的 PTC 状态进行乐观分配,或者干脆延迟 payload 证明的处理,直到完整的 payload 已被验证。
### 构建者的最低抵押
我们可以简单地为具有零驱逐余额的构建者添加一个新的验证者提款凭证前缀。从而允许构建者拥有尽可能低的抵押,从而使想要仅参与小型区块拍卖的构建者能够参与。
### Payload 证明奖励
关于 payload 证明的更改集是最小的。特别是,任何错过的 slot 都会因错过证明而惩罚 PTC 成员。以稍微更多的技术开销为代价,我们可以允许将较旧的 payload 证明包含在区块中,并据此奖励证明者。
## 与其他方法的比较
### Payload 欺骗
从激励角度以及市场效率和整体用户体验来看,执行票证或 slot 拍卖都具有许多有趣的特性。但是,有一个似乎是根本性的复杂性,至少作者不知道如何解决。区块欺骗有两个问题。首先是在 forkchoice 中,对于同一个 slot,可能存在多个有效条目。另一个是它们会导致 head 分裂视图,并且如果我们导入了错误的 head,则我们需要请求并导入正确的 head。
在 ePBS 上,由于添加了 payload 状态,forkchoice 节点的结构变得更加复杂。具有共识区块的节点可以是空的或完整的。也就是说,forkchoice 节点由信标区块根和 payload 的存在的一对 `(Root, bool)` 参数化。
当可以看到与给定区块关联的任意执行 payload 时,我们移至完全二维问题 `(Root, Root)`。这在 forkchoice 攻击和 head 分裂视图上打开了无数的极端情况,至少此作者不知道如何解决。
### 自动列入黑名单
具有链外 payload 提议者的系统使得将特定构建者列入黑名单非常困难。愿意花费足够资金的单个实体可能会影响链的活跃度或强制进行本地区块生产,其约束条件是资金而不是客户端的任意启发式方法。这个特定版本的 ePBS 使得自动将任何无法广播区块的构建者列入黑名单变得微不足道。并且不会影响整个协议。
### JIT 构建者
链外构建者允许他们成为 JIT 机会主义者,他们看到可能值得的交易,并可以为其提交出价。至少这位作者不知道如何在不对中心化可信中继造成严重劣势的情况下启用此类构建者。
### 两轮投票/SSF
与当前提案相比,拥有两轮完全聚合的投票,尤其是在单 slot 最终确定下,将具有更强的 forkchoice 保证。即使没有 SSF,我们也不知道如何在不显着增加 slot 时间的情况下在 slot 中进行两轮聚合。
## FAQ
#### 自建仍然可行吗?
是的,可以。
#### 构建者可以取消出价吗?
是的,可以。
#### 为什么有人会使用这个?
当前无法选择非审查构建者的提议者将能够直接选择它们。目前由于与中继的信任问题而甚至无法尝试进入市场的构建者将能够进入。想要避免与垂直集成构建者竞争的构建者可以自己垂直集成。监视网络的社区成员可以通过向 P2P 网络提交 vanilla EL 出价来保证最低的出价。
#### 中继仍然会发挥作用吗?
他们可能会,验证者仍然可以连接到它们并从中请求出价。它们没有固有的优势,实际上,直接连接的构建者将具有更快的连接速度,因此验证者更有可能通过连接到它们的外部端点而不是通过中继从同一构建者那里获得更好的出价。非常小的构建者或不想进行抵押的构建者仍然可以选择使用中继。
#### 链外解决方案怎么样?
它们没有解决 [简介](#Introduction) 中的问题
#### 客户端会仍然支持 MEV-Boost 吗?
没有必要,而且很可能不会。客户端仍然会实现一个 Builder API 版本,以直接连接到构建者。中继可以通过此 API 本身访问。
#### 这会由于需要的抵押而使构建者系统中心化吗?
1. 目前,1 个构建者拥有超过 80% 的市场份额,此系统严格来说是对现状的改进。
2. 我们可以根据需要将抵押金降至 0,从而允许较小的构建者参与高达他们愿意放置的股份。
3. 不包括 JIT 构建者,但他们仍然可以通过可信中继参与。
4. 客户团队、社区成员、家庭抵押者等。将能够轻松地开设构建者帐户,并且已经进行了抵押。他们今天无法这样做。
#### 执行票证不是更好的解决方案吗?
实际上可能是,但是 a) 我目前不知道如何实施 ET,并且 b) 此实施可以在短时间内准备好并进行测试,并且是朝着 ET 迈出的一步。如果解决了 拍卖 的犯错问题,那么从 ePBS 到 slot 拍卖的最小更改,以及从那里到 ET 的更改似乎是一个更近的差距。
>- 原文链接: [hackmd.io/@potuz/rJ9GCnT...](https://hackmd.io/@potuz/rJ9GCnT1C)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!