Rust提名池性能基准测试库pallet-nomination-pools-benchmarking的使用,优化Substrate链上质押池性能评估

以下是根据您提供的内容整理的完整示例demo,展示了如何使用pallet-nomination-pools-benchmarking库来评估Substrate链上质押池的性能:

use frame_benchmarking::{benchmarks, impl_benchmark_test_suite};
use frame_system::RawOrigin;
use pallet_nomination_pools::{BondExtra, Pallet as Pools};
use pallet_nomination_pools::Config as PoolsConfig;
use pallet_nomination_pools_benchmarking::Pallet as PoolsBench;

// 生成验证人账户的辅助函数
fn generate_validator<T: PoolsConfig>(index: u32) -> T::AccountId {
    let account = frame_benchmarking::account("validator", index, 0);
    account.into()
}

benchmarks! {
    // 基准测试:创建新的提名池
    create {
        let caller: T::AccountId = whitelisted_caller();
        let amount = T::Currency::minimum_balance() * 10u32.into();
        T::Currency::make_free_balance_be(&caller, amount);
    }: _(RawOrigin::Signed(caller), amount)
    verify {
        // 验证池是否创建成功
        assert_eq!(Pools::<T>::last_pool_id(), 1u32.into());
    }
    
    // 基准测试:提名验证人
    nominate {
        let n in 1 .. T::MaxNominations::get();
        let caller: T::AccountId = whitelisted_caller();
        let amount = T::Currency::minimum_balance() * 10u32.into();
        T::Currency::make_free_balance_be(&caller, amount);
        
        let pool_id = Pools::<T>::create(RawOrigin::Signed(caller.clone()).into(), amount)?;
        let validators = (0..n).map(|i| generate_validator::<T>(i)).collect::<Vec<_>>();
    }: _(RawOrigin::Signed(caller), pool_id, validators)
    verify {
        // 验证提名操作是否成功
        assert!(Pools::<T>::nominations(pool_id).is_some());
    }
    
    // 基准测试:质押更多资金
    bond_extra {
        let caller: T::AccountId = whitelisted_caller();
        let initial_amount = T::Currency::minimum_balance() * 10u32.into();
        let extra_amount = T::Currency::minimum_balance() * 5u32.into();
        T::Currency::make_free_balance_be(&caller, initial_amount + extra_amount);
        
        let pool_id = Pools::<T>::create(RawOrigin::Signed(caller.clone()).into(), initial_amount)?;
    }: _(RawOrigin::Signed(caller), BondExtra::FreeBalance(extra_amount))
    verify {
        // 验证质押金额是否正确增加
        let member = Pools::<T>::pool_members(&caller).unwrap();
        assert_eq!(member.points, initial_amount + extra_amount);
    }
    
    // 基准测试:解绑质押资金
    unbond {
        let caller: T::AccountId = whitelisted_caller();
        let amount = T::Currency::minimum_balance() * 10u32.into();
        T::Currency::make_free_balance_be(&caller, amount * 2u32.into());
        
        let pool_id = Pools::<T>::create(RawOrigin::Signed(caller.clone()).into(), amount)?;
    }: _(RawOrigin::Signed(caller), pool_id, amount)
    verify {
        // 验证解绑操作是否成功
        let member = Pools::<T>::pool_members(&caller).unwrap();
        assert!(member.unbonding_eras.len() > 0);
    }
}

impl_benchmark_test_suite!(
    PoolsBench,
    crate::mock::new_test_ext(),
    crate::mock::Test,
);

这个完整示例在原有基础上增加了:

  1. 解绑质押资金的基准测试
  2. 每个基准测试的验证逻辑
  3. 生成验证人账户的辅助函数
  4. 更完整的类型导入

使用该库可以全面评估提名池的各种操作性能,包括创建、提名、质押和解绑等关键操作。建议在测试环境中运行这些基准测试,并根据结果优化链上参数配置。


1 回复

Rust提名池性能基准测试库pallet-nomination-pools-benchmarking使用指南

概述

pallet-nomination-pools-benchmarking是Substrate框架中的一个专用库,用于对提名池(pallet-nomination-pools)进行性能基准测试。该库帮助开发者评估和优化Substrate链上质押池的性能表现,确保网络在高负载下仍能保持稳定运行。

主要功能

  • 提供标准化的提名池操作基准测试
  • 测量不同操作在链上的执行时间和资源消耗
  • 帮助确定合理的权重(weights)参数
  • 评估不同硬件配置下的性能表现

使用方法

1. 添加依赖

首先需要在runtime的Cargo.toml中添加基准测试依赖:

[dev-dependencies]
pallet-nomination-pools-benchmarking = { version = "4.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-vX.Y.Z" }

2. 配置基准测试

在runtime的benchmarking模块中配置提名池基准测试:

#[cfg(feature = "runtime-benchmarks")]
mod benches {
    use super::*;
    use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
    
    impl pallet_nomination_pools_benchmarking::Config for Runtime {}
    
    frame_benchmarking::benchmarks! {
        join_pool {
            // 基准测试代码
        }
        
        // 其他操作基准测试
    }
}

3. 运行基准测试

使用Substrate的benchmark子命令运行测试:

./target/release/your-node benchmark pallet \
    --chain=dev \
    --execution=wasm \
    --wasm-execution=compiled \
    --pallet=pallet_nomination_pools \
    --extrinsic="*" \
    --steps=50 \
    --repeat=20 \
    --output=./pallets/nomination-pools/src/weights.rs

4. 常见基准测试示例

加入质押池基准测试

join_pool {
    let caller: T::AccountId = whitelisted_caller();
    let bond = 100 * DOLLARS;
    let pool_id = Pools::<T>::create(bond, caller.clone()).unwrap();
}: _(RawOrigin::Signed(caller), pool_id, bond)

创建新池基准测试

create {
    let caller: T::AccountId = whitelisted_caller();
    let bond = 100 * DOLLARS;
}: _(RawOrigin::Signed(caller), bond)

提名基准测试

nominate {
    let n in 1 .. MAX_VALIDATORS;
    let caller: T::AccountId = whitelisted_caller();
    let bond = 100 * DOLLARS;
    let pool_id = Pools::<T>::create(b bond, caller.clone()).unwrap();
    
    let validators = create_validators::<T>(n);
    frame_system::Pallet::<T>::set_block_number(1u32.into());
}: _(RawOrigin::Signed(caller), pool_id, validators)

完整示例代码

以下是一个完整的提名池基准测试示例,包含创建池、加入池和提名验证人等操作:

// runtime/src/benchmarking.rs
#[cfg(feature = "runtime-benchmarks")]
mod nomination_pools_benchmarking {
    use super::*;
    use frame_benchmarking::{benchmarks, whitelisted_caller};
    use frame_system::RawOrigin;
    use pallet_nomination_pools::Pallet as Pools;
    
    // 实现配置trait
    impl pallet_nomination_pools_benchmarking::Config for Runtime {}
    
    // 定义基准测试模块
    benchmarks! {
        // 创建新池的基准测试
        create {
            // 创建白名单调用者账户
            let caller: T::AccountId = whitelisted_caller();
            // 设置质押金额
            let bond = 100 * DOLLARS;
        }: _(RawOrigin::Signed(caller), bond)
        
        // 加入质押池的基准测试
        join_pool {
            let caller: T::AccountId = whitelisted_caller();
            let bond = 100 * DOLLARS;
            // 先创建一个池
            let pool_id = Pools::<T>::create(bond, caller.clone()).unwrap();
        }: _(RawOrigin::Signed(caller), pool_id, bond)
        
        // 提名验证人的基准测试
        nominate {
            // n的范围从1到最大验证人数
            let n in 1 .. MAX_VALIDATORS;
            let caller: T::AccountId = whitelisted_caller();
            let bond = 100 * DOLLARS;
            // 创建池
            let pool_id = Pools::<T>::create(bond, caller.clone()).unwrap();
            // 创建n个验证人
            let validators = create_validators::<T>(n);
            // 设置区块号
            frame_system::Pallet::<T>::set_block_number(1u32.into());
        }: _(RawOrigin::Signed(caller), pool_id, validators)
        
        // 其他操作可以继续添加...
    }
    
    // 辅助函数,创建指定数量的验证人
    fn create_validators<T: Config>(count: u32) -> Vec<T::AccountId> {
        (0..count).map(|i| account("validator", i, 0)).collect()
    }
}

优化建议

  1. 权重校准:根据基准测试结果调整操作权重,确保区块处理时间合理
  2. 硬件评估:在不同硬件配置上运行测试,确定最优节点配置
  3. 参数调优:根据测试结果调整链上参数如:
    • 最大池数量
    • 最大池成员数
    • 最大验证人提名数
  4. 监控关键指标:重点关注:
    • 执行时间
    • 存储读写次数
    • 内存使用情况

输出解释

基准测试完成后,会生成类似以下输出:

Pallet: "pallet_nomination_pools", Extrinsic: "join_pool", Lowest values: [], Highest values: [], Steps: 50, Repeat: 20
Raw Storage Info:
  Storage: NominationPools PoolMembers (r:1, w:1)
  Storage: NominationPools CounterForPoolMembers (r:1, w:1)
  Storage: System Account (r:1, w:1)
  Storage: Balances Locks (r:1, w:1)
  Storage: NominationPools BondedPools (r:1, w:0)
  Storage: NominationPools RewardPools (r:1, w:0)

Median Slopes Analysis
  Extrinsic Time: 123.456 µs
  Storage Reads: 5
  Storage Writes: 3

通过这些数据可以评估操作的成本并相应调整链参数。

注意事项

  1. 基准测试应在与生产环境相似的硬件上运行
  2. 测试数据应覆盖各种边界情况
  3. 定期重新运行基准测试,特别是在Substrate版本升级后
  4. 考虑网络延迟和IO性能对实际运行的影响
回到顶部