Rust质押奖励函数库pallet-staking-reward-fn的使用,Substrate区块链staking模块自定义奖励机制实现
Rust质押奖励函数库pallet-staking-reward-fn的使用,Substrate区块链staking模块自定义奖励机制实现
安装
在项目目录中运行以下Cargo命令:
cargo add pallet-staking-reward-fn
或者在Cargo.toml中添加以下行:
pallet-staking-reward-fn = "24.0.0"
使用示例
以下是如何使用pallet-staking-reward-fn实现自定义质押奖励机制的完整示例:
use frame_support::{decl_module, decl_storage, dispatch::DispatchResult};
use pallet_staking_reward_fn::{RewardFunction, RewardParams};
use sp_runtime::Perbill;
// 1. 定义你的自定义奖励函数
pub struct CustomRewardFunction;
impl RewardFunction for CustomRewardFunction {
fn calculate_reward(params: RewardParams) -> Perbill {
// 自定义奖励计算逻辑
// 例如:根据质押时间和金额计算奖励
let base_reward = Perbill::from_percent(5); // 5%基础奖励
// 如果质押超过100个代币,增加1%
if params.stake > 100.into() {
base_reward + Perbill::from_percent(1)
} else {
base_reward
}
}
}
// 2. 在你的pallet中使用自定义奖励函数
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin {
fn set_reward_function(origin) -> DispatchResult {
// 设置自定义奖励函数
pallet_staking_reward_fn::RewardFunctionProvider::<T>::set(RewardFunctionType::Custom(Box::new(CustomRewardFunction)));
Ok(())
}
}
}
// 3. 在你的runtime中配置staking奖励函数
impl pallet_staking::Config for Runtime {
// ...
type RewardFunction = pallet_staking_reward_fn::RewardFunctionAdapter<CustomRewardFunction>;
// ...
}
实现细节
-
自定义奖励函数:
- 实现
RewardFunction
trait - 根据
RewardParams
(包含质押金额、时间等参数)计算奖励比例 - 返回
Perbill
类型,表示奖励比例
- 实现
-
在pallet中使用:
- 通过
RewardFunctionProvider
设置自定义奖励函数 - 可以动态切换不同的奖励算法
- 通过
-
runtime配置:
- 在staking pallet配置中指定自定义奖励函数
- 使用
RewardFunctionAdapter
适配器将自定义函数集成到staking模块
完整示例代码
// runtime/src/lib.rs
use frame_support::{parameter_types, traits::Everything};
use sp_runtime::{
traits::{IdentifyAccount, Verify},
Perbill,
};
// 1. 定义自定义奖励函数
pub struct TieredRewardFunction;
impl pallet_staking_reward_fn::RewardFunction for TieredRewardFunction {
fn calculate_reward(params: pallet_staking_reward_fn::RewardParams) -> Perbill {
// 分级奖励算法
match params.stake {
stake if stake > 1000.into() => Perbill::from_percent(8), // 大额质押8%
stake if stake > 500.into() => Perbill::from_percent(6), // 中额质押6%
stake if stake > 100.into() => Perbill::from_percent(5), // 小额质押5%
_ => Perbill::from_percent(3), // 默认3%
}
}
}
// 2. 创建自定义pallet
pub mod custom_staking_pallet {
use super::*;
use frame_support::{decl_module, decl_storage, dispatch::DispatchResult};
use frame_system::ensure_root;
pub trait Config: frame_system::Config {}
decl_storage! {
trait Store for Module<T: Config> as CustomStakingPallet {
// 存储定义
}
}
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin {
// 设置奖励函数
#[weight = 0]
pub fn set_reward_function(origin) -> DispatchResult {
ensure_root(origin)?;
// 使用TieredRewardFunction作为奖励函数
pallet_staking_reward_fn::RewardFunctionProvider::<T>::set(
pallet_staking_reward_fn::RewardFunctionType::Custom(Box::new(TieredRewardFunction))
);
Ok(())
}
}
}
}
// 3. runtime配置
parameter_types! {
pub const SessionsPerEra: sp_staking::SessionIndex = 6;
pub const BondingDuration: sp_staking::EraIndex = 24;
}
impl pallet_staking::Config for Runtime {
type Currency = Balances;
type UnixTime = Timestamp;
type CurrencyToVote = U128CurrencyToVote;
type RewardFunction = pallet_staking_reward_fn::RewardFunctionAdapter<TieredRewardFunction>;
type SessionsPerEra = SessionsPerEra;
type BondingDuration = BondingDuration;
type Slash = ();
type SessionInterface = Self;
type Event = Event;
type WeightInfo = ();
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
}
// 4. 在construct_runtime!宏中包含pallet
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// ...
Staking: pallet_staking::{Pallet, Call, Storage, Config<T>, Event<T>},
CustomStakingPallet: custom_staking_pallet::{Pallet, Call, Storage},
// ...
}
);
功能说明
-
分级奖励机制:
- 根据质押金额不同提供不同奖励比例
- 大额质押(>1000)获得8%奖励
- 中额质押(>500)获得6%奖励
- 小额质押(>100)获得5%奖励
- 默认3%奖励
-
动态设置:
- 通过root账户调用set_reward_function方法
- 可以随时更换奖励算法
-
与staking模块集成:
- 通过RewardFunctionAdapter将自定义函数集成到staking模块
- 保持与原生staking模块的兼容性
1 回复
Rust质押奖励函数库pallet-staking-reward-fn的使用
介绍
pallet-staking-reward-fn
是一个Substrate区块链框架中的自定义质押奖励函数库,它允许开发者灵活地实现和定制质押(staking)模块的奖励分配机制。这个库特别适合需要超越标准线性奖励模型的区块链项目。
主要功能
- 提供可插拔的奖励计算接口
- 支持自定义奖励算法实现
- 与Substrate的staking模块无缝集成
- 允许基于不同参数(如质押时间、数量等)计算奖励
使用方法
1. 添加依赖
首先在项目的Cargo.toml
中添加依赖:
[dependencies]
pallet-staking-reward-fn = { git = "https://github.com/paritytech/substrate", branch = "master" }
2. 实现奖励特征
你需要实现RewardFunction
特征:
use pallet_staking_reward_fn::RewardFunction;
use sp_runtime::Perbill;
struct CustomReward;
impl RewardFunction for CustomReward {
fn calculate_reward(
staked_amount: Balance,
staking_duration: BlockNumber,
total_staked: Balance,
) -> Balance {
// 自定义奖励计算逻辑
// 示例:基于质押时间的平方根计算奖励
let duration_factor = (staking_duration as f64).sqrt();
let reward = staked_amount * Perbill::from_percent(10) * duration_factor;
reward
}
}
3. 集成到Runtime
在你的runtime中集成自定义奖励函数:
impl pallet_staking::Config for Runtime {
type RewardFunction = CustomReward;
// 其他配置...
}
示例实现
线性奖励模型
struct LinearReward;
impl RewardFunction for LinearReward {
fn calculate_reward(
staked_amount: Balance,
_staking_duration: BlockNumber,
_total_staked: Balance,
) -> Balance {
// 简单线性奖励:质押金额的5%
staked_amount * Perbill::from_percent(5)
}
}
递减奖励模型
struct DecreasingReward;
impl RewardFunction for DecreasingReward {
fn calculate_reward(
staked_amount: Balance,
staking_duration: BlockNumber,
total_staked: Balance,
) -> Balance {
// 奖励随质押时间递减
let base_reward = staked_amount * Perbill::from_percent(10);
let decay_factor = 极1.0 / (1.0 + (staking_duration as f64 / 1000.0));
(base_reward as f64 * decay_factor) as Balance
}
}
基于总质押量的动态奖励
struct DynamicReward;
impl RewardFunction for DynamicReward {
fn calculate_reward(
staked_amount: Balance,
_staking_duration: BlockNumber,
total_staked: Balance,
) -> Balance {
// 总质押量越少,奖励比例越高
let ratio = total_staked / staked_amount;
let reward_percent = 20u32.saturating_sub(ratio as u32 / 1000);
staked_amount * Perbill::from_percent(reward_percent)
}
}
完整示例demo
下面是一个完整的runtime集成示例,展示了如何使用自定义奖励函数:
//! 自定义质押奖励函数完整示例
use frame_support::traits::{Currency, Imbalance, OnUnbalanced};
use frame_system as system;
use sp_runtime::{Perbill, traits::{AccountIdConversion, Saturating}};
use pallet_staking_reward_fn::RewardFunction;
// 1. 定义自定义奖励函数
struct ExponentialReward;
impl RewardFunction for ExponentialReward {
fn calculate_reward(
staked_amount: Balance,
staking_duration: BlockNumber,
_total_staked: Balance,
) -> Balance {
// 指数增长奖励模型
// 基础奖励率1%,每1000个区块奖励增加0.1%
let base_rate = Perbill::from_percent(1);
let bonus_rate = Perbill::from_perthousand(staking_duration / 1000);
staked_amount * (base_rate + bonus_rate)
}
}
// 2. 定义runtime配置
pub trait Config: frame_system::Config {
type RewardFunction: RewardFunction;
type Currency: Currency<Self::AccountId>;
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
}
// 3. 实现staking pallet配置
impl pallet_staking::Config for Runtime {
type RewardFunction = ExponentialReward;
type Currency = Balances;
type Event = Event;
// 其他必要配置...
}
// 4. 构建runtime
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system::{Module, Call, Config, Storage, Event<T>},
Staking: pallet_staking::{Module, Call, Config<T>, Storage, Event<T>},
Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
}
);
最佳实践
- 测试奖励函数:确保在各种边界条件下测试你的奖励函数
- 考虑精度:使用
Perbill
或Permill
来处理小数计算 - 性能考量:复杂的计算可能会影响区块生产时间
- 安全性:确保奖励计算不会导致通胀或资金异常
注意事项
- 奖励函数会在每个区块或每个era被调用,应保持高效
- 确保你的奖励模型与代币经济模型一致
- 考虑实现
OnStakingUpdate
trait来响应质押状态变化
通过pallet-staking-reward-fn
,你可以为Substrate区块链创建高度定制化的质押奖励机制,满足各种经济模型需求。