本文讨论了EigenPod重设计中的检查点证明系统,详细介绍了如何解决传统M2证明系统中的问题,通过设置有效验证者集合与快照的结合,提供了一种保证ETH来源和数量的机制,从而支持部分提款和防止算计攻击。文章结构清晰,涵盖了系统的工作原理、主要问题及解决方案,并提供了代码示例和逻辑解释。
eigenlayer-contracts/#515
EigenPod 信标状态证明面临的主要技术问题是如何使用这些证明来准确地确定 ETH 的位置。
我们要求状态证明的原因是确保 如果我们授予股份,它们能够保证与最终将通过 pod 流动的 ETH 一对一对应。
因此,EigenPod 证明系统的 最终目标 是确定支持所授予股份的资产当前的位置。理想的证明系统不应是 模糊的。当我们处理一个证明时,我们应该明确知道两件事:
只要我们能确定这些信息而没有歧义,我们可以安全地授予我们知道有支持的股份。
M2 证明存在模糊性并且具有一些会使实施新功能(特别是删减)变得更困难的会计特性。为了理解其原因,我们需要了解 M2 系统使用了什么信息——也就是说,我们 实际上在证明什么。
目前,我们有三种类型的证明:
在这三种证明类型之间,我们主要使用了两个关于信标链的信息:有效余额 和 提款。我们用这些信息来确定:
M2 利用这些信息相应地授予或删除股份。
提款凭证和余额更新证明使用了信标链中 validator 的 effective_balance
,该信息位于信标链的 Validator
容器 中。
有效余额的问题在于它们仅在 每个纪元 更新,而不是 每个块。这意味着有效余额证明可能会最多陈旧 32 个块——遗漏了 validator 余额的变化,例如:
仅依靠有效余额证明,我们无法知道 validator 当前在信标链上的 ETH 具体有多少。我们也不知道 validator 是否已经提款。
部分/全部提款证明使用信标链的 Withdrawal
容器 中找到的 amount
。它们还将 Withdrawal
创建的纪元与 Validator
容器 中找到的 withdrawable_epoch
进行比较。这作为启发式方法来确定 Withdrawal
是被视为 “部分” 还是 “完全” 的提款。
使用信标链的 Withdrawals
的好处在于,当 EigenPod 看到 Withdrawal
证明时,被证明的精确 ETH 数量已经保证在 pod 中。
然而,依赖信标链的 Withdrawals
也有几个缺点:
Withdrawals
每个块创建,并且自 Dencun 升级以来,每个块最大处理 16 次提款。
Validator
的 withdrawable_epoch
无法准确指示完全提款—它仅指示“在 withdrawable_epoch
之后的某个时间点,validator 将被提款。”
Withdrawal
在 validator 的 withdrawable_epoch
之后,确实意味着该 validator 已经完全提款。但没有办法判断特定的 Withdrawal
是否是整个提款的金额!单个提款证明本身告诉你 ETH 移动到 pod 的数量,但什么都没有告诉你信标链上还剩余多少 ETH。这意味着 我们不能确定 我们看到的提款是否是来自该 validator 的 所有 ETH,或是否有更多正在路上。
这使得基于提款证明调整股份变得困难,并导致 M2 股份会计中的模糊性和边缘案例。考虑以下场景:
0) 我有一个在信标链上拥有 32 ETH 的 validator,我已经证明我的 validator 的提款凭证指向我的 pod。
ETH | 股份 |
---|---|
32 ETH 在信标链上 | 32 ETH 的股份 |
1) 然后,我退出了我的其中一个 validator。 我 没有证明 这一点到我的 pod。
ETH | 股份 |
---|---|
- 0 ETH 在信标链上 <br> - 32 ETH 在我的 pod | - 32 ETH 的股份 |
2) 接下来,我向我已退出的 validator 存入 1 ETH。 这将自动被提款到我的 pod,但并不是立即的。现在,它仅记录在我 validator 的 effective_balance
中。
ETH | 股份 |
---|---|
- 1 ETH 在信标链上 <br> - 32 ETH 在我的 pod | - 32 ETH 的股份 |
3) 最后,我进行余额更新证明,显示我的 pod 里我的 validator 只有 1 ETH。 由于上次我 pod 看到的证明余额是 32 ETH,因此这导致了股份减少 31 ETH。
ETH | 股份 |
---|---|
- 1 ETH 在信标链上 <br> - 32 ETH 在我的 pod | - 1 ETH 的股份 |
最终,这使得一个 validator 可以误报他们在其 pod 中的股份数量,这在被削减的上下文中特别危险。攻击者可以进行恶意行为,然后如上所述操纵其信标股份,以减少可以被削减的股份数量。
这对攻击者的风险很小,因为 m2 证明系统仍会接受缺失的提款证明——因此攻击者可以在削减的危险过后恢复其股份。
使用信标链证明,我们无法区分部分和全部提款,也无法依赖提款证明来确定事件的顺序。在 M2 中,我们应用一个启发式方法来获得对此的“最佳猜测”,但这个猜测有一些会计特性导致未来 EigenLayer 削减发布的显著攻击向量。
我们需要在发布削减之前解决这个问题。
检查点证明系统基于 pod “活动 validator 集合”的概念。即 - 在信标链上被 pod 知道具有指向 pod 的提款凭证的 validator 集合。
当你证明一个 validator 的提款凭证时,该 validator 会进入 pod 的活动 validator 集合。当你显示一个 validator 已退出时,该 validator 会离开 pod 的活动 validator 集合。M2 系统已经使用了这个状态模型:
verifyWithdrawalCredentials
将 validatorInfo.status
设置为 ACTIVE
,并将 activeValidatorCount
增加 1verifyAndProcessWithdrawals
将 validatorInfo.status
设置为 WITHDRAWN
并将 activeValidatorCount
减少 1检查点证明结合了 pod 的活动 validator 集合与信标链状态和 EigenPod 状态的快照,以明确确定 支持 pod 的 ETH 量 及 ETH 的去向。
struct Checkpoint {
bytes32 beaconBlockRoot; // 检查点开始之前的块的信标区块根
uint256 podBalanceGwei; // 检查点开始时 pod 的余额(以 gwei 计),减去已经由股份支持的余额
int256 balanceDeltasGwei; // 信标余额的总变化,在检查点进展时更新
uint256 proofsRemaining; // 完成检查点之前需要证明的 validator 数量
}
检查点证明有两个步骤:
startCheckpoint
。这是对信标链和 EigenPod 状态的快照:uint256 podBalanceGwei =
(address(this).balance / GWEI_TO_WEI) - withdrawableRestakedExecutionLayerGwei;
// 使用上一个块的根创建检查点证明,并将当前 `activeValidatorCount` 作为最终izing
// 检查点所需的证明数。
Checkpoint memory checkpoint = Checkpoint({
beaconBlockRoot: _getParentBlockRoot(uint64(block.timestamp)),
podBalanceGwei: podBalanceGwei,
balanceDeltasGwei: 0,
proofsRemaining: activeValidatorCount
});
verifyCheckpointProofs
,pod 所有者(或其他任何人)为 ACTIVE
状态的每个 validator 提交一个余额证明。这会减少检查点的 proofsRemaining
,并将自上次看到的余额以来的差异更新到检查点的 balanceDeltasGwei
中。struct BalanceProof {
bytes32 pubkeyHash; // 被证明的 validator 的公钥哈希
bytes32 balanceRoot; // validator 的编码余额
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);
检查点证明系统的一个关键细节是 任何我们无法归因于现有股份的 pod 中的 ETH 必须授予股份。因为 pod 中的原生 ETH 从根本上是无法归因的——我们不知道这些 ETH 来自哪里,因为有几个 ETH 来源绕过了合同执行:
在以上每个来源中,有一个特别需要考虑:对于具有经过验证提款凭证的 validator ,来自信标链全额提款的任何 pod 中的 ETH 已经授予了股份!我们需要确保不会盲目地为 pod 中的任何 ETH 授予股份,因为这可能意味着我们在退出 validator 的股份上进行了重复计数。
为了避免重复计数,完成检查点证明会导致一个股份增量,遵循这个公式,其中
v(i) 是 pod 中一个单独的 validator,具有
具有验证的提款凭证的 n 个 validator:
ΔpodShares=ΔpodBalance+∑i=0nΔbeaconBalance[v(i)]
当一个 validator 退出时,
ΔbeaconBalance 将是一个负数:它当前的余额(0)减去它之前证明的
beaconBalance。这个数字被加到
podBalance,确保这些股份不会被重复计数。
这也意味着 将为部分提款授予股份(以及任何其他我们无法归因来源的 ETH)。
startCheckpoint
采取的快照使我们能够阐明 ETH 的 “去向”,而通过 pod 的活动 validator 集合总余额证明使我们能够阐明 “数量”。这创建了一个我们可以用来授予股份的保证:
这个保证的关键在于 startCheckpoint
使用的快照过程,它执行了两个操作:
block.timestamp
作为输入调用 EIP-4788 信标区块根预言机。这返回前一个信标区块的块根——即对应于 block.number - 1
的信标区块根。activeValidatorCount
这个检查点用于所有后续证明的起始点。
uint256 podBalanceGwei =
(address(this).balance / GWEI_TO_WEI) - withdrawableRestakedExecutionLayerGwei;
// 使用上一个块的根创建检查点证明,并将当前
// `activeValidatorCount` 作为最终izing
// 检查点所需的证明数。
Checkpoint memory checkpoint = Checkpoint({
beaconBlockRoot: _getParentBlockRoot(uint64(block.timestamp)),
podBalanceGwei: podBalanceGwei,
balanceDeltasGwei: 0,
proofsRemaining: activeValidatorCount
});
执行层/信标链块处理的一个奇怪特点是,在执行层中,信标链的提款在所有区块交易之后处理(这实际上导致了我们在 Cantina 中的唯一 “高” BUG)。
这个特点意味着,如果我们快照了 当前 信标区块根和 当前 pod ETH 余额,则可能会出现:
这就是为什么当调用 startCheckpoint
时,它查询 EIP-4788 预言机,使用当前的 block.timestamp
,这实际上返回 上一个区块的根!这意味着,调用 startCheckpoint
时:
这些特性意味着在检查点中证明的
beaconBalances 与在检查点开始时快照的
podBalance 是 100% 不同的,我们可以安全授予股份,而不必担心重复计数。
随着 EigenLayer 原生支付和削减的即将发布,EigenLayer 和 AVS 将依赖于核心协议报告的 EigenPod 股值,以:
因此, pod 会计系统一个重要的考虑因素是:如何确保 pod 股始终保持最新? 毕竟,pod 会计系统的准确性在很大程度上取决于是否定期获得余额更新证明,因为这是它了解信标链状态的唯一 “视图”。
请注意,validator 的信标链余额可能因几个事件而下降:
M2 针对这个问题的回答是 EigenPod.verifyBalanceUpdate
,此方法可以由任何人调用(不仅仅是 pod 所有者),以证明自上次看到的证明以来,validator 的信标链余额是否上升或下降。然而,如果 validator 的余额下降, pod 所有者永远不会有动机去证明这一点,因为这样会减少他们的股份。
检查点有些不同:因为部分提款会授予股份,因此 pod 所有者有动力在以下情况下证明余额更新:
在大多数情况下,检查点系统提供了足够的激励来保持 pod 股份的最新状态。
通常,startCheckpoint
只能由 pod 所有者调用。这是因为检查点必须在启动新检查点之前完成——作为一个可能耗费气体的过程,我们希望允许 pod 所有者决定何时进行检查点。
然而,如果 pod 中有大量 validator 在信标链上被削减, pod 所有者可能不想执行检查点。在这种情况下,我们依赖于一个 “陈旧性证明”,以允许第三方代表 pod 所有者启动检查点。
任何人都可以向 EigenPod.verifyStaleBalance
提交陈旧性证明:
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external;
verifyStaleBalance
允许任何人提交证明,证明 pod 中的一个活动 validator 已在信标链上被削减。
如果成功,这将允许调用者启动一个检查点。请注意,如果已存在一个检查点,调用将失败——需要在成功之前完成现有检查点!
请在这里跟进进行中的合同工作:eigenlayer-contracts/#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 当一个 validator 在给定的检查点被证明时触发
event ValidatorCheckpointed(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex);
/// @notice 当一个 validator 在给定的检查点被证明余额为 0 时触发
event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex);
/// 结构体
struct Checkpoint {
bytes32 beaconBlockRoot;
uint24 proofsRemaining;
uint64 podBalanceGwei;
int128 balanceDeltasGwei;
}
/// 查看方法
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
这两种新方法应提供与已删除的方法相同的功能,并带来以下额外好处:
DelayedWithdrawalRouter
。 相反,完成的检查点将部分提款赠予可以通过 DelegationManager
提款队列提取的股份,方式与其他所有 EigenLayer 股份相同。用户流程示例 - 申请部分提款
EigenPod.startCheckpoint()
。这将更新:
EigenPod.currentCheckpointTimestamp
EigenPod.currentCheckpoint
EigenPod.currentCheckpoint()
并获取将用于生成新检查点证明的 beaconBlockRoot
。ACTIVE
状态的 validator 生成一个余额证明。
EigenPod.validatorStatus(pubkeyHash).
检查 validator 是否处于 ACTIVE
状态。ACTIVE
validator 已通过 verifyWithdrawalCredentials
进行验证,但尚未被证明为 WITHDRAWN
。Validator.effective_balance
,而是使用在 BeaconState.balances
中找到的当前余额。EigenPod.verifyCheckpointProofs
。你可以单独提交这些证明,也可以全部一次性提交。
verifyCheckpointProofs
,后续调用可以在 stateRootProof
参数中留空;这个值在第一次为给定检查点证明时会被缓存。currentCheckpoint.proofsRemaining
将减少 1currentCheckpoint.balanceDeltasGwei
将更新,包括该证明计算的余额增量currentCheckpoint.proofsRemaining
达到 0 时,检查点会自动完成,你的部分提款将获得股份。一些重要说明:
一旦启动了一个检查点,它不能被取消。 pod 所有者必须完成现有检查点后才能启动新检查点。
完成一个检查点不会授予在检查点启动后进入 pod 的任何部分提款的股份。
提供一个证明表明一个 validator 的余额为 0 将标记该 validator 为 WITHDRAWN
并减少 EigenPod.activeValidatorCount
。 这意味着在未来的检查点证明中你不需要为该 validator 提供证明。
已添加:
interface IEigenPod {
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external;
}
在大多数情况下,pod 所有者无需考虑此方法——此方法的存在是为了允许第三方在 validator 在信标链上被削减时启动检查点。
如上所述,在检查点激励与信标链削减部分中有进一步解释。
已移除:
EigenPodManager.beaconChainOracle()
EigenPodManager.updateBeaconChainOracle(...)
EigenPodManager.getBlockRootAtTimestamp(...)
已更改:
EigenPod.verifyWithdrawalCredentials(...)
VERIFY_BALANCE_UPDATE_WINDOW_SECONDS (4.5 小时)
内使用 oracleTimestamp
的要求oracleTimestamp
参数现在对应于用于证明的信标区块根之后的 下一个有效块。currentCheckpointTimestamp
的要求上下文:
verifyWithdrawalCredentials
正在进行一些小更改,以确保与新检查点系统兼容。接口将保持相同,但我们已调整确定可以处理提款凭证证明的条件。
在 M2 中,verifyWithdrawalCredentials
证明:
oracleTimestamp
添加到第三方控制的 beaconChainOracle
oracleTimestamp
年限不超过 4.5 小时这两项都是我们在前 Deneb 系统中的遗留,依赖于由受信方提供信标链块根的 EigenPods
。然而,我们现在处于后 Deneb 世界, EIP-4788 为我们提供了保障!
我们正在删除上述两项要求。相反,verifyWithdrawalCredentials
证明:
可以使用最近24小时内的任何有效 block.timestamp
,只要时间戳比 currentCheckpointTimestamp
新
block.timestamp
应该与被证明的信标块后面块的时间戳匹配!这是由于 EIP-4788 的工作原理。如果被证明的 Validator
容器 显示该 validator 已经设置 exit_epoch != FAR_FUTURE_EPOCH
,则证明会回滚。
DelayedWithdrawalRouter
已移除:
EigenPod.activateRestaking
EigenPod.withdrawBeforeRestaking
EigenPod.withdrawNonBeaconChainETHBalanceWei
EigenPod.hasRestaked()
EigenPod.nonBeaconChainETHBalanceWei
EigenPod.mostRecentWithdrawalTimestamp
已更改:
EigenPod
不再调用 DelayedWithdrawalRouter
DelayedWithdrawalRouter
中队列的现有提款将不受影响,将按预期日期可主张DelegationManager
提款队列进行。上下文 - Pod 激活:
activateRestaking
原本旨在允许 pre-M2 pod 所有者通过选择调用 activateRestaking
以启用在其 EigenPod 上进行的证明来 “选择加入” M2 升级。同样,withdrawBeforeRestaking
旨在允许未 “选择加入” 的 pod 所有者继续提取共识奖励,而无需参与 M2 证明系统。
通过检查点证明,这种在 M1 和 M2 pods 之间的区分变得不再重要,因为检查点过程直接支持这两个功能集:
startCheckpoint
继续不重新质押其validator 的信标链 ETH 和直接接入共识奖励。
verifyWithdrawalCredentials
重新质押任何 validator,startCheckpoint
将自动完成一个检查点,授予 pod 所有者与 pod 的原生 ETH 余额相等的股份。这些可以通过 DelegationManager
进行重新质押或提取。上下文 - 移除 DelayedWithdrawalRouter
:
由于这两个功能集现在涉及到 pod 所有者申请股份和通过 DelegationManager
进行股份的重新质押/提款,我们看到一个机会,通过完全移除 DelayedWithdrawalRouter
进一步简化 EigenPod 系统。
这非常可取,因为 DelegationManager
队列是 EigenLayer 进行取款处理的方式,而保持 DelayedWithdrawalRouter
意味着我们需要有 2 条资金离开系统的单独路径。
既然我们正在移除 DelayedWithdrawalRouter
,其通过 withdrawNonBeaconChainETHBalanceWei
的用法也将被移除。
移除 EigenPod.MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR
Pectra 硬分叉 带来了几个重大变化,其中最重要的变化如下。
1) MaxEB 增加到 2048 ETH,意味着 validator 的余额可以更高,并且可能具有自定义部分提款清扫上限。M2 证明系统将难以支持这一点,因为它试图区分部分/全部提款。然而,检查点证明对此无关紧要!
2) Validator 合并 允许两个具有相同提款凭证的 validator(source
和 target
)被合并。这将把 source
validator 的余额设置为 0,target
validator 的余额设置为 target + source
。
目前尚不清楚合并是在共识层上发起还是在执行层上发起(详情见下文)。在后者的情况下,EigenPod
本身将公开方法,允许 pod 所有者启动合并。
一般来说,检查点证明可以毫无问题地处理合并。因为 source
将余额为 0,检查点证明将其移至 WITHDRAWN
状态,因此不需要对其进行进一步证明。 同样, target
validator 的余额增量将简单地包含 source
validator 的以前余额,因此整体股份增量不应改变。
然而,考虑到检查点证明仅要求对 pod 的 ACTIVE
validator 集合(经过验证的提款凭证 + 不 WITHDRAWN
)就是意味着有一些重要的边缘案例需要考虑:
source: INACTIVE, target: ACTIVE
:如果 source
没有经过验证的提款凭证,则 target
的余额变化将在下一个检查点中被记录。
source
合并到 target
,然后在 同一纪元中 调用 startCheckpoint
。如果随后 source
使用 在 startCheckpoint
后但仍在同一纪元中 的时间戳验证提款凭证,则在提款凭证证明中使用的 effective_balance
将未反映合并。Validator
容器的状态。如果,例如,它设置了该 validator 的 exit_epoch
,则在这种情况下验证提款凭证将变得不可行,因此这不是问题(verifyWithdrawalCredentials
会在 validator 不再缺席时回滚)Validator
容器做出修改,我们将需要更改 verifyWithdrawalCredentials
使用 current_balance
,就像检查点系统所做的那样。source: ACTIVE, target: INACTIVE
:如果 target
没有经过验证的提款凭证,则 target
的余额变化 不会被下一个检查点记录。
source
的余额下降到 0,而 pod 的 ETH 余额没有相应的增加。它将似乎 ETH 消失——同样,检查点系统会相应地减少股份。这不会让用户的资产面临风险,但对于未来的 EigenLayer 削减功能,我们不希望质押者能“暂时移除”他们可以被削减的资产!verifyWithdrawalCredentials
可以由任何人调用(而不仅仅是 pod 所有者),并运行观察者以监控 pod 的这种类型的活动。这并不理想,但实际上没有其他选择。打开 verifyWithdrawalCredentials
,使其可被任何人调用,而不仅仅是 pod 的所有者
运行监视器以监控 source -> target
合并,其中 target
为 INACTIVE
。
根据合并后 Validator
容器的变化,我们可能需要改变 verifyWithdrawalCredentials
,使其除了使用当前使用的 Validator
容器证明外,还能使用 current_balance
证明。
如果合并是在执行层发起的,我们不需要立即进行任何更改! 我们可以选择在稍后的日期向 EigenPod
接口添加合并支持,并包含上述规则以避免相关的边缘案例。
(可能不完整)此文档尚未明确提及的事项集合 - 想先让大家在今天的会议上了解一下;如果你们想,我们可以讨论这些内容!
effective_balance
证明,因为后者导致了模糊。
validators
和 current_balances
树中都需要证明某种内容,因此开销较高,而新的余额证明将只需要后者。我们在证明提取凭证后不需要检查 Validator
容器。verifyWithdrawalCredentials
和余额证明快照。
WITHDRAWN
状态。podBalance
部分)。我们将像处理其他任何资产一样授予它股份。
- 原文链接: hackmd.io/@-HV50kYcRqOjl...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!