Rust区块链随机数生成库pallet-insecure-randomness-collective-flip的使用,提供不安全但高效的链上随机性功能

Rust区块链随机数生成库pallet-insecure-randomness-collective-flip的使用

警告:不要在生产环境中使用

该模块生成的随机值不满足密码学随机数的安全要求。不应用于高风险的生产环境。

随机数模块

Randomness Collective Flip模块提供了一个random函数,该函数基于过去81个区块的哈希值生成低影响力随机数。这种低影响力随机性在防御相对较弱的对手时可能有用。建议仅在测试等低安全性场景中使用该模块作为随机源。

使用示例

获取当前区块的随机种子

以下是示例代码:

use frame_support::traits::Randomness;

#[frame_support::pallet]
pub mod pallet {
    use super::*;
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    #[pallet::pallet]
    pub struct Pallet<T>(_);

    #[pallet::config]
    pub trait Config: frame_system::Config + pallet_insecure_randomness_collective_flip::Config {}

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        #[pallet::weight(0)]
        pub fn random_module_example(origin: OriginFor<T>) -> DispatchResult {
            let _random_value = pallet_insecure-randomness-collective-flip::Pallet::<T>::random(&b"my context"[..]);
            Ok(())
        }
    }
}

完整示例

// 引入必要的依赖
use frame_support::{traits::Randomness, dispatch::DispatchResult};
use frame_system::pallet_prelude::*;

// 定义模块
#[frame_support::pallet]
pub mod insecure_random_demo {
    use super::*;
    
    // 声明模块
    #[pallet::pallet]
    pub struct Pallet<T>(_);
    
    // 配置trait
    #[pallet::config]
    pub trait Config: frame_system::Config + pallet_insecure_randomness_collective_flip::Config {}
    
    // 存储项
    #[pallet::storage]
    pub type LastRandomValue<T> = StorageValue<_, [u8; 32], ValueQuery>;
    
    // 模块调用
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        /// 生成并存储随机值
        #[pallet::weight(10_000)]
        pub fn generate_random(
            origin: OriginFor<T>,
            context: Vec<u8>
        ) -> DispatchResult {
            // 确保调用有权限
            ensure_signed(origin)?;
            
            // 生成随机值
            let random_bytes = pallet_insecure_randomness_collective_flip::Pallet::<T>::random(&context);
            
            // 存储随机值
            LastRandomValue::<T>::put(random_bytes);
            
            Ok(())
        }
        
        /// 获取上次生成的随机值
        #[pallet::weight(10_000)]
        pub fn get_last_random(
            origin: OriginFor<T>
        ) -> DispatchResult {
            // 确保调用有权限
            ensure_signed(origin)?;
            
            // 读取存储的随机值
            let random_value = LastRandomValue::<T>::get();
            
            // 这里可以处理随机值...
            
            Ok(())
        }
    }
}

完整示例Demo

以下是一个更完整的示例,展示如何使用该模块构建一个简单的随机数应用:

// 引入必要的依赖
use frame_support::{
    dispatch::DispatchResult,
    traits::Randomness,
    pallet_prelude::*,
};
use frame_system::pallet_prelude::*;
use sp_std::vec::Vec;

// 定义模块
#[frame_support::pallet]
pub mod random_app {
    use super::*;
    
    // 声明模块
    #[pallet::pallet]
    pub struct Pallet<T>(_);
    
    // 配置trait
    #[pallet::config]
    pub trait Config: frame_system::Config + pallet_insecure_randomness_collective_flip::Config {
        /// 因为我们要分发事件,所以需要事件类型
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
    }
    
    // 存储项
    #[pallet::storage]
    #[pallet::getter(fn random_values)]
    pub type RandomValues<T> = StorageMap<_, Blake2_128Concat, T::AccountId, [u8; 32], ValueQuery>;
    
    // 定义事件
    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        /// 存储了新的随机值 [谁存储的, 随机值]
        RandomValueStored(T::AccountId, [u8; 32]),
    }
    
    // 错误处理
    #[pallet::error]
    pub enum Error<T> {
        /// 随机值生成失败
        RandomGenerationFailed,
    }
    
    // 模块调用
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        /// 生成并存储随机值
        #[pallet::weight(10_000)]
        pub fn generate_and_store(
            origin: OriginFor<T>,
            context: Vec<u8>
        ) -> DispatchResult {
            // 验证调用者
            let who = ensure_signed(origin)?;
            
            // 生成随机值
            let random_bytes = pallet_insecure_randomness_collective_flip::Pallet::<T>::random(&context);
            
            // 存储随机值
            RandomValues::<T>::insert(&who, random_bytes);
            
            // 发出事件
            Self::deposit_event(Event::RandomValueStored(who, random_bytes));
            
            Ok(())
        }
        
        /// 获取指定账户的随机值
        #[pallet::weight(10_000)]
        pub fn get_random_value(
            origin: OriginFor<T>,
            account: T::AccountId
        ) -> DispatchResult {
            // 验证调用者
            ensure_signed(origin)?;
            
            // 读取存储的随机值
            let _random_value = RandomValues::<T>::get(&account);
            
            // 这里可以处理随机值...
            
            Ok(())
        }
    }
}

安装

在项目目录中运行以下Cargo命令:

cargo add pallet-insecure-randomness-collective-flip

或者在Cargo.toml中添加:

pallet-insecure-randomness-collective-flip = "30.0.0"

许可证: Apache-2.0


1 回复

Rust区块链随机数生成库pallet-insecure-randomness-collective-flip使用指南

概述

pallet-insecure-randomness-collective-flip是Substrate框架中的一个模块,提供了一种简单但不安全的链上随机数生成机制。它基于前一个区块的哈希值生成随机数,虽然效率高但不适合安全敏感的场景。

主要特点

  • 高效性:基于前一个区块的哈希值计算,性能开销低
  • 确定性:所有节点都能验证和重现随机数
  • 不安全:容易被区块生产者预测和操纵
  • 简单接口:易于集成和使用

使用方法

1. 添加依赖

在runtime的Cargo.toml中添加依赖:

[dependencies.pallet-insecure-randomness-collective-flip]
default-features = false
git = 'https://github.com/paritytech/substrate.git'
branch = 'master'

2. 在runtime中实现

impl pallet_insecure_randomness_collective_flip::Config for Runtime {}

construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        // ... 其他pallet
        RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip::{Pallet, Storage},
    }
);

3. 生成随机数

在其他pallet中可以通过以下方式获取随机数:

use frame_support::traits::Randomness;

// 获取随机数
let random_seed = RandomnessCollectiveFlip::random_seed();
let random_subject = b"my context";
let random_number = RandomnessCollectiveFlip::random(&random_subject);

4. 完整示例

use frame_support::{decl_module, decl_storage, traits::Randomness};
use sp_runtime::traits::Hash;

pub trait Config: pallet_insecure-randomness-collective-flip::Config {}

decl_storage! {
    trait Store for Module<T: Config> as ExampleModule {
        pub LastRandomNumber get(fn last_random_number): u64;
    }
}

decl_module! {
    pub struct Module<T: Config> for enum Call where origin: T::Origin {
        fn on_initialize() {
            // 获取随机数
            let random_seed = pallet_insecure_randomness_collective_flip::Pallet::<T>::random_seed();
            let random_number = Self::derive_random_number(random_seed);
            
            // 存储随机数
            <LastRandomNumber<T>>::put(random_number);
        }
    }
}

impl<T: Config> Module<T> {
    fn derive_random_number(seed: T::Hash) -> u64 {
        // 简单的从哈希值派生出随机数
        let bytes = seed.as_ref();
        let mut number = 0u64;
        
        for (i, byte) in bytes.iter().take(8).enumerate() {
            number += (*byte as u64) << (i * 8);
        }
        
        number
    }
}

安全警告

此随机数生成器不安全,因为:

  • 区块生产者可以预知下一个区块的随机数
  • 攻击者可以通过选择性地不发布区块来影响随机数
  • 不适合用于赌博、抽奖等安全敏感场景

替代方案

对于需要安全随机数的场景,建议考虑:

  • pallet-babepallet-grandpa提供的随机信标
  • 使用VRF(可验证随机函数)的pallet
  • 链下随机数预言机

总结

pallet-insecure-randomness-collective-flip提供了简单高效的链上随机数生成功能,适合非安全关键的场景。使用时应当充分了解其局限性,并根据应用场景选择适当的随机数源。

完整示例demo

下面是一个更完整的示例,展示如何在自定义pallet中使用随机数生成器:

// 自定义pallet示例:随机数抽奖系统(仅用于演示,不适用于生产环境)

use frame_support::{decl_module, decl_storage, decl_event, traits::Randomness};
use frame_system::ensure_root;
use sp_runtime::traits::Hash;
use sp_std::vec::Vec;

/// 配置trait
pub trait Config: pallet_insecure_randomness_collective_flip::Config {
    type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
}

// 存储项定义
decl_storage! {
    trait Store for Module<T: Config> as Lottery {
        // 参与者列表
        Participants get(fn participants): Vec<T::AccountId>;
        // 中奖者
        Winner get(fn winner): Option<T::AccountId>;
    }
}

// 事件定义
decl_event! {
    pub enum Event<T> where AccountId = <T as frame_system::Config>::AccountId {
        // 参与事件
        Participated(AccountId),
        // 抽奖事件
        LotteryDrawn(AccountId),
    }
}

// 模块定义
decl_module! {
    pub struct Module<T: Config> for enum Call where origin: T::Origin {
        fn deposit_event() = default;

        // 参与抽奖
        #[weight = 10_000]
        fn participate(origin) {
            let who = ensure_signed(origin)?;
            
            <Participants<T>>::mutate(|participants| {
                participants.push(who.clone());
            });
            
            Self::deposit_event(RawEvent::Participated(who));
        }

        // 开奖(仅root可调用)
        #[weight = 10_000]
        fn draw_lottery(origin) {
            ensure_root(origin)?;
            
            let participants = <Participants<T>>::get();
            if participants.is_empty() {
                return;
            }
            
            // 获取随机种子
            let seed = pallet_insecure_randomness_collective_flip::Pallet::<T>::random_seed();
            // 生成随机索引
            let winner_index = Self::random_index(seed, participants.len() as u32);
            let winner = participants[winner_index as usize].clone();
            
            // 存储中奖者
            <Winner<T>>::put(winner.clone());
            // 清空参与者列表
            <Participants<T>>::kill();
            
            Self::deposit_event(RawEvent::LotteryDrawn(winner));
        }
    }
}

impl<T: Config> Module<T> {
    // 从随机种子生成指定范围内的随机索引
    fn random_index(seed: T::Hash, max: u32) -> u32 {
        let bytes = seed.as_ref();
        let mut index = 0u32;
        
        // 使用种子字节生成索引
        for (i, byte) in bytes.iter().take(4).enumerate() {
            index += (*byte as u32) << (i * 8);
        }
        
        index % max
    }
}

这个示例展示了:

  1. 如何使用pallet-insecure-randomness-collective-flip生成随机数
  2. 如何基于随机数实现简单的抽奖逻辑
  3. 存储参与者和中奖者信息
  4. 发出相应事件

再次强调,此示例仅用于演示,不应用于生产环境,因为使用的随机数生成器不安全。

回到顶部