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>;
    // ...
}

实现细节

  1. 自定义奖励函数:

    • 实现RewardFunction trait
    • 根据RewardParams(包含质押金额、时间等参数)计算奖励比例
    • 返回Perbill类型,表示奖励比例
  2. 在pallet中使用:

    • 通过RewardFunctionProvider设置自定义奖励函数
    • 可以动态切换不同的奖励算法
  3. 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},
        // ...
    }
);

功能说明

  1. 分级奖励机制:

    • 根据质押金额不同提供不同奖励比例
    • 大额质押(>1000)获得8%奖励
    • 中额质押(>500)获得6%奖励
    • 小额质押(>100)获得5%奖励
    • 默认3%奖励
  2. 动态设置:

    • 通过root账户调用set_reward_function方法
    • 可以随时更换奖励算法
  3. 与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>},
    }
);

最佳实践

  1. 测试奖励函数:确保在各种边界条件下测试你的奖励函数
  2. 考虑精度:使用PerbillPermill来处理小数计算
  3. 性能考量:复杂的计算可能会影响区块生产时间
  4. 安全性:确保奖励计算不会导致通胀或资金异常

注意事项

  • 奖励函数会在每个区块或每个era被调用,应保持高效
  • 确保你的奖励模型与代币经济模型一致
  • 考虑实现OnStakingUpdate trait来响应质押状态变化

通过pallet-staking-reward-fn,你可以为Substrate区块链创建高度定制化的质押奖励机制,满足各种经济模型需求。

回到顶部