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-babe
或pallet-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
}
}
这个示例展示了:
- 如何使用
pallet-insecure-randomness-collective-flip
生成随机数 - 如何基于随机数实现简单的抽奖逻辑
- 存储参与者和中奖者信息
- 发出相应事件
再次强调,此示例仅用于演示,不应用于生产环境,因为使用的随机数生成器不安全。