显示软件包…
1 个稳定版本
2.0.0 | 2021 年 4 月 4 日 |
---|
#2 在 #tetcore
113 每月下载量
用于 13 个软件包(8 个直接使用)
2MB
40K SLoC
质押模块
质押模块用于管理网络维护者投入的资金。
概述
质押模块是通过以下方式选择一组网络维护者(在某些情况下称为“权威”,在其他情况下称为“验证者”)的手段:那些自愿将资金存入的。在存款期间,这些资金在正常运营下会得到奖励,但如果质押的维护者被发现未能正确履行其职责,这些资金将面临被“削减”(没收)的风险。
术语
- 质押:将资金锁定一段时间,使其面临被削减(损失)的风险,以成为网络奖励的维护者。
- 验证:运行节点以积极维护网络的过程,无论是通过生产区块还是保证链的最终性。
- 提名:将质押资金放在一个或多个验证者身后,以分享任何奖励和惩罚的过程。
- 存档账户:持有所有者用于质押的资金账户。
- 控制器账户:控制所有者用于质押的资金账户。
- 时代:会话的(整个)数量,这是验证者集(以及每个验证者的活跃提名者集)重新计算和奖励发放的期间。
- 削减:对质押者的惩罚,通过减少其资金。
目标
Tetcore NPoS 中的质押系统旨在实现以下目标
- 将受冷钱包控制的资金进行质押。
- 在不中断实体角色的情况下,部分提取或存入更多资金。
- 以最小的开销在角色(提名者、验证者、空闲)之间切换。
场景
质押
几乎与质押模块的所有交互都需要一个称为“绑定”(也称为成为质押者)的过程。要成为“绑定”的,一个被称为“存档账户”的资金持有账户,它持有一些或全部的资金,这些资金作为质押过程的一部分被冻结在原地,与一个活跃的“控制器”账户配对,该账户发布有关如何使用这些资金的指令。
账户对可以通过使用bond
调用进行绑定。
存仓账户可以通过使用set_controller
调用更改其关联的控制器。
任何质押账户对都可能处于以下三种可能的角色之一:Validator
(验证者)、Nominator
(提名者)和Idle
(闲置)(定义在StakerStatus
中)。有三个相应的指令用于在角色之间切换,即:validate
(验证)、nominate
(提名)和chill
(冷却)。
验证
验证者的角色是验证区块或确保其最终性,维护网络的准确性。验证者应避免任何形式的恶意行为和离线。声明有意成为验证者的绑定账户并不会立即被选为验证者。相反,它们被宣布为候选人,它们可能在下一个时代被选为验证者。选举结果由提名者和他们的投票决定。
账户可以通过使用validate
调用成为验证者候选人。
提名
提名者不直接参与维护网络,而是对一组要被选为的验证者进行投票。一旦账户声明了提名的兴趣,它将在下一个选举轮次生效。提名者存仓账户中的资金表示其投票的权重。验证者获得的奖励和惩罚都由验证者和其提名者共享。这一规则激励提名者尽可能不投票给表现不佳/离线的验证者,因为如果投票不当,提名者也会损失资金。
账户可以通过使用nominate
调用成为提名者。
奖励和惩罚
奖励和惩罚程序是质押模块的核心,试图拥抱合法行为,同时惩罚任何恶意行为或不可用行为。
在它变得太老之前,必须使用$HISTORY_DEPTH
通过使用payout_stakers
调用来申报每个时代的奖励。任何账户都可以调用payout_stakers
,该调用将奖励支付给验证者以及其提名者。只有最大的Config::MaxNominatorRewardedPerValidator
质押者可以申报其奖励。这是为了限制每个提名者账户修改存储的I/O成本。
一旦报告了恶意行为,就可以在任何时候进行惩罚。一旦确定了惩罚,就会从被惩罚的验证者的余额以及为其投票的所有提名者的余额中扣除价值(从被惩罚实体的存仓账户中扣除)。
惩罚逻辑在slashing
模块的文档中进一步描述。
类似于减半,奖励也会在验证者和其关联提名者之间共享。然而,奖励资金并非总是转移到存档账户,并可进行配置。有关详细信息,请参阅奖励计算。
冷静
最后,上述任何角色都可以选择暂时退居幕后,冷静一段时间。这意味着,如果他们是提名者,将不再被视为投票者;如果他们是验证者,将不再成为下次选举的候选人。
账户可以通过chill
调用退居幕后。
会话管理
该模块实现了SessionManager
特性。这是查询新验证者集的唯一API,允许这些验证者集在其时代结束时获得奖励。
接口
可调用的函数
抵押模块的可调用函数使实体能够接受和改变其角色,并提供一些辅助函数以获取/设置模块的元数据。
公共函数
抵押模块包含许多公共存储项和(不可变)函数。
用法
示例:按ID奖励验证者。
use fabric_support::{decl_module, dispatch};
use fabric_system::ensure_signed;
use noble_staking::{self as staking};
pub trait Config: staking::Config {}
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin {
/// Reward a validator.
#[weight = 0]
pub fn reward_myself(origin) -> dispatch::DispatchResult {
let reported = ensure_signed(origin)?;
<staking::Module<T>>::reward_by_ids(vec![(reported, 10)]);
Ok(())
}
}
}
实现细节
时代支付
时代支付是使用定义在T::RewardCurve
的年度通货膨胀曲线计算的,如下所示:
staker_payout = yearly_inflation(npos_token_staked / total_tokens) * total_tokens / era_per_year
此支付用于在下文定义的下一个部分中奖励抵押者。
remaining_payout = max_yearly_inflation * total_tokens / era_per_year - staker_payout
剩余的奖励将发送到可配置的终点T::RewardRemainder
。
奖励计算
在每个时代结束时,验证者和提名者都会获得奖励。一个时代的总奖励是通过时代持续时间和抵押率(提名者和验证者抵押的代币总量的总和除以总代币供应量)计算的。它的目的是激励达到一个定义的抵押率。完整规范可以在这里找到。
总奖励根据验证者和其提名者在时代期间获得的积分比例在验证者和其提名者之间分配。积分通过reward_by_ids
或reward_by_indices
添加到验证者。
Module
实现了noble_authorship::EventHandler
以向块生产者和引用的叔父块生产者添加奖励积分。
验证者和其提名者按以下方式分割其奖励:
验证器可以声明一个名为commission
的金额,该金额不会在每次奖励支付时与其提名者共享,这是通过其ValidatorPrefs
实现的。这个值会从支付给验证器及其提名者的总奖励中扣除。剩余部分按比例分配给验证器和所有提名该验证器的提名者,比例与该验证器背后的质押价值相关(即,通过Exposure
中的own
或others
除以total
)。
所有获得奖励的实体都有选择通过Payee
存储项目(见set_payee
)来选择其奖励目的地的选项,可以是以下之一
- 控制账户,显然不会增加质押价值。
- Stash账户,不会增加质押价值。
- Stash账户,也会增加质押价值。
额外资金管理操作
已放入stash的资金可以是以下操作的目标
控制账户可以使用unbond
调用释放部分(或全部)资金。请注意,资金不能立即获取。相反,必须经过由BondingDuration
(以时代数量表示)表示的时间段。一旦BondingDuration
结束,可以使用withdraw_unbonded
调用实际提取资金。
请注意,可以通过unbond
调度的未来解锁资金块数量有限制。如果在达到最大值(MAX_UNLOCKING_CHUNKS
)的情况下,必须先等待成功的withdraw_unbonded
调用以移除一些块。
选举算法
当前的选举算法是基于Phragmén实现的。参考实现可以在这里找到。
选举算法除了选举具有最大质押价值和投票的验证器外,还试图以平等的方式分配提名者的投票。为了进一步确保这一点,可以应用一个可选的后处理,该处理会迭代地规范提名者的质押价值,直到特定提名者的投票总差异小于一个阈值。
GenesisConfig
质押模块依赖于GenesisConfig
。该GenesisConfig
是可选的,允许设置一些初始的质押者。
相关模块
许可证:Apache-2.0
依赖关系
~5–15MB
~185K SLoC