ELIP-004: 具有罚没感知能力的 EigenPod

该提案(ELIP-004)介绍了对 EigenPod 合约的修改,使其能够感知 slashing 且与 Pectra 兼容。

作者 创建时间 状态 参考资料 讨论
Matt Nelson, Alex Wade, Yash Patil, Matt Curtis 2025/02/10 已合并 仓库 讨论论坛

ELIP-004: 具有罚没感知能力的 EigenPod


概要

罚没升级是迈向完整 EigenLayer 的一个关键里程碑。作为更大规模的罚没发布的一部分,EigenPod 正在升级,以适应一些底层更改,这些更改实现了 Unique Stake 模型、Operator Sets,以及作为这两者的产物,AVS 罚没。有关罚没以及实现它的机制的更多信息,请参见 ELIP-002

本提案介绍了对 EigenPod 合约的有针对性的更改,使其具有罚没感知能力并与 Pectra 兼容。升级 Pod 可以使原生重新质押的 ETH 在用作可罚没质押时,在功能上与 ERC-20 保持一致。此升级的范围对 EigenPod 引入了重大更改,并更新了多个接口。总的来说,此升级带来了:

  • 具有罚没感知能力的 EigenPod 合约,可以正确核算 Native ETH 罚没,
  • 引入 Beacon Chain 罚没因子,以在 EigenLayer 中正确传播外部以太坊罚没,
  • 一个新的检查点结构,
  • 在相关升级期间暂停检查点
  • 修改后的 EigenPod 提款流程,以将以太坊和/或 AVS 罚没应用于从 EigenPod 提取的资产。

这些升级共同正确地核算了以太坊 AVS 罚没之间的交互,并确保在升级和提款过程中平稳过渡。

此外,即将到来的以太坊 Pectra 硬分叉包括对证明生成库的重大更改,并增加了执行层触发的验证器提款。本提案包括升级,以确保 EigenPod 在硬分叉后仍保持功能。

动机

罚没需要对 EigenLayer 中使用的会计系统进行许多更改。在 Operator 和 Staker 的 stake 发生减少的情况下,罚没会计必须正确地传播到 stake 生命周期的各个阶段,例如待处理的提款。它还需要在数据存在和显示的各个位置保持一致。

虽然 ERC-20 在设计上非常灵活,但原生重新质押的 ETH 带来了一些不同的挑战,因为它存在于以太坊的共识层上,并且 EigenLayer 执行环境无法立即访问。此外,共识层也可能会削减此 ETH,EigenPod 必须核算 EigenLayer 上的这种 stake 减少,即使该 stake 已分配给 AVS 的可削减 Operator Set。

在底层,EigenLayer 处理原生 ETH Strategy 的方式与其他 ERC-20 Strategy 不同。由于 Strategy 与 ELIP-002 中提出的罚没设计紧密耦合,因此 EigenPod 设计中出现了一些极端情况。这些需要对 EigenPod 进行升级,使其与罚没向前兼容,为在 L1 上 Pectra 升级之后进行进一步改进做好准备,并确保使用原生 ETH 作为 Unique Stake 时的必要安全属性。所有资产对于保护 AVS 都至关重要,本提案确保它们都具有相同的功能。

特性与规范

目标

在 EigenLayer 上进行原生 ETH 重新质押对于 AVS 来说是一个有价值的安全维度,重新质押的 ETH 约占质押信标链 ETH 供应量的 \~4%。此升级旨在:

  • 保持 EigenLayer 对原生 ETH 和 ERC-20 的对等性,以确保 AVS 拥有多个资产类别可用作 Unique Stake,
  • 引入 beaconChainSlashingFactor,以便 EigenPod 在会计处理和提取时具有罚没感知能力,
  • 实现与Pectra 后罚没的前向兼容

上述目标通过更新 EigenPodEigenPodManagerDelegationManager 中的合约和接口来实现。

EigenPod 会计变更

本提案更改了信标链会计系统,以将原生重新质押的 ETH 与其他代币同等对待,以便在罚没期间进行更适当的处理。建议你在继续之前,了解 ELIP-002 中描述的罚没幅度 (Slashing Magnitudes) 和 Unique Stake。这些 EigenPod 更改包含在更广泛的罚没版本中,并且不是正交的。

如今,所有 EigenPod 余额更新都使用 检查点系统 进行核算。检查点允许在 Staker 和 Operator 之间正确核算以太坊验证器的余额变化。以太坊验证器的余额会不断变化,要么是通过以太坊奖励分配增加,要么是在验证器遭受处罚或罚没时减少。你可以在此处了解有关以太坊处罚和奖励的信息。

检查点会累积这些变化,并且节点运营者会定期检查它们,以更新 EigenLayer 上 Pod 的余额。这还会更新相应的 stake 值,这些 stake 值会在委托的 Operator 及其任何 Native ETH 分配中传播。在极少数情况下,例如信标链罚没,不控制 Pod 的其他人可能会检查 Pod 的余额,以确保在 EigenLayer 中进行正确的核算。

EigenPod 的独特之处在于,它们必须核算 EigenLayer 内部的罚没(即由 AVS 发起)信标链验证器罚没。对于每个单独的 EigenPodEigenPodManager 跟踪一个新的 beaconChainSlashingFactor。这个整数是一个单调递减的值,表示每个 Native Restaker 的底层 Beacon Chain stake 的处罚累积。它以 wads 表示,并在每次 EigenPod 检查点更新。

完成 EigenPod 的检查点后,负余额增量不再直接减少 stake 核算。相反,EigenPod 所有者新旧余额的比例变化会累积在 beaconChainSlashingFactor 中。现在,它用于跟踪 Pod 的份额实际对应的资产数量 (代码链接):

/**
 * @notice 返回 pod 所有者在更新其 pod 余额时所经历的比例余额减少的历史总和。
 */
function beaconChainSlashingFactor(
  address staker
) external view returns (uint64);

beaconChainSlashingFactor 在每个 EigenPod 合约中都以 INITAL_BEACON_CHAIN_SLASHING_FACTOR 初始化。此因子与给定 ERC-20 Strategy 的 Operator 的 INITIAL_TOTAL_MAGNITUDE 类似。beaconChainSlashingFactor 会因 EigenPod 的 ETH 和已完成的检查点中经过验证的验证器的任何减少而减少(例如,从 1.0 减少到 0.8)。beaconChainSlashingFactor 的这种减少与经过验证的总余额的减少成正比(在前面的示例中减少了 20%)。

“余额减少” 专门指 Pod 的原生 ETH 余额加上其验证器余额的总和 严格小于 上次完成 EigenPod 的检查点或提款时。以下公式给出了 Pod 余额:

\Delta \text{podShares} = \Delta \text{podBalance} + \sum_{i=0}^{n} \Delta \text{beaconBalance}[ v(i) ]

在实践中,beaconChainSlashingFactor 仅应在任何验证器遭受非活动处罚或在信标链上被罚没时受到影响。使用 beaconChainSlashingFactor 的任何函数都是原子的。它们将正确处理 在信标链上 的任何全部和部分提款核算。由于上述公式中的 beaconBalance 会随着任何验证器退出的函数而减少,因此 podBalance 的增加将反映此更改,如果在发生信标链的惩罚,则保持罚没因子一致。

虽然原生 Restaker 主要受到这些变更的影响,但 Operator 和 AVS 应注意以下几点:

  • 当用于保护 Operator Set 时,原生 ETH 的处理方式与其他 Strategy 相同,
  • 在考虑其用途时,Operator 应将原生 ETH 的分配与其他分配相同对待,
  • AVS 可以选择评估原生 ETH 的安全性与其他资产不同,但它的行为与 Operator Set 中的任何其他 Unique Stake 相同。但是,外部风险因素(例如验证器罚没)可能会减少可用的 Unique Stake。在某些方面,这种风险可以被认为类似于 LST 脱钩。

通过使用 beaconChainSlashingFactor,可以轻松且正确地在协议中传播余额更改。它已合并到链下和链上实体使用的所有视图函数中,以确定 Staker 在 DelegationManager 中的实际 stake。beaconChainSlashingFactor 将罚没惩罚应用于 Native ETH Strategy 中 Operator 的所有份额,包括未完成的提款。

EigenPod 提款

当向节点运营者展示功能时,提款将在很大程度上保持不变。在 Staker 提款时,beaconChainSlashingFactor 将应用于 Native ETH。如果 AVS 已削减委托的 Operator,则 Strategy Magnitudes 的任何更改都将应用于提取的资产。ELIP-002 更详细地分解了该过程。

以下是新的提款界面。Stake 内省处理方式如下所示,进行了一些修改。函数 getWithdrawableShares 已从 EigenPodManager 移动到 DelegationManager

/**
 * @notice 给定一个 staker 和一组 strategy,返回他们可以排队等待提款的份额和相应的 depositShares。
 * 此值取决于 staker 委托给哪个 operator。
 * 返回的份额数量是 staker 将收到的 Strategy 份额的实际数量(取决于每个 strategy 的底层份额与代币的比率)。
 */
function getWithdrawableShares(
  address staker,
  IStrategy[] memory strategies
) external view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares);

 /**
     * @notice 返回 staker 及其所有 strategy 的存储份额数量
     */
    function getDepositedShares(
        address staker
    ) external view returns (IStrategy[] memory, uint256[] memory);

在查看 Pod 可用的可提取份额数量时,应将此函数视为事实的来源。此 getWithdrawableShares 函数中返回的 uint256[] memory depositShares 也返回相同的 depositSharesEigenPodManager 中的 podOwnerShares 内省已弃用。getDepositedShares 将返回 Staker 存入的原始数量,而不应用罚没和处罚。

排队提款

现在,排队提款时发出的事件名为 SlashingWithdrawalQueued。更新后的提款事件和结构如下:

/**
 * @notice 当新的提款被排队时发出。
 * @param withdrawalRoot 是 `withdrawal` 的哈希值。
 * @param withdrawal 是提款本身。
 * @param sharesToWithdraw 是与 `withdrawal` 中的 strategy 对应的预期提款份额的数组。
 */
event SlashingWithdrawalQueued(
    bytes32 withdrawalRoot, 
    Withdrawal withdrawal, 
    uint256[] sharesToWithdraw
);

/// @notice 当排队的提款完成时发出
event SlashingWithdrawalCompleted(bytes32 withdrawalRoot);

/**
 * 用于指定现有排队提款的结构体类型。不存储整个结构体,而仅存储哈希值。
 * 在对现有排队提款进行操作的函数中 -- 例如 `completeQueuedWithdrawal`,数据被重新提交,并且提交数据的哈希值由 `calculateWithdrawalRoot` 计算并与存储的哈希值进行比较,以确认提交数据的完整性。
 */
struct Withdrawal {
    // 发起提款的地址
    address staker;
    // 创建提款时 staker 委托给的地址
    address delegatedTo;
    // 可以完成提款 + 完成提款时将收到资金的地址
    address withdrawer;
    // 用于保证其他相同提款具有唯一哈希值的随机数
    uint256 nonce;
    // 创建提款时的区块号。
    uint32 startBlock;
    // 提款包含的 strategy 数组
    IStrategy[] strategies;
    // 包含 `strategies` 数组中每个 Strategy 中 staker 的 scaledShares 提款数量的数组
    // 请注意,这些 scaledShares 在完成时需要乘以 operator 的 maxMagnitude 和 beaconChainScalingFactor,以包括在提款排队期间发生的罚没。这是因为 scaledShares = sharesToWithdraw / (maxMagnitude * beaconChainScalingFactor)
    // 在排队时间。如果 strategy 不是 beaconChainStrategy,则 beaconChainScalingFactor 简单地等于 1。
    // 为了核算罚没,我们稍后在最早可能的完成时间将 scaledShares * maxMagnitude * beaconChainScalingFactor 相乘,以获得在延迟期间应用罚没后提取的份额。
    uint256[] scaledShares;
}

完成提款

排队提款会发出一个带有 withdrawal 结构的事件,该结构目前必须被索引并在 WITHDRAWAL_DELAY 周期后传递到 completeQueuedWithdrawal 函数中。前端可用于提供此 calldata,但并非严格强制性的。使用罚没更新:

  1. 排队提款时发出的事件会发生变化(如上所示)。
  2. completeQueuedWithdrawal 参数会发生变化(以删除未使用的参数)。

新的完整提款界面如下。具体来说,我们从两种完整方法中删除了未使用的 uint256 参数 (middlewareTimesIndex)。通过使用 getQueuedWithdrawals 函数来内省提款,人们只需通过 RPC 调用即可完成提款,从而无需运行索引器来完成提款。

// 一项提款,通过索引提款结构或调用 `getQueuedWithdrawals` 获得。
function completeQueuedWithdrawal(
      Withdrawal calldata withdrawal,
      IERC20[] calldata tokens,
      bool receiveAsTokens
)

// 许多提款,通过在排队时索引提款或调用 `getQueuedWithdrawals` 获得。
function completeQueuedWithdrawals(
      Withdrawal[] calldata withdrawals,
      IERC20[][] calldata tokens,
      bool[] calldata receiveAsTokens
)

// 内省当前排队的提款。仅返回在罚没升级后排队但未完成的提款。
function getQueuedWithdrawals(
      address staker
) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares)

检查点

引入 Beacon Chain 罚没需要新的检查点结构和定义。在下面的结构体中,添加了 prevBeaconBalanceGwei 以计算更新 beaconChainScalingFactor 所需的比例差异。此外,balanceDeltasGwei 也已减少到 int64

以下是 EigenPod 合约中的新检查点结构:

struct Checkpoint {
  bytes32 beaconBlockRoot;
  uint24 proofsRemaining;
  uint64 podBalanceGwei;
  int64 balanceDeltasGwei;
  uint64 prevBeaconBalanceGwei;
}

此更改与现有未完成的检查点不向后兼容。 将在罚没升级之前暂停创建检查点。 所有未完成的检查点将在升级之前完成。升级发生后,将恢复创建检查点。时间表将与社区仔细沟通,并留出充足的时间。该过程将如下所示,并在以太坊 L1 上每次网络分叉前约 6 小时开始:

  1. 暂停新的检查点创建和凭据证明生成
  2. 升级核心合约(在每个网络上)
  3. 在 Pectra 分叉时间戳过去后,设置它。这必须在我们可以在下一个可用的区块中包含交易的合约中完成
  4. 恢复检查点创建和凭据证明生成

所有具有负余额的 EigenPod 必须完成其提款,以确保在处理新的检查点之前余额为非负数。这将影响极少数 EigenPod,因为只有在提款排队后验证器被罚没/处罚时,才会发生这种情况。要检查是否需要在发布升级之前完成提款,请查询 EigenPodManager.podOwnerDepositShares。如果此查询返回负值,则需要完成提款。升级后,任何具有负余额的 EigenPod 都需要使用标志 receiveAsTokens == false 完成提款才能解决负余额。这将将任何剩余的 ETH 留在 EigenPod 中,并重新启用检查点,这必须在新提款排队之前完成。

Pectra 后的罚没

随罚没版本一起交付…

Pectra 导致 EigenPod 证明生成库 发生重大更改,需要更新链上证明处理和链下库。在生成证明时,库版本将支持现有验证器 (0x01) 和具有新的 0x02 复合提款凭据 的验证器。

在 Pectra 硬分叉之前,将在 EigenPod 上暂停启动检查点和凭据证明。在暂停期间,可以完成已启动的检查点。硬分叉后,将升级 EigenPod,之后凭据和检查点证明将取消暂停。

支持此重大更改的升级取决于 Pectra 硬分叉的时间。库将在测试网络和主网络上各种分叉之前进行更新。一旦以太坊基金会发布,这些更改生效的时间戳将被纳入升级。

在 Pectra 升级之前,罚没的信标链 Ether 将无限期地锁定在 EigenPod 合约中。没有计划使其可恢复。

在单独的待定版本中…

Pectra 在以太坊中提供了一个关键的功能,该功能将在发布时能够更强大地处理 EigenPod 中的罚没。也就是说,EigenPod 将能够使用 EIP-7002,执行层可触发的提款。在以太坊的 Pectra 硬分叉 以及单独的 EigenLayer 协议升级 之后,提款机制将发生变化。原生重新质押的 ETH 可能会被强制退出被罚没的信标链验证器到相关的 EigenPod 合约中使用 EIP-7002,然后将被退出的 ETH 的被罚没部分发送到 0x00…000e16e4 地址。此设计旨在具有指示性,并且可能会发生变化。后续的 ELIP 将概述提议利用 Pectra 的这些变更。

理由

为什么 EigenPod 需要升级?

当前的 EigenPod 核算系统允许 staker 的份额通过尝试将 pod 所有者递减在检查点中验证的减少份额数量来承担负值。在罚没后保留此逻辑是有问题的,因为:

  1. 它要求我们在系统的其他部分实现可以承担负值的变量,这使得协议更难理解和实现。
  2. 它以不同于 LST 和其他代币的方式处理罚没原生 ETH…
    1. 假设信标链上的 rETH 总供应量为 100 ETH,转换率为 1:1,并且所有这些都已在 EigenLayer 中质押。如果在 EigenLayer 上削减 50%,然后在信标链上削减 50 ETH,这会使 staker 留下 50 rETH,其在信标链上价值 25 ETH
    2. 假设 EigenPod 在信标链上验证了 100 个原生 ETH 份额。如果 AVS 在 EigenLayer 上将此 Native ETH Strategy 削减 50%,则该 strategy 的 Operator 幅度会按比例减少。现在在信标链上又削减了 50%。如果没有罚没因子,提款会将两个 50% 的减少传播到上次检查点中验证的 100 ETH,从而在提款时获得 0 ETH。
      • 通过单独记录的 Strategy Magnitude 和 beaconChainSlashingFactor,提款会按比例应用两次减少。ETH Strategy 减少了 50%,剩下 50 ETH。接下来,将 .5 beaconChainSlashingFactor 应用于 50 ETH,从而获得 25 ETH 的提款。
    3. 区分两种 strategy 的处理方式会使系统更难推理

升级使系统更加一致并降低了实施复杂性。

为什么在升级期间必须暂停检查点创建?

升级后修改了检查点代码,并且与现有未完成的检查点不兼容。为了适应对 EigenPod 的更改,我们将在罚没发布之前执行迁移。该过程大致包括:

  • 在主网上线罚没发布前约 6 小时,将为所有 EigenPod 暂停 EigenPod.startCheckpoint 方法。
  • 执行罚没发布时,将取消暂停 EigenPod.startCheckpoint,并且可以恢复正常操作。

为什么必须阻止检查点完成,直到份额为非负数?

升级后的检查点完成逻辑与负份额不兼容,因此本提案将使在负份额上下文中完成检查点恢复。相反,必须完成待处理的提款,直到份额为非负数,然后才能完成检查点。

如果在罚没发布时你具有负的 stakerDepositShares,你将无法完成检查点或向你的 pod 添加新的验证器。请参阅此处的具体检查和说明。为了解决这种情况,你需要使用 receiveAsTokens == false 完成 DelegationManager 中的任何现有提款。

从安全的角度来看,此检查点暂停没有问题,因为 AVS 已经认为具有负份额的 EigenPod 的 stake 资金为 0,并且没有收到任何奖励。

安全注意事项

存在这样一种情况,即当所有附加的验证器都在信标链上被完全削减 (100%) 并且 EigenPod 上没有其他资产时,EigenPod 合约会变得完全无法运行。它将变得 "bricked" 或无法运行,这意味着即使添加了新资产或验证器附加到 Pod,它仍然无法运行。

这被认为是公开的安全问题,但由于 Beacon Chain 罚没的性质,尚未发生完全 100% 的削减,并且这种情况非常罕见。

影响总结

原生 Restaker (EigenPod Staker)

EigenPod staker 主要应注意检查点的暂停。如果你通过前端与你的 Pod 交互,这些更改将反映在 app.eigenlayer.xyz 上。

随着罚没上线,值得回顾你的 EigenPod 的委托和提款流程。如果你的 stake 已委托给运营商,他们将有权将该 stake 分配为可削减的。如果需要进行任何更改以反映新的风险状况,请确保你拥有适当的提款凭据,并且你已了解更广泛的提款和重新委托流程。你可以在 ELIP 中了解有关罚沒对 staker 的意义的更多信息。

如果你计划使用智能合约接口与你的 Pod 交互,请查看上面概述的更改。

LRT

LRT 应仔细审查新的合约接口,主要与以下方面相关:

  • Stake 内省,
  • 提款…

这两者都具有与之相关的重大更改。通过 stake 内省,getWithdrawableShares 已从 EigenPodManager 移动到 DelegationManager

已更改提款以适应新的 EigenPod 会计处理和一些生活质量改进。传递新的提款结构时,现有的代码路径将起作用。提款流程的更改已在 罚没 ELIP 的提款部分 中概述。

参考资料和相关讨论

https://hackmd.io/@-HV50kYcRqOjl_7du8m1AA/rJOX08AG1x

  • 原文链接: github.com/eigenfoundati...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
eigenfoundation
eigenfoundation
江湖只有他的大名,没有他的介绍。