本文档深入探讨了 EigenPod 的重新设计,重点是引入检查点证明系统,旨在解决M2证明系统中存在的歧义性和会计问题,特别是在处理提款和保证ETH与股份对应关系方面。新的检查点系统结合了活跃验证器集合与信标链和EigenPod状态的快照,以明确确定ETH的数量和位置,从而提高股份分配的准确性和安全性,并解决了与部分提款和信标链削减相关的激励问题。
[TOC]
* 进行中的合约工作: [`eigenlayer-contracts/#515`](https://github.com/Layr-Labs/eigenlayer-contracts/pull/515) * [`eip-4788`](https://learnblockchain.cn/docs/eips/EIPS/eip-4788) * Lighthouse 区块和 epoch 处理: * [`per_block_processing`](https://github.com/sigp/lighthouse/blob/3058b96f2560f1da04ada4f9d8ba8e5651794ff6/consensus/state\_processing/src/per_block_processing.rs#L100) * [`per_epoch_processing`](https://github.com/sigp/lighthouse/blob/3058b96f2560f1da04ada4f9d8ba8e5651794ff6/consensus/state\_processing/src/per_epoch_processing/capella.rs#L21) * [`apply_blocks`](https://github.com/sigp/lighthouse/blob/3058b96f2560f1da04ada4f9d8ba8e5651794ff6/consensus/state\_processing/src/block_replayer.rs#L223)
EigenPod 信标链状态证明的主要技术问题是使用它们来确定 ETH 的位置的准确程度。
我们首先需要状态证明的原因是为了确保 *如果我们奖励份额,它们保证与最终会流经 pod 的 ETH 对应 1:1。 * 此属性对于支付很重要,它决定了质押者委托其份额所获得的金额。 * 此属性对于罚没更为重要,因为它提供了 *保证的下行空间\ 如果质押者行为不端 - 他们的份额可以被罚没,这直接代表了他们可能损失的 ETH。
因此,EigenPod 证明系统的 **最终目标** 是确定支持所奖励份额的资产的当前位置。理想情况下,证明系统不应 *模棱两可*。当我们处理一个证明时,我们应该明确地知道两件事:
只要我们可以毫不含糊地确定这些事情,我们就可以安全地奖励我们知道有支持的份额。
M2 证明在模糊性方面存在问题,并且存在一些会计怪癖,这将使实施新功能(尤其是罚没)变得更加困难。要理解原因,我们需要了解我们的 M2 系统消耗哪些信息 - 也就是说,*我们实际证明的是什么*。
目前,我们有三种类型的证明: * 提款凭证证明 * 余额更新证明 * 部分/全部提款证明
在这三种证明类型之间,我们主要消耗两个信标链信息:*有效余额*和*提款*。我们正在使用这些信息来确定: * 有多少ETH支持pod的股份 * 支持的 ETH 在哪里(信标链或 pod)
M2 使用此信息来相应地奖励或删除股份。
提款凭证和余额更新证明会消耗验证者的 `effective_balance`,该余额位于信标链的 [`Validator` 容器](https://eth2book.info/capella/part3/containers/dependencies/#validator)中。
有效余额的问题在于它们仅在 *每个 epoch* 更新,而不是 *每个区块* 更新。这意味着有效余额证明最多可能过时 32 个区块 - 忽略了验证器余额的变化,例如: * 提议者或证明者的罚没 * 提议者奖励 * 存款 * 部分或全部提款
仅依靠有效余额证明,我们无法 *准确地* 知道验证者当前在信标链上有多少 ETH。我们也不知道验证者是否已经提款。
部分/全部提款证明会消耗在信标链的 [`Withdrawal` 容器](https://eth2book.info/capella/part3/containers/dependencies/#withdrawal)中找到的 `amount`。他们还将 `Withdrawal` 创建的 epoch 与 [`Validator` 容器](https://eth2book.info/capella/part3/containers/dependencies/#validator)中找到的 `withdrawable_epoch` 进行比较。这是一种启发式方法,用于确定 `Withdrawal` 是被视为“部分”还是“全部”提款。
消耗信标链 `Withdrawals` 的好处是,当 EigenPod 看到 `Withdrawal` 证明时,*经过证明的准确 ETH 金额保证在 pod 中*。
但是,依赖信标链 `Withdrawals` 存在一些缺点: * 信标链 `Withdrawals` 是每个区块创建的,截至 Dencun 升级,每个区块最多处理 16 个提款。 * 这些提款可能是部分或全部提款;它们位于同一个队列中。无法区分部分提款和全部提款。 * `Validator's` `withdrawable_epoch` 并未给出全部提款的可靠指标 - 它仅表示“在 `withdrawable_epoch` 之后的某个时间点,验证者将被撤回”。 * 还要注意,在验证者的 `withdrawable_epoch` *之后* 的区块中存在 `Withdrawal` 确实意味着验证者已完全提款。但是,无法判断该特定 `Withdrawal` 是否是提取的全部金额!
一个单独的提款证明告诉你多少ETH转移到了pod中,但没有告诉你还有多少ETH在信标链上。这意味着 *我们无法判断* 我们看到的提款是否是我们将从该验证器看到的所有ETH,或者是否还有更多ETH在路上。
这使得基于提款证明调整份额变得困难,并导致 M2 份额会计中的模糊性和边缘情况。考虑以下情况:
0) 我在信标链上有一个拥有 32 ETH 的验证器,并且我已经证明我的验证器的提款凭证指向我的 pod。
ETH | 股份 |
---|---|
信标链上的 32 ETH | 32 ETH的股份 |
1) 然后,我从信标链中退出我的一个验证器。我*没有向我的 pod 证明*这一点。
ETH | 股份 |
---|---|
- 信标链上 0 ETH <br /> - 我的 pod 中 32 ETH | 32 ETH的股份 |
2) 接下来,我向我已退出的验证器存入 1 ETH。 这将被自动提取到我的 pod,但不会立即提取。目前,它只是记录在我的验证器的 `effective_balance` 中。
ETH | 股份 |
---|---|
- 信标链上 1 ETH <br /> - 我的 pod 中 32 ETH | 32 ETH的股份 |
3) 最后,我执行余额更新证明,向我的 pod 显示我的验证器只有 1 ETH。 因为我的 pod 上次看到的经过证明的余额是 32 ETH,所以这导致了 31 ETH 的股份减少。
ETH | 股份 |
---|---|
- 信标链上 1 ETH <br /> - 我的 pod 中 32 ETH | 1 ETH的股份 |
最终,这允许验证器歪曲他们 pod 中的股份数量,这在进行罚没时尤其危险。攻击者可能会提交恶意行为,然后如上所述操纵他们的信标链份额,以减少可以被罚没的股份数量。
攻击者承担的风险很小,因为 m2 证明系统仍然会接受丢失的提款证明 - 因此攻击者可以在罚没的危险过去后恢复他们的股份。
使用信标链证明,我们无法区分全部提款和部分提款,也无法依赖提款证明来确定事件的顺序。在 M2 中,我们应用了一种启发式方法来获得“最佳猜测”,但这个猜测存在一些会计怪癖,为未来的 EigenLayer 罚没版本带来了重大的攻击媒介。
*我们需要在发布罚没之前解决这个问题*。
---
检查点证明系统基于 pod 的“活跃验证器集”的概念。也就是说 - 信标链上的一组验证器,pod 知道这些验证器具有指向该 pod 的提款凭证。
当你证明验证器的提款凭证时,该验证器将进入 pod 的活跃验证器集。当你显示验证器已退出时,该验证器将离开 pod 的活跃验证器集。M2 系统已经使用了此状态模型: * `verifyWithdrawalCredentials` 将 `validatorInfo.status` 设置为 `ACTIVE`, 并将 `activeValidatorCount` 增加 1 * 在处理全部提款时,`verifyAndProcessWithdrawals` 将 `validatorInfo.status` 设置为 `WITHDRAWN` 并将 `activeValidatorCount` 减少 1
检查点证明将 pod 的活跃验证器集与信标链状态 *和* EigenPod 状态的快照相结合,以明确地确定 *有多少 ETH 支持 pod* 以及 *ETH 在哪里*。
struct Checkpoint {
bytes32 beaconBlockRoot; // 检查点开始之前的区块的信标区块根
uint256 podBalanceGwei; // 检查点开始时 pod 的 gwei 余额,减去已由股份支持的余额
int256 balanceDeltasGwei; // 信标余额的总变化,随检查点的进行而更新
uint256 proofsRemaining; // 完成检查点之前要证明的验证器数量
}
检查点证明有两个步骤:
uint256 podBalanceGwei =
(address(this).balance / GWEI_TO_WEI) - withdrawableRestakedExecutionLayerGwei;
// 使用前一个区块的根创建检查点以用于证明,以及当前的
// \`activeValidatorCount\` 作为完成检查点所需的检查点证明的数量。
Checkpoint memory checkpoint = Checkpoint({
beaconBlockRoot: _getParentBlockRoot(uint64(block.timestamp)),
podBalanceGwei: podBalanceGwei,
balanceDeltasGwei: 0,
proofsRemaining: activeValidatorCount
});
struct BalanceProof {
bytes32 pubkeyHash; // 要证明的验证器的公钥
bytes32 balanceRoot; // 验证器的编码余额
bytes proof; // 信标状态根内包含的默克尔证明
}
function verifyCheckpointProofs(
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.BalanceProof[] calldata proofs
)
external;
一旦提交了足够的证明,`verifyCheckpointProofs` 会自动完成检查点。要完成检查点,pod 会计算总股份增量并将其发送到 `EigenPodManager`:
int256 totalShareDeltaWei =
(int256(checkpoint.podBalanceGwei) + checkpoint.balanceDeltasGwei) * int256(GWEI_TO_WEI);
// 将 pod 中的任何原生 ETH 添加到 \`withdrawableRestakedExecutionLayerGwei\`
// ... 此金额可以通过 \`DelegationManager\` 提款队列提取
withdrawableRestakedExecutionLayerGwei += uint64(checkpoint.podBalanceGwei);
// 完成检查点
lastFinalizedCheckpoint = currentCheckpointTimestamp;
delete currentCheckpointTimestamp;
delete currentCheckpoint;
// 更新 pod 所有者的股份
eigenPodManager.recordBeaconChainETHBalanceUpdate(podOwner, totalShareDeltaWei);
emit CheckpointFinalized(lastCheckpointTimestamp, totalShareDeltaWei);
<!-- 检查点证明系统的关键细节是 *任何我们无法归因于(i)现有股份或(ii)当前信标链余额的 pod 中的 ETH 必须被授予股份*。这意味着股份将被授予部分提款,以及任何其他我们无法归因来源的 ETH。 -->
检查点证明系统的关键细节是 *任何我们无法归因于现有股份的 pod 中的 ETH 必须被授予股份*。这是因为 pod 中的原生 ETH 基本上是无法归因的 - 我们不知道该 ETH 来自哪里,因为有几个 ETH 来源绕过了合约执行: * *信标链完全提款* * *信标链部分提款* * *自毁* * *优先费用转移给区块生产者的费用接收者*
在这些来源中,我们需要特别考虑一个:对于具有经过验证的提款凭证的验证器,*来自信标链完全提款的 pod 中的任何 ETH 都已经获得了股份*!我们需要确保不要盲目地为 pod 中的任何 ETH 授予股份,因为这可能意味着我们正在重复计算已退出的验证器的股份。
为了避免重复计算,完成检查点证明会产生一个股份增量,该增量遵循以下等式,其中 $v(i)$ 是 pod 中具有 $n$ 个具有经过验证的提款凭证的验证器:
$$ \Delta \text{podShares} = \Delta \text{podBalance} + \sum_{i=0}^{n} \Delta \text{beaconBalance}[ v(i) ] $$
当验证器退出时,其 $\Delta beaconBalance$ 将为负数:其当前余额 (0) 减去其先前证明的 $beaconBalance$。此数字将添加到 $podBalance$,确保不会重复计算这些股份。
这也意味着 *股份将被授予部分提款*(以及任何其他我们无法归因来源的 ETH)。
`startCheckpoint` 获取的快照使我们能够消除 ETH“在哪里”的歧义,而 pod 的活跃验证器集中的余额证明的总和使我们能够消除“有多少”的歧义。这创建了一个我们可以用来授予股份的保证:
此保证的关键是 `startCheckpoint` 使用的快照过程,该过程会执行两项操作: * 直接使用当前 `block.timestamp` 作为输入调用 [EIP-4788 信标区块根 Oracle](https://learnblockchain.cn/docs/eips/EIPS/eip-4788#specification)。\*这将返回父信标区块根* - 即,与 `block.number - 1` 对应的信标区块根。 * 读取 pod 的: * `activeValidatorCount` * 当前 ETH 余额(减去已由股份支持的任何内容)
此检查点用作所有后续证明的起点。
uint256 podBalanceGwei =
(address(this).balance / GWEI_TO_WEI) - withdrawableRestakedExecutionLayerGwei;
// 使用前一个区块的根创建检查点以用于证明,以及当前的
// \`activeValidatorCount\` 作为完成检查点所需的检查点证明的数量。
Checkpoint memory checkpoint = Checkpoint({
beaconBlockRoot: _getParentBlockRoot(uint64(block.timestamp)),
podBalanceGwei: podBalanceGwei,
balanceDeltasGwei: 0,
proofsRemaining: activeValidatorCount
});
执行层/信标链区块处理的一个奇怪之处在于,在执行层中,信标链提款是在所有区块交易之后处理的(这实际上导致了我们在 Cantina 中的唯一一个“高”错误)。
这个怪癖意味着,如果我们快照 *当前* 信标区块根以及 *当前* pod ETH 余额,则可能: * 我们的余额证明显示“0”,因为提款刚刚被处理 * 在创建检查点时,ETH 不在 pod 中,因为 ETH 在区块结束之前不会到达 pod。
这就是为什么当调用 `startCheckpoint` 时,它会使用当前 `block.timestamp` 查询 EIP-4788 Oracle,这实际上会返回 *前一个区块的根*!这意味着当调用 `startCheckpoint` 时: * 前一个区块的信标链提款 *已经在 pod 中* * 如果验证器在该区块中有提款(或者如果他们在之前的区块中已完全提款),则针对前一个区块的根的证明 *将显示 0 余额* * *自上一个区块以来,没有信标链 ETH 进入 pod*
这些属性意味着在检查点中证明的 $beaconBalances$ 与在检查点开始时快照的 $podBalance$ 100% 不同,我们可以授予股份而无需担心重复计算。
随着 EigenLayer 原生支付和罚没的即将发布,EigenLayer 和 AVS 将依赖于核心协议报告的 EigenPod 股份价值,以便: * 根据质押者/运营者拥有的股份数量向他们支付报酬 * 对行为不端的质押者/运营者处以最高金额的股份罚没
因此,pod 会计系统的一个重要考虑因素是:**我们如何确保 pod 股份保持最新?** 毕竟,pod 会计系统的准确性在很大程度上取决于是否定期提供余额更新证明,因为这是它唯一可以看到信标链状态的“视图”。
请注意,由于以下几个事件,验证器的信标链余额可能会下降: * 验证器被罚没 * 验证器离线 * 验证器离线,*且 > 1/3 的所有信标链验证器也离线*
M2 对此问题的回答是 `EigenPod.verifyBalanceUpdate`,任何人(而不仅仅是 pod 所有者)都可以调用它来证明验证器的信标链余额自上次看到的证明以来已经上升或下降。但是,如果验证器的余额下降,*pod 所有者永远没有动力来证明这一点*,因为它会减少他们的股份。
检查点在这一点上略有不同:由于股份是针对部分提款授予的,因此当 pod 所有者希望时,他们有动力来证明余额更新: * 他们想完全退出一个验证器 * 他们的 pod 已经积累了足够的部分提款来抵消余额的下降
在大多数情况下,检查点系统提供了足够的激励来保持 pod 股份的最新状态。
通常,`startCheckpoint` 只能由 pod 所有者调用。这是因为检查点必须在启动新检查点之前完成 - 并且作为一个潜在的 gas 密集型过程,我们希望使 pod 所有者能够决定何时进行检查点是值得的。
但是,如果 *pod 中的很大一部分验证器在信标链上被罚没,* pod 所有者不太可能想要执行检查点。在这种情况下,我们依靠“陈旧性证明”来允许第三方代表 pod 所有者启动检查点。
任何人都可以向 `EigenPod.verifyStaleBalance` 提交陈旧性证明:
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external;
`verifyStaleBalance` 允许任何人提交证明,证明 pod 中的 ACTIVE 验证器在信标链上被罚没。
如果成功,这将允许调用者启动检查点。请注意,如果存在现有检查点,则调用将失败 - 需要完成现有检查点,此调用才能成功!
---
:::info 请在此处关注正在进行的合约工作:[`eigenlayer-contracts/#515`](https://github.com/Layr-Labs/eigenlayer-contracts/pull/515)。以下是更改的简要摘要。
**注意:目前没有针对此版本的具体ETA!** 这些说明是对将伴随该版本发布的合约更改的早期展望 - 我们希望尽早获得有关此的反馈,以了解这些更改是否对任何人造成重大问题! :::
*已删除*: * 余额更新证明 * `EigenPod.verifyBalanceUpdates()` * 提款处理 * `EigenPod.verifyAndProcessWithdrawals()` * `EigenPod.provenWithdrawal()` * `EigenPod.sumOfPartialWithdrawalsClaimedGwei()`
*已添加*:
interface IEigenPod {
/// 状态更改方法
function startCheckpoint(bool revertIfNoBalance) external;
function verifyCheckpointProofs(
BeaconChainProofs.BalanceContainerProof calldata balanceContainerProof,
BeaconChainProofs.BalanceProof[] calldata proofs
) external;
/// 事件
/// @notice 当创建检查点时发出
event CheckpointCreated(uint64 indexed checkpointTimestamp, bytes32 indexed beaconBlockRoot);
/// @notice 当检查点完成时发出
event CheckpointFinalized(uint64 indexed checkpointTimestamp, int256 totalShareDeltaWei);
/// @notice 当为一个给定的检查点证明了验证器的时候发出
event ValidatorCheckpointed(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex);
/// @notice 当一个验证器被证明在给定的检查点余额为0的时候发出
event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex);
/// 结构体
struct Checkpoint {
bytes32 beaconBlockRoot;
uint24 proofsRemaining;
uint64 podBalanceGwei;
int128 balanceDeltasGwei;
}
/// view 方法
function activeValidatorCount() external view returns (uint256); //注意 - 这个变量已经存在于M2中; 这个更改仅仅是让它公开!
function lastCheckpointTimestamp() external view returns (uint64);
function currentCheckpointTimestamp() external view returns (uint64);
function currentCheckpoint() external view returns (Checkpoint memory);
}
*上下文*:
有关这些方法如何工作的大部分上下文和解释可以在本文档的上半部分中找到。
总而言之,此版本删除了两个主要的 `EigenPod` 方法: * `verifyBalanceUpdates` * `verifyAndProcessWithdrawals`
取而代之的是,pod 所有者将使用: * `startCheckpoint` * `verifyCheckpointProofs`
这两种新方法应提供与已删除方法相同的所有功能,并具有以下额外好处: * *检查点证明会复合执行层奖励*; 即,当一个检查点完成时,部分提款将被记入可委派的股份 * *检查点证明会批量处理信标链提款(部分和全部)*。检查点证明不是每个提款提交一个证明,而是需要 *每个验证器一个证明* 来声称 pod 中的所有提款。 * Gas 估计表明每个验证器将花费大约 50-60k 的 gas。 * *不再依赖第 **三方信标链 Oracle 时间戳*不再需要等待第三方将时间戳添加到信标链 Oracle * *不再有 `DelayedWithdrawalRouter`方法。* 相反,已完成的检查点会将任何部分提款奖励为股份,这些股份可以通过 `DelegationManager` 提款队列提取,就像所有其他 EigenLayer 股份的提取方式一样。
*示例用户流程 - 声明部分提款*
*一些重要的注意事项*: * *一旦开始检查点,就无法取消。* pod所有者必须在开始新检查点之前完成现有检查点。 * 这主要是由于在检查点过程中更新/维护状态的困难。试图使检查点可取消最终增加了很多复杂性,因此我们采用了这种设计。 * *完成检查点不会将股份授予在检查点开始后进入 pod 的任何部分提款。* * 这是由于 [检查点快照过程如何工作](#What-Gets-Snapshotted)。要获得这些资金的股份,你需要另一个检查点。 * *提供一个显示验证器余额为 0 的检查点证明将把该验证器标记为 `WITHDRAWN` 并减少 `EigenPod.activeValidatorCount`。* 这意味着对于将来的检查点证明,你无需为该验证器提供证明。
---
*已添加*:
interface IEigenPod {
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external;
}
在大多数情况下,pod 所有者不需要考虑此方法 - 在信标链上验证程序已被削减的情况下,它允许第三方启动检查点。
有关更多说明,请参见上面的 [检查点激励和信标链削减](#Checkpointing-Incentives-and-Beacon-Chain-Slashing)。
*已删除:* * `EigenPodManager.beaconChainOracle()` * `EigenPodManager.updateBeaconChainOracle(...)` * `EigenPodManager.getBlockRootAtTimestamp(...)`
*已更改:* * `EigenPod.verifyWithdrawalCredentials(...)` * 取消了在 `block.timestamp` 的 `VERIFY_BALANCE_UPDATE_WINDOW_SECONDS (4.5小时)` 内使用 `oracleTimestamp` 的要求 * 取消了使用第三方添加到信标根 Oracle 的时间戳的要求 * 增加了在 24 小时内针对任何有效的信标链时间戳执行证明的能力,而无需等待 Oracle 更新 * 更改了时间戳语义:`oracleTimestamp` 参数现在对应于用于证明的信标块 *之后的下一个有效块*。 * 增加了此证明时间戳必须大于 `currentCheckpointTimestamp` 的要求 * 增加了要证明的验证程序必须尚未设置退出 Epoch 的要求
*上下文*:
正在对 `verifyWithdrawalCredentials` 进行一些小的更改,以确保它与新的检查点系统兼容。接口将保持不变,但是我们调整了一些可以处理提款凭据证明的条件。
在 M2 中,`verifyWithdrawalCredentials` 证明: * 需要使用添加到第三方控制的 `beaconChainOracle` 的特定 `oracleTimestamp` * 需要使用不早于 4.5 小时的 `oracleTimestamp`
这些都是我们 Deneb 之前系统的遗留物,该系统依赖于受信任的第三方提供的 `EigenPods` 的信标链区块根。但是,我们现在处于 Deneb 之后的世界,[EIP-4788](https://learnblockchain.cn/docs/eips/EIPS/eip-4788) 为我们提供了保障!
我们正在删除上面列出的两个要求。相反,`verifyWithdrawalCredentials` 证明: * 可以使用过去 24 小时内的任何有效的 `block.timestamp`,只要该时间戳晚于`currentCheckpointTimestamp` * 请注意,此 `block.timestamp` 应对应于用于证明的信标块 *之后的* 块的时间戳! 这是由于 [EIP-4788 的工作原理](https://learnblockchain.cn/docs/eips/EIPS/eip-4788#block-processing)。 * 如果正在证明的 [`Validator` container](https://eth2book.info/capella/part3/containers/dependencies/#validator) 显示验证员已设置 `exit_epoch != FAR_FUTURE_EPOCH`,则将恢复原状。 * 这是为了防止已经退出/即将退出的验证器证明提款凭据,因为它在检查点证明中引入了边缘情况问题。
---
*已删除:* * `EigenPod.activateRestaking` * `EigenPod.withdrawBeforeRestaking` * `EigenPod.withdrawNonBeaconChainETHBalanceWei` * `EigenPod.hasRestaked()` * `EigenPod.nonBeaconChainETHBalanceWei` * `EigenPod.mostRecentWithdrawalTimestamp` *已更改*: \ `EigenPod` 不再调用 `DelayedWithdrawalRouter` \* 已经在 `DelayedWithdrawalRouter` 中排队的提款将不会受到影响,并且可以在其预计日期被认领 \ 所有未来的提款将通过 `DelegationManager` 提款队列进行。
*背景 - Pod 激活*:
`activateRestaking` 最初旨在允许 M2 之前的 pod 所有者通过选择调用 `activateRestaking` 并在其 EigenPod 上启用 proofs 来“选择加入” M2 升级。 同样,`withdrawBeforeRestaking` 旨在允许未“选择加入”的 pod 所有者继续提取共识奖励,而无需参与 M2 证明系统。
通过 checkpoint proofs,M1 和 M2 pod 之间的这种分离不再重要,因为 checkpoint 过程直接支持这两种 featuresets: \ M1 pod 所有者可以通过调用 `startCheckpoint` 继续不 restaking 其验证者的 beacon chain ETH 并直接访问共识奖励。 \* 如果没有通过 `verifyWithdrawalCredentials` restaked 的验证者,`startCheckpoint` 将自动完成一个 checkpoint,该 checkpoint 将 pod 所有者奖励与 pod 的 native ETH 余额相等的 shares。 这些可以通过 `DelegationManager` 进行 restaked 或提取。 \ 已经 restaked beacon chain 验证者的 M2 pod 所有者可以像往常一样与 checkpoint 证明系统进行交互。
*背景 - 移除 `DelayedWithdrawalRouter`*:
因为现在这两种 featuresets 都涉及到 pod 所有者认领 shares 并通过 `DelegationManager` restaking/提取这些 shares,所以我们看到了通过完全移除 `DelayedWithdrawalRouter` 来进一步简化 EigenPod 系统的机会。
这是非常理想的,因为 `DelegationManager` 队列是 EigenLayer 的其余提款的处理方式,并且保留 `DelayedWithdrawalRouter` 意味着我们有 2 条单独的资金离开系统的路径。
由于我们正在移除 `DelayedWithdrawalRouter`,因此它通过 `withdrawNonBeaconChainETHBalanceWei` 的使用也将被移除。
---
#### 已弃用:杂项
\ 移除 `EigenPod.MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR` \ 这是 M2 之前的代码的遗留物,该代码将验证者余额限制为 32 ETH。 它在 M2 代码中并没有真正使用,也不会在 checkpoint 代码中使用。 截至 [Pectra hard fork](https://learnblockchain.cn/docs/eips/EIPS/eip-7600),验证者可能能够拥有远远超过 32 ETH 的余额。
---
### 补充说明
#### 与 Pectra 的兼容性
[Pectra hard fork](https://learnblockchain.cn/docs/eips/EIPS/eip-7600) 带来了几个重大变化,其中最重要的变化如下所示。
1) *MaxEB 增加到 2048 ETH* 意味着验证者可以拥有更高的余额,并且可能具有自定义的部分提款扫描上限。 M2 证明系统将难以支持这一点,因为它试图区分部分/完全提款。 但是,checkpoint proofs 并不关心哪个是哪个!
2) *Validator consolidation* 允许将具有相同提款凭证的两个验证者(`source` 和 `target`)合并。 这会将 `source` 验证者的余额设置为 0,并将 `target` 验证者的余额设置为 `target + source`。
是否在共识层或执行层启动 consolidation 仍然有待确定(详情如下)。 在后一种情况下,`EigenPod` 本身将公开方法以允许 pod 所有者启动 consolidation。
一般来说,checkpoint proofs 可以毫无问题地处理 consolidation。 因为 `source` 的余额为 0,所以 checkpoint proof 会将其移动到 `WITHDRAWN` 状态,并且不需要进一步的证明。 同样,`target` 验证者的余额增量将仅包括 `source` 验证者之前的余额,因此总的 share 增量不应更改。
但是,重新计算 checkpoint proofs 仅对 pod 的 `ACTIVE` 验证者集中的验证者(已验证的提款凭证 + 未 `WITHDRAWN`)是必需的,因此需要考虑几个重要的边缘情况: \ `source: INACTIVE, target: ACTIVE`: 如果 `source` 没有经过验证的提款凭证,则 `target` 的余额变化将在下一个检查点中被拾取。 \ 对于共识层 consolidation,这可能会允许 `source` 合并到 `target` 中,然后在 \同一 epoch 中调用 `startCheckpoint` 的边缘情况。 如果 `source` 随后使用 *在 `startCheckpoint` 之后,但在同一 epoch 中 的时间戳验证提款凭证,则提款凭证证明中使用的 `effective_balance` 将不会反映 consolidation。 \ 从现有的 EIP 规范中尚不清楚 consolidation 是否会以任何方式更改 `Validator` 容器状态。 例如,如果它设置了该验证者的 `exit_epoch`,那么在这种情况下验证提款凭证将是不可能的,这不是问题(如果验证者具有 `exit_epoch`),则 `verifyWithdrawalCredentials` 会 revert) \ 如果未对 `Validator` 容器进行任何更改,我们将需要更改 `verifyWithdrawalCredentials` 以使用 `current_balance`,就像 checkpoint 系统使用的一样。 \ 对于执行层 consolidation,这不是问题 - 我们可以简单地拒绝没有经过验证的提款凭证的验证者的 consolidation。 \ `source: ACTIVE, target: INACTIVE`: 如果 `target` 没有经过验证的提款凭证,则 `target` 的余额变化将不会在下一个 checkpoint 中被拾取。 \ 对于共识层 consolidation,这是一个令人讨厌的问题要处理。 在此 consolidation 之后进行检查点将显示 `source` 余额降至 0,并且 pod 的 ETH 余额中没有相应的余额增加。 看起来 ETH 消失了 - 同样,checkpoint 系统将相应地扣除 shares。 这不会使用户的资产面临风险,但是对于将来的 EigenLayer slashing 功能,我们不希望 stakers 能够“暂时删除”其可 slashing 的资产! \ 这里的解决方案是同时打开 `verifyWithdrawalCredentials` 以供任何人调用(而不仅仅是 pod 所有者),并运行 watchers 来监视 pods 是否存在这种类型的活动。 这不是理想的选择,但实际上没有其他选择。 \ 对于执行层 consolidation,这不是问题 - 我们可以简单地拒绝没有经过验证的提款凭证的验证者的 consolidation。
现在主要的问题是 consolidation 是在共识层还是在执行层启动。 在前一种情况下,我们需要做几件事: \ 打开 `verifyWithdrawalCredentials` 以供任何人调用,而不仅仅是 pod 所有者 \* 运行 watchers 来监视 `source -> target` consolidation,其中 `target` 为 `INACTIVE`。 \ 根据 `Validator` 容器由于 consolidation 而发生的变化,我们可能需要更改 `verifyWithdrawalCredentials` 以使用 `current_balance` 证明以及它们当前使用的 `Validator` 容器证明。
*如果在执行层启动 consolidation,我们不需要进行任何立即的更改!* 我们可以(稍后)选择将 consolidation 支持添加到 `EigenPod` 接口,并包括上述规则以避免其相关的边缘情况。
#### 尚未提及
(可能不完整)本文档尚未明确提及的事项的集合 - 希望让你们今天先睹为快; 如果你们愿意,我们可以讨论这些内容! \ Checkpoint proofs 重新引入 current balance proofs 以代替 `effective_balance` 证明,因为后者导致歧义。 \ 但是,在我们以前的 current balance proofs 非常昂贵,因为我们在 `validators` 和 `current_balances` 树中都证明了一些东西,而新的 balance proofs 只需要后者。 在提款凭证得到证明后,我们不需要检查 `Validator` 容器。 \ 我们不再使用提款 proofs - 仅使用 `verifyWithdrawalCredentials` 和 balance proof 快照。 \* 如果验证者的快照 balance proof 显示“current balance”为 0,我们会将验证者移动到 `WITHDRAWN` 状态。 \ 当验证者在被标记为 withdrawn 后重新 deposit 会发生什么? 如果验证者退出到 pod,但他们从未验证提款凭证呢? \ 当 checkpoint 最终确定后,如果这两种情况中的任何一种发生,那么 ETH 将以“未入账”的形式出现在 pod 中(即在 checkpoint 的 `podBalance` 部分)。 我们像其他东西一样奖励它 shares。 \ 更新余额的激励措施(以及平衡这些激励措施与付款/slashing)。 供讨论!
- 原文链接: hackmd.io/U36dE9lnQha3tb...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!