Substrate no_std环境下引入rand包WeightedIndex、StdRng报错如何解决?
问题原因
rand包在关闭默认特性(default-features = false)的情况下,WeightedIndex所属的加权分布功能需要额外启用weighted特性才能导入;同时WeightedIndex内部需要动态内存分配,依赖alloc特性,no_std环境下默认不开启该特性。StdRng是依赖系统熵源的随机数生成器,本身不支持no_std环境。Substrate Runtime是WASM的no_std环境,没有系统级熵源接口,因此无法导入和使用StdRng。
解决方案
第一步 调整Cargo.toml依赖配置
修改rand的依赖声明,补充需要的特性:
[dependencies] rand = { version = "0.8.4", default-features = false, features = ["alloc", "weighted", "small_rng"] }
同时在pallet的std特性配置中,补充rand的std特性适配native编译:
[features] default = ["std"] std = [ "rand/std", # 保留原有其他依赖的std配置 ]
第二步 替换不兼容的随机数生成器
将StdRng替换为纯算法实现、no_std兼容的SmallRng,修改导入和实例化代码:
use rand::distributions::WeightedIndex; use rand::prelude::*; use rand::{rngs::SmallRng, SeedableRng}; fn draw_juror_for_citizen_profile_function( citizen_id: u128, length: usize, ) -> DispatchResult { let nonce = Self::get_and_increment_nonce(); let random_seed = T::RandomnessSource::random(&nonce).encode(); let random_number = u64::decode(&mut random_seed.as_ref()) .expect("secure hashes should always be bigger than u32; qed"); // 替换为SmallRng let mut rng: SmallRng = SeedableRng::seed_from_u64(random_number); // 后续即可正常使用WeightedIndex,示例: // let weights = vec![1, 2, 3]; // let dist = WeightedIndex::new(&weights).unwrap(); // let selected_index = dist.sample(&mut rng); Ok(()) } fn get_and_increment_nonce() -> Vec<u8> { let nonce = <Nonce<T>>::get(); <Nonce<T>>::put(nonce.wrapping_add(1)); nonce.encode() }
注意事项
- Substrate Runtime默认启用
alloc,因此rand开启alloc特性不会和no_std环境冲突。 - 如果需要更高安全性的随机数生成器,可以选择引入
rand_chacha依赖,使用ChaCha20Rng替代SmallRng,该实现同样支持no_std环境。
内容的提问来源于stack exchange,提问作者Amiya Behera
相关产品推荐
相关产品推荐

