社区质押模块(CSM)架构

lido__ 发布于 2024-07-30 阅读 10

本文详细介绍了Lido社区质押模块(CSM)的架构设计,旨在吸引社区质押者以无需许可的方式加入Lido以太坊协议成为节点运营商。CSM要求节点运营商提供债券作为安全抵押,债券与验证者数量相关,并通过FIFO队列分配质押。文章阐述了验证者生命周期:加入、奖励、惩罚和退出机制。奖励包括节点运营商奖励和债券重基收益,由绩效预言机通过Merkle树分发。惩罚机制分即时和延迟两种,涵盖被罚没、MEV窃取和提款余额不足等情况。此外,还介绍了退出请求、紧急制动、早期采用期等设计。

CSM Arch logo

本文档描述了社区质押模块(Community Staking Module,CSM)的架构。该模块实现了《社区质押格局》(Community Staking Landscape)中描述的理念。本文档的主要目的是详细描述 CSM 的架构和主要设计决策。

本文档中,验证者(validator)、密钥(key)、验证者密钥(validator key)和存款数据(deposit data)的含义相同。

∑ TL;DR

CSM 是一个无许可(permissionless)质押模块,旨在吸引社区质押者以节点运营者(Node Operator)的身份参与 Lido on Ethereum 协议。加入 CSM 成为节点运营者的唯一要求是能够运行验证者并提供保证金(bond)。只要密钥有效,质押份额将按照密钥提供的顺序进行分配。保证金并非直接与实际验证者的质押份额关联,而是被视为一种安全抵押品。保证金是节点运营者的一个属性,因此它是该节点运营者所有验证者的抵押品。这使得保证金可以递减——节点运营者拥有的验证者越多,单个验证者所需的保证金就越少。节点运营者的奖励来自保证金 rebase 收益以及其所获得的质押奖励份额。如果验证者表现高于阈值,节点运营者的质押奖励部分将进行社会化(即平均化)分配。累计的共识层(CL)惩罚导致余额降至存款余额以下,以及被窃取的执行层(EL)奖励,都将从节点运营者的保证金中扣除。节点运营者应按照协议请求执行验证者退出,也可以自愿退出。

📓 术语表

  • 质押路由器(staking router,SR)是 Lido on Ethereum 协议中的一个智能合约,负责在不同模块之间进行质押份额分配和奖励分发;
  • 质押模块(staking module,SM)是连接到质押路由器的一个或一组智能合约,其功能包括:
    • 维护底层的运营者和验证者集合;
    • 负责运营者的加入/退出(on/off-boarding);
    • 维护验证者的存款、提款和退出;
    • 维护模块及参与者的费用结构和分配等;
  • 保证金(bond)是节点运营者提供的 ETH 或 stETH,作为不良行为或表现不佳的抵押品;
  • Lido DAO 是一个去中心化自治组织,通过治理代币(LDO)的投票权来决定受治理的流动性质押协议的关键参数。
  • 节点运营者(Node Operator,NO)是运行验证者的个人或实体;
  • Lido 是 Lido on Ethereum 协议的核心合约,存储协议状态、接受用户提交,并包含 stETH 代币;
  • stETH 是由 Lido 铸造的 ERC-20 代币,代表 totalPooledEther 中的一份份额;
  • 存款数据(deposit data)是指提交给 DepositContract 的结构,包含验证者的公钥和存款签名。在本文中,该术语也可以称为 keys(密钥)。验证者私钥仅由节点运营者创建、存储和管理;
  • DepositContract 是用于验证者存款的官方合约;
  • DepositSecurityModule(即 DSM)是一组智能合约和链下组件,用于缓解 相关漏洞
  • 当节点运营者的当前保证金不足以覆盖某验证者时,该验证者被视为"未足额担保"(unbonded);
  • 如果验证者在收到协议退出信号后未能及时退出,则该验证者被视为"卡住"(stuck);
  • Curated module 是 Lido 的第一个质押模块,之前称为节点运营者注册表(Node Operators Registry);
  • EasyTrack 是一套智能合约和一种基于否决权的替代投票模型,用于简化 DAO 的日常操作;
  • AccountingOracle 是一个合约,负责收集链下预言机提交的关于 Lido 参与验证者及其余额状态的信息、协议金库(即提款和执行层奖励金库)中累积的资金量、已退出和卡住的验证者数量、协议可以处理的提款请求数量,并分发节点运营者奖励;

🌎 总体信息

CSM 是一个要求提供保证金即可无许可准入的质押模块。该模块旨在成为独立的社区质押者(solo stakers 或 home stakers)进入 Lido on Ethereum 协议(LoE)节点运营者集合的清晰路径。保证金要求是一种至关重要的安全与一致性工具,可以在不损害底层质押协议(LoE)安全性和可靠性的前提下,实现无许可准入。

🤓 模块特性

所有质押模块都应遵循相同的 IStakingModule 接口。这不可避免地导致各模块具有许多共同或相似的组件和逻辑。CSM 也不例外。例如,密钥存储组件基于现有的 Curated module。然而,有几个方面有所不同,值得单独提及。

已退出与已提款

Curated module 使用验证者的"已退出"(exited)状态(包括被罚没并退出未被罚没并退出)作为记账中最后一个有意义的状态,因为在此状态之后,验证者不再承担信标链上的任何职责(少数延迟同步委员会参与的情况除外)。而 CSM 需要知道每个验证者的确切提款余额,以决定保证金惩罚。因此,该模块仅使用会计预言机报告的"已退出"计数器来向质押路由器返回正确的"活跃"密钥数量,并实现了无需许可的报告方法,一旦验证者进入可提款(Withdrawable)状态,即可报告验证者的提款余额(实际报告发生在验证者完成提款之后)。

质押分配队列

节点运营者必须提供保证金才能向 CSM 上传新的验证者密钥。按照与保证金提交顺序相似的顺序来分配质押份额是合理的。为此,采用了 FIFO(先进先出)质押分配队列。当质押路由器请求密钥以进行存款时,将返回队列中的下 X 个密钥,从而保持保证金的提交顺序。

针对"卡住"密钥的替代措施

节点运营者存在"卡住"密钥表明其违反了 Lido 退出政策。在这种情况下,模块应对违反政策的节点运营者采取措施。CSM 使用的措施与 Curated module 不同。相关措施将在下面的对应章节中描述。

节点运营者结构

CSM 中的节点运营者数据结构与 Curated module 类似,但有几个细微差别:

  • name(名称)属性被省略,因为对于无许可模块来说它是多余的;
  • rewardAddress(奖励地址)仅用于接收奖励和领取超额保证金;
  • 引入了新属性 managerAddress(管理者地址)。节点运营者应使用该地址进行方法调用;
  • 引入了新属性 totalWithdrawnKeys(已提款密钥总数),用于累计每个节点运营者已提款的密钥总数;
  • 引入了新属性 depositableValidatorsCount(可存款验证者数),用于统计当前符合存款条件的存款数据数量;
  • 引入了新属性 enqueuedCount(入队数),用于跟踪未入队的密钥数量;

🔄 CSM 验证者生命周期

描述 CSM 架构的最佳方式是沿着验证者的生命周期展开。

🚪 第 1 步:加入 CSM

image 加入 CSM 流程

创建节点运营者

要成为 CSM 中的节点运营者,或为现有节点运营者注册新的验证者,至少需要提供一个 validator pubkey(验证者公钥)、相应的 deposit signature(存款签名)以及相应的保证金金额。

存款数据准备与上传

CSM 接受与 Curated module 相同格式的存款数据(validator pubkey + deposit signature),主要区别在于要求在存款数据上传之前或同时提交保证金。

deposit signature 必须(deposit_message, domain) 的根进行签名。其中 domain 用于标识链,deposit_message 具有以下元组形式:

保证金

在此之后,"保证金"(bond)一词的含义如下:

保证金(Bond)——节点运营者在向 CSM 上传验证者密钥之前必须提交的一种安全抵押品。该抵押品用于覆盖因节点运营者不当行为可能造成的损失。一旦验证者从信标链退出,且所有已发生的损失得到弥补,该抵押品即可被领取或重新用于上传新的验证者密钥。

保证金是节点运营者的属性,而非验证者的属性。保证金以 stETH 的形式存储。节点运营者可以提交 ETH、stETH 和 wstETH 作为保证金代币。其中 ETH 会被质押,wstETH 会在提交时被解包(unwrap),以确保 stETH 是保证金的唯一形式。

所需保证金的总金额取决于节点运营者的验证者总数,其计算公式为函数 getBondAmountByKeysCount(keysCount)

image

为了方便读者理解,可以将上图按单个验证者(而非验证者总数)的维度重新绘制。

image

可能存在多个保证金"曲线"(即 getBondAmountByKeysCount 函数的实现)。所有节点运营者在创建时都会被分配一个默认曲线。DAO 可以为节点运营者设置自定义曲线。

现有节点运营者可以在不上传存款数据的情况下补充保证金,以弥补惩罚造成的损失,或提前预存保证金资金。

未足额担保的验证者

引入术语"未足额担保"(unbonded)来指代保证金未能完全覆盖的验证者。由于保证金对节点运营者的所有验证者是共有的,未足额担保的验证者可以按下图所示的方式确定。在示例中,验证者 N+1 是未足额担保的。

image

负 stETH rebase 可能带来的后果

由于保证金以 stETH 形式存储,存在因负 stETH rebase 导致保证金金额减少的风险。这可能会导致一些节点运营者无法领取奖励(因为实际保证金低于所需金额),甚至使验证者变成未足额担保状态。此问题在 Lido ADR 中的保证金机制 中有详细描述。就本文而言,值得一提的是,由于负 stETH rebase 发生的概率较低,且 Lido DAO 有一笔专用的基金可供使用以进行可能的补偿,因此 CSM 无需采取额外的应对措施。

存款数据的验证与失效(即审查与撤销审查,vetting 和 unvetting)

考虑到即将到来的 DSM v1.5 升级,CSM 将采用乐观验证(optimistic vetting)方法。上传的存款数据将被视为有效,除非 DSM 报告其无效。如果检测到无效的存款数据,DSM 会调用 decreaseOperatorVettedKeysvettedKeys 指针设置在第一个无效存款数据之前。

可存款密钥

多个因素决定了是否可以使用相应的存款数据进行存款。该信息体现在节点运营者的 depositableKeys(可存款密钥)属性中。该属性表示从节点运营者密钥存储中最后一条已存入记录之后开始,按顺序提取出的、可供质押路由器进行存款的存款数据记录数量。该数量的计算方式如下:

  • 未设置 targetLimit -> vettedKeys - depositedKeys - unbondedKeys
  • 已设置 targetLimit -> min(vettedKeys,targetLimit) - depositedKeys - unbondedKeys;如果节点运营者的 stuckKeys != 0,则为 0。

质押分配队列

CSM 中的质押分配队列是一个传统的 FIFO(先进先出)队列。节点运营者以 {noId, keysCount} 批次在队列中占据位置,并等待轮到他们。

image

当队列轮到该节点运营者的批次时,CSM 使用公式 min(depositableKeys, keysInBatch) 检查该批次中有多少密钥可以存入。

image

在某些情况下,节点运营者可能有一些密钥不在队列中,这是因为在队列迭代时这些密钥因当时不可存款而被跳过。normalizeQueue 方法允许节点运营者将所有可存款的密钥重新放回队列。

CSM 中有多个与存款数据存储相关的指针,其中包括 totalKeysvettedKeys 指针。在采用乐观验证方法且没有无效存款数据报告的情况下,这两个指针在大多数时候应保持同步(totalKeys == vettedKeys)。因此,存款数据进入队列有两种方式:

  • 存款数据上传后,如果 totalKeys == vettedKeys
  • 在调用 normalizeQueue 方法之后,如果某些密钥在上传时未被放入队列(上传时 totalKeys != vettedKeys),或在队列迭代过程中被跳过;

另有一些方法用于检查接下来的 X 个元素,并移除其中不包含可存款密钥的元素。这些方法是必要的,以确保即使在导致队列被大量不可存款密钥"污染"的灾难性场景下,队列仍能正常运作。

队列的详细描述见单独文档

存款数据删除

如果上传的存款数据尚未被存入,节点运营者可以自愿删除。每删除一个密钥,将从节点运营者的保证金中扣除 keyRemovalCharge(密钥删除费),以覆盖与队列处理相关的最大可能运营成本。存款数据可以按连续的索引区间批量删除(例如,从索引 5 到 10)。

如果协议已经存入了与该存款数据相关的验证者,则节点运营者无法删除该存款数据。停止验证职责的唯一方式是在共识层(CL)上退出验证者。一旦验证者完成提款,节点运营者即可领取超额保证金。

🤑 第 2 步:奖励

image 奖励总览

CSM 节点运营者有两种类型的奖励:

  • 节点运营者奖励;
  • 保证金奖励;

image

节点运营者奖励来自 LoE 协议从共识层和执行层奖励中分得的份额。这些奖励按完整 32 ETH 验证者奖励的一定百分比计算。节点运营者奖励以相同的方式(按每个模块的活跃验证者数量比例分配,其中 active == deposited - exited)在所有质押模块之间分配。每次会计预言机报告都会为 CSM 分配新的质押奖励份额。分配到的奖励存储在模块上。然后,由 CSM 表现预言机(Performance Oracle)每个 frame(周期)通过 Merkle 树提供 CSM 节点运营者奖励的分配,使新一批奖励可供申领。

保证金奖励(rebase)来源于 stETH 的 rebase 属性以及保证金以 stETH 存储这一事实。每次会计预言机报告后,shareRate(份额汇率)都会发生变化(大概率是上升)。因此,相同数量的 stETH 份额现在将等于更多的 stETH 代币。

总奖励的完整公式如下:totalRewards = 32 * moduleFee + bondAmount * shareRateChange。更多细节发布在补充文章中。

总奖励中有相当一部分来自保证金 rebase。在领取之前,保证金和节点运营者奖励会被合并。最终可领取的奖励金额计算方式为 bond + NodeOperatorRewards - bondRequired。这一方式还可确保任何保证金缺口都会在奖励申领前被协议补足。

image

此外,任何超额保证金都将被视为奖励。

image

表现预言机

表现预言机创建包含质押奖励分配的 Merkle 树,并将根提交到链上。为了让用户能够获取原始 Merkle 树,它将发布在 IPFS 和 GitHub 上。与存储多个根不同,每棵新树都包含 CSM 节点运营者曾获得的所有节点运营者奖励。因此,只需最新的树即可确定奖励分配。可领取的奖励金额可以计算为 totalAcquiredRewards - claimedRewards

表现预言机使用结合包含延迟(inclusion delay)的成功证明率(attestation rate)作为验证者整体表现的代理指标。通过一个表现阈值来确定实际节点运营者奖励的分配。表现高于阈值的验证者被纳入分配池,其余验证者则不被纳入。在计算节点运营者份额时,会考虑激活和退出事件。分配池形成后,每个验证者获得 totalStakingRewardsAccumulated / totalValidatorsInDistributionPool 的质押奖励份额。这实际上意味着模块获得的所有奖励将在表现良好的验证者之间分配。然后,验证者份额被分配到相应的节点运营者,每个运营者可以一次性领取其所有验证者的奖励。

image

需要特别注意的是,表现预言机只管理总奖励中的一部分。即使验证者在某个 frame 内表现低于阈值,其保证金奖励(rebase)仍然会计入。可以在此处找到奖励计算的示例。请注意,即使表现低于阈值,每个验证者的奖励仍将高于 solo staking 的奖励。

建议将表现预言机报告的 frame 设置为 28 天。这将使 frame 足够长,以涵盖短暂的表现中断(如果将 frame 设置得更短,这种覆盖短暂中断的效果就会减弱,表现阈值的作用也会降低)。将 frame 设置为大于 28 天会导致奖励分配出现不必要的延迟。

表现阈值的设定应参照整体网络的证明有效性,以确保节点运营者无法控制的网络问题不会影响奖励分配。

如果你想了解更多关于表现预言机实际算法的信息,请查看这份详细文档

👮‍♂️ 第 3 步:惩罚

即时惩罚与延迟惩罚

引入了以下惩罚方案:

  1. 即时惩罚(适用于无歧义且可以通过去信任化证明进行评估的惩罚);
  2. 带有质疑期的延迟惩罚(适用于可能出现误报或需要调查的情况);

延迟惩罚的质疑期是通过将惩罚执行过程拆分为两个角色来实现的。

第一个角色是"报告者"(reporter)。该角色的成员可以首先报告一个应导致惩罚的事实。在此阶段,保证金资金将被锁定,但不会被销毁或没收。"报告者"也可以在质疑结果有利于节点运营者时撤销初始报告。

第二个角色称为"裁决者"(settler)。该角色的成员可以最终确定(裁决)先前报告的惩罚。

分离这两个角色确保了只有在两个独立参与者达成一致时才能施加惩罚。

原因

CSM 节点运营者的保证金被惩罚的主要原因有三个:

  1. 验证者被罚没(slashed)。在这种情况下,将没收初始(最低)罚没惩罚。惩罚金额 = 1 ETHEFFECTIVE_BALANCE / 32);
  2. 运营者窃取了 EL 奖励(MEV)。惩罚金额 = 窃取金额 + 固定窃取罚金(可适用于同一 NO 的多个验证者);
  3. 验证者的提款余额低于 DEPOSIT_AMOUNT(32 ETH)。惩罚金额 = 32 - 验证者的提款余额

第一种惩罚使用 EIP-4788 以无需许可的方式报告,以证明罚没事实。该惩罚在报告交易内立即执行。

第二种惩罚采用带有质疑期的延迟惩罚形式。一个专门的委员会(报告者)检测 MEV 窃取行为并在链上报告该事实,锁定保证金资金。通过 EasyTrack 动议进行裁决(裁决者)确保了 DAO 与检测委员会之间的一致性。一旦惩罚被裁决(确认),由于违反了协议规则,节点运营者的所有权益将被重置。如果惩罚在 retention_period(保留期)内未被裁决,锁定的保证金将自动解锁。

第三种惩罚类型使用验证者的提款余额计算(实际报告方式将在下文相关章节中描述)。该惩罚在报告交易内立即执行。如果已经施加了初始罚没惩罚(第一种惩罚类型),则会将其考虑在内,以避免双重惩罚。

机制

与节点运营者保证金惩罚相关的机制有两种。

第一种是使用 Burner 销毁 stETH 份额。这些被没收的份额被销毁后,stETH 总份额减少。因此,shareRate 上升,实际上是将所有被销毁的 stETH 价值分配给其他 stETH 持有者。

第二种机制是将被没收的 stETH 转移到 Lido DAO 金库。这种方法适用于那些用于覆盖协议运营成本的惩罚(例如 keyRemovalCharge)。

针对上一节描述的所有惩罚原因,被罚没的资金都会被销毁。目前,唯一转移到金库的惩罚是 keyRemovalCharge

保证金不足

如果在施加惩罚后,节点运营者的保证金不足以覆盖其当前全部验证者所需的最低金额,则所有新的奖励将用于补充 NO 的保证金,直到恢复到所需水平。节点运营者也可以自行"补足"保证金(通过提交所需的差额),以便能够再次领取奖励。

如果惩罚金额超过节点运营者可用保证金的金额,则所有可用资金将被销毁。

权益重置

与默认曲线不同的保证金曲线可以被视为对节点运营者的一项权益。确保在表现不佳或违反规则时重置这些权益至关重要。在 CSM 中,有以下 4 种情况会重置节点运营者的权益:

  • 检测到并确认窃取 EL 奖励;
  • NO 的某个验证者被报告罚没;
  • NO 的某个验证者因 CL 余额不足而被驱逐;
  • 基于 DAO 的决定;

如果节点运营者自愿退出所有验证者并领取全部保证金,则不会重置权益,因为节点运营者没有恶意或违规行为。

关于该主题的详细研究见单独文档

👋 第 4 步:验证者退出

image 退出流程总览

自愿退出

鉴于 CSM 的无许可特性,NO 可以随时自愿退出其验证者。

协议发起的退出

为了与核心协议和其他质押模块保持一致,CSM 使用 VEBO 来请求或触发验证者退出。

从核心协议侧来看,可以请求验证者退出以覆盖 stETH 持有者的提款请求,或根据 DAO 的决定进行退出。

从 CSM 侧来看,可以为未足额担保的验证者请求退出。此类退出通过 forcedTargetLimit 自动请求。

forcedTargetLimit 目前正在 SR v1.5 中开发。简而言之,它与现有的 targetLimit 类似,但超过 forcedTargetLimit 的验证者可以立即请求退出,甚至无需满足 stETH 持有者的提款请求。

节点运营者应关注 VEBO 事件(例如,通过使用 Ejector)以确保其及时退出验证者。如果节点运营者在协议请求后拒绝退出验证者,则应施加以下惩罚和限制措施:

  1. 将该 NO 的密钥从队列中排除,并且在 stuckKeysCount = 0 之前不再将其放回队列;
  2. 如果节点运营者在表现预言机的报告周期内 stuckKeysCount > 0,则不向该运营者分配质押奖励;

此外,在特殊情况下,Lido DAO 可以触发节点运营者验证者的退出。

长期表现不佳

如果验证者在 6 个 frame 中有 3 个 frame 的表现低于表现阈值,则该验证者被视为违反协议内良好表现规则的差表现者。具有 3 次"违规记录"(表现不佳的 frame)的验证者可以通过无需许可的方法从协议中被驱逐。还有一种选择是从节点运营者的保证金中没收此类验证者错失的利润。然而,该选项仍在考虑之中。

要了解更多关于驱逐差表现者的信息,请参阅单独文档

提款余额报告

要释放保证金并计算退出惩罚(如果有),需要验证者的提款余额。该余额由 CSM 机器人或节点运营者本人使用 EIP-4788 以无需许可的方式进行报告。

🫡 结论

如果你有任何问题,或者认为本文有遗漏之处,请在评论区留言。

附录 1:紧急制动

为确保协议安全,提出了以下紧急制动措施:

  • 禁用来自质押路由器的存款;
  • 禁用 NO 创建;
  • 禁用存款数据上传;
  • 禁用奖励分配根提交;
  • 禁用奖励领取;

上述某些方法可能会分配给一个专门的多重签名(multisig),以便在 CSM 的早期成熟阶段能够快速响应。

附录 2:方法与参与者映射

方法 参与者
设置模块目标份额(SR 方法) Aragon agent
设置节点运营者的 targetLimit Aragon agent
报告验证者被罚没 无需许可(附带证明)
报告验证者提款 无需许可(附带证明)
执行 keyRemovalCharge 模块代码
设置 keyRemovalCharge Aragon agent
报告无效密钥 DSM
对节点运营者施加通用惩罚* Aragon agent
报告窃取 EL 奖励并锁定保证金 MEV 窃取委员会**
销毁已锁定的保证金 专用 Easy Track
提交新的奖励根 表现预言机
为节点运营者设置保证金曲线 Aragon agent
创建节点运营者 无需许可
上传存款数据和保证金 节点运营者管理者
补充保证金 无需许可
领取奖励和超额保证金 节点运营者管理者或奖励地址
删除存款数据 节点运营者管理者
更改节点运营者的管理者地址 节点运营者管理者
更改节点运营者的奖励地址 节点运营者奖励地址
重置节点运营者的管理者地址 节点运营者奖励地址
禁用来自质押路由器的存款 Aragon agent 或 DSM
禁用 NO 创建和存款数据上传 Aragon agent 或 EB MS
禁用奖励分配根提交 Aragon agent 或 EB MS
禁用奖励领取 Aragon agent 或 EB MS
启用来自质押路由器的存款 Aragon agent
启用 NO 创建和存款数据上传 Aragon agent
启用奖励分配根提交 Aragon agent
启用奖励领取 Aragon agent
重新分配角色成员 Aragon agent

* 在模块运行满 1 年后过期

** 多重签名

附录 3:早期采用期

无许可准入的挑战之一在于,在条件颇具吸引力的情况下,可能出现一个大型参与者占据质押模块中所有席位的情形。为了克服这一点,提出了一个早期采用期(Early Adoption)作为 CSM 主网生命周期的第一阶段。建议在早期采用期内,使用 Merkle 证明作为进入 CSM 主网的入场券。除了能够加入之外,这些节点运营者还将有资格获得"首个验证者保证金折扣"。这将确保在早期采用期内,经过验证的 solo 质押者(来自 Rated 的名单并经 Lido DAO 评估)能够以少量优惠加入。

请参阅详细文档以了解更多关于早期采用期机制的信息。

附录 4:相关文档

  • 原文链接: hackmd.io/@lido/csm-v1-a...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论