本文深入探讨了 EigenLayer 的 slashing 机制中一个有趣的边缘案例,该案例涉及信标链 slashing factor 的计算,并可能导致提款份额计算的不一致性。文章通过一个实际例子详细阐述了在不同时间点验证验证器可能导致不同提款份额的情况,并分析了 EigenLayer 对此的回应,强调了频繁执行 EigenPod 检查点的重要性。
注意:这篇文章假设你已经对 EigenLayer 的再质押协议和 M4 智能合约有很好的理解(在引入 slashing 升级之前)。
EigenLayer 的 slashing 机制是其再质押协议不可或缺的组成部分,因为它能约束 AVS 运营商。在 ELIP-002 中引入的 slashing 机制为 EigenLayer 再质押协议带来几个新概念,这些概念共同创建了一个强大的 slashing 系统,可以处理 EigenLayer 原生的 slashing 和信标链的 slashing 事件。
在这篇文章中,我们将探讨在这种机制中发现的一个有趣的边界情况,该情况会影响在特定情况下如何计算可提取份额。但首先,让我们对 slashing 升级有一个基本的了解。
关于 EigenLayer 的 slashing 机制的详细说明可以在 ELIP-002 中找到。
为了理解这篇文章,我们将简要介绍如何计算可提取份额。
有三个重要的因素共同决定了某个质押者的“可提取份额”:
存款缩放因子 (DSF) - 每个质押者、每种策略的值,用于缩放质押者随着时间推移存入资产的存款份额。这个因子有助于解释可能发生在存款之间的 slashing,以便新的存款不会因之前的 slashing 事件而受到惩罚。这个因子会随着在 slashing 事件后进行新的存款而增加,并在质押者委托给新的运营商或增加其存款份额(从零开始)时重置。
最大幅度 (MM) - 这代表了在运营商集合中,经过 EigenLayer 原生 slashing 后,运营商的委托质押中保持未被 slashed 的比例。AVS 通过降低某些运营商集合中的最大幅度来 slash 其运营商。随着运营商被 slashed,这个比例会随着时间推移而单调递减。
信标链 Slashing 因子 (BCSF) - 这代表了在信标链上发生 slashing 事件后,质押者的信标链 ETH 中保持未被 slashed 的比例。随着质押者的信标链 ETH 被 slashed,这个比例会随着时间推移而单调递减。
注意:你可能还会遇到 Slashing 因子 (SF)。这只是 MM 和 BCSF 的乘积。它代表了在 EigenLayer 原生 slashing 和信标链 slashing 之后,质押者的存款份额中保持未被 slashed 的比例。
可以使用以下公式计算质押者的可提取份额:
withdrawableShares=depositShares×DSF×MM×BCSF
这种机制有两个有趣的相互交织的特性:
AVS 的 slashing 和信标链的 slashing 是彼此独立处理的,但两者都应用于相同的存款份额。这意味着相同的份额有可能被 slash 两次(一次由 AVS slash,一次由信标链 slash)。
AVS 的 slashing 采用百分比形式,而信标链的 slashing 采用绝对 ETH 值(以 gwei 为单位)。这可能导致不清楚有多少 ETH 被 slashed。例如,考虑到 32 ETH 的初始余额,AVS slash 了 50% 的 MM,然后信标链 slash 了 16 ETH,导致可提取份额为 8 ETH,即使质押者在信标链 slash 之前已经拥有 16 ETH 的可提取 ETH。这是因为 32 ETH 中的 8 ETH 被 slash 了两次。
图 1: AVS 的 slashing 和信标链的 slashing 如何影响相同的质押,从而导致对同一 ETH 进行双重 slashing 的可视化。
在调查 EigenLayer 的代码时,我们发现在信标链 slashing 因子计算中存在一个有趣的边界情况,根据相对于检查点验证验证器的时间,可能会导致不一致的可提取份额计算。
根本原因在于 EigenPodManager.sol
中的 _reduceSlashingFactor()
函数:
function _reduceSlashingFactor(
address podOwner,
uint256 prevRestakedBalanceWei,
uint256 balanceDecreasedWei
) internal returns (uint64) {
uint256 newRestakedBalanceWei = prevRestakedBalanceWei - balanceDecreasedWei;
uint64 prevBeaconSlashingFactor = beaconChainSlashingFactor(podOwner);
// newBeaconSlashingFactor 小于 prevBeaconSlashingFactor,因为
// newRestakedBalanceWei < prevRestakedBalanceWei
uint64 newBeaconSlashingFactor =
uint64(prevBeaconSlashingFactor.mulDiv(newRestakedBalanceWei, prevRestakedBalanceWei));
uint64 beaconChainSlashingFactorDecrease = prevBeaconSlashingFactor - newBeaconSlashingFactor;
_beaconChainSlashingFactor[podOwner] =
BeaconChainSlashingFactor({slashingFactor: newBeaconSlashingFactor, isSet: true});
emit BeaconChainSlashingFactorDecreased(podOwner, prevBeaconSlashingFactor, newBeaconSlashingFactor);
return beaconChainSlashingFactorDecrease;
}
如上一节所述,信标链的 slashings 与 AVS 的 slashings 是独立处理的。因此,BCSF 的计算不考虑 MM 或 DSF,而仅使用信标链上报告的余额。
由于 DSF 没有被纳入 BCSF 的计算中,因此当质押者被 AVS slashed 后,验证者在信标链上被 slashed 时,BCSF 可能会过度降低。
这个边界情况可能有点令人困惑,因此让我们用一个实际的例子来分解它,并记录每个步骤之后可提取份额和因子的任何变化。
考虑以下情况:
情景 A:第二个验证者在 EigenPod 检查点之后被质押和验证
withdrawableShares = 32 ETH
)withdrawableShares = 8 ETH
,MM = 0.25
)withdrawableShares = 4 ETH
,BCSF = 0.5
)withdrawableShares = 36 ETH
,DSF = 4.5
)其中:
DSF=newWithdrawableSharesnewDepositShares×SFstepFour=3664×(0.25×0.5)=4.5
finalWithdrawableSharesA=depositShares×DSF×SF=64×4.5×(0.25×0.5)=36
情景 B:第二个验证者在 EigenPod 检查点之前被质押和验证
withdrawableShares = 32 ETH
)withdrawableShares = 8 ETH
,MM = 0.25
)withdrawableShares = 40 ETH
,DSF = 2.5
)withdrawableShares = 30 ETH
,BCSF = 0.75
)其中:
DSF=newWithdrawableSharesnewDepositShares×SFstepTwo=4064×0.25=2.5
finalWithdrawableSharesB=depositShares×DSF×SF=64×2.5×(0.25×0.75)=30
请注意,情景 A 和 情景 B 会给出不同的最终可提取份额。
更令人感兴趣的是,情景 B 导致的最终可提取份额小于 32 ETH,这是在步骤 4 中质押并验证第二个验证者后存款份额的增加量。这意味着第二个验证者的 ETH 正在被 slash,即使它在技术上没有被 AVS 或信标链 slash。
为了计算预期的最终可提取份额,我们可以拆分两个验证者的存款份额,并分别对每个验证者应用 slashing。 由于 AVS 和信标链的 slashings 仅适用于属于第一个验证者的存款份额,我们可以按如下方式计算预期的最终可提取份额:
finalWithdrawableSharesexpected=withdrawableSharesvalidatorOne+withdrawableSharesvalidatorTwo=depositSharesvalidatorOne×SFvalidatorOne+depositSharesvalidatorTwo=32×(0.25×0.5)+32=36
我们可以看到,情景 A 产生了预期的最终可提取份额。
EigenLayer 承认了这个边界情况,并决定保留当前的实现。 不过,并非一切都失去了。报告这个边界情况使他们有机会测试他们对其设计选择的理解,并改进他们的文档。
总结他们的回应,该系统在发生信标链 slashing 时,有意减少 AVS 的可归属 slashed 金额。基于检查点时间的不同,最终可提取份额的任何差异都是异步信标链证明系统的自然结果。
为了更好地说明这一点,请考虑在情景 B 中,质押者在步骤 2 中经过 AVS slashing 后的 slashed 金额为 24 ETH。 在步骤 5 中,EigenPod 检查点捕获了占总存款份额 25%(64 ETH 中的 16 ETH)的信标链 slashing 事件后,AVS 的 slashed 金额相应地减少了 25%,变为 18 ETH。
将其与情景 A 进行比较,其中信标链的 slashing 事件被记录为占总存款份额的 50%(32 ETH 中的 16 ETH),因为第二个验证者尚未被验证,并且相应的 AVS 的 slashed 金额减少了 50%,变为 12 ETH。
你可能会从上面的示例中注意到,这种行为的一个积极副作用是,它激励质押者更频繁地执行 EigenPod 检查点,因为这会减少 AVS slash 的 ETH 数量。
复杂的会计很难做好。这意味着对于安全研究人员来说,仅通过手动代码审查也很难理解和发现边界情况。因此,在许多不同的场景中测试代码以捕获这些边界情况也很重要。
感谢 EigenLayer 智能合约和安全团队对他们协议安全的不懈奉献。
有关此边界情况的完整报告和 EigenLayer 的回应,请参阅下面的进一步阅读部分。
- 原文链接: blog.sigmaprime.io/eigen...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!