Rust Substrate区块链框架pallet-preimage插件库的使用,实现链上数据预处理与存储功能
Rust Substrate区块链框架pallet-preimage插件库的使用,实现链上数据预处理与存储功能
安装
在项目目录中运行以下Cargo命令:
cargo add pallet-preimage
或者在Cargo.toml中添加以下行:
pallet-preimage = "42.0.0"
使用示例
pallet-preimage是Substrate框架中的一个重要组件,用于将数据预处理并存储在链上,以便后续使用。以下是完整的使用示例:
// 在runtime/src/lib.rs中配置pallet-preimage
use frame_support::traits::PreimageProvider;
use pallet_preimage::{Config, Pallet};
// 配置trait实现
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type Currency: ReservableCurrency<Self::AccountId>;
type ManagerOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type WeightInfo: WeightInfo;
}
// 在construct_runtime!宏中添加pallet
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
// ...其他pallet...
Preimage: pallet_preimage::{Pallet, Call, Storage, Event<T>},
}
);
// 示例使用方法
impl pallet_preimage::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type ManagerOrigin = EnsureRoot<AccountId>;
type WeightInfo = pallet_preimage::weights::SubstrateWeight<Runtime>;
}
主要功能实现
// 存储预处理数据
let data = vec![1, 2, 3, 4, 5]; // 需要存储的数据
let hash = sp_io::hashing::blake2_256(&data); // 计算数据的哈希
// 提交数据到链上
pallet_preimage::Pallet::<Runtime>::note_preimage(
RuntimeOrigin::signed(caller),
data.clone(),
)?;
// 检查数据是否已存储
assert!(pallet_preimage::Pallet::<Runtime>::preimage(hash).is_some());
// 使用存储的数据
let retrieved_data = pallet_preimage::Pallet::<Runtime>::preimage(hash)
.expect("数据应该存在");
assert_eq!(retrieved_data, data);
// 清理不再需要的数据
pallet_preimage::Pallet::<Runtime>::unnote_preimage(
RuntimeOrigin::signed(caller),
hash.into(),
)?;
完整示例demo
以下是一个完整的pallet-preimage使用示例,展示了从配置到实际使用的全过程:
// runtime/src/lib.rs
use frame_support::{
construct_runtime, parameter_types,
traits::{Currency, ReservableCurrency},
weights::Weight,
};
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
AccountId32, Perbill,
};
// 基础配置
type Block = frame_system::mocking::MockBlock<Runtime>;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
// 实现Runtime配置
impl frame_system::Config for Runtime {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId32;
type Lookup = IdentityLookup<Self::AccountId>;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
// 预定义类型
type Balance = u128;
// 实现pallet_balances配置
impl pallet_balances::Config for Runtime {
type Balance = Balance;
type DustRemoval = ();
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
type MaxLocks = ();
type MaxReserves = ();
type ReserveIdentifier = [u8; 8];
type FreezeIdentifier = ();
type MaxFreezes = ();
type HoldIdentifier = ();
type MaxHolds = ();
}
// 实现pallet_preimage配置
impl pallet_preimage::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type ManagerOrigin = frame_system::EnsureRoot<AccountId32>;
type WeightInfo = ();
}
// 构建Runtime
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system,
Balances: pallet_balances,
Preimage: pallet_preimage,
}
);
// 测试用例
#[test]
fn test_preimage_workflow() {
use frame_support::assert_ok;
use pallet_preimage::Call as PreimageCall;
// 初始化测试环境
let mut t = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.unwrap();
// 设置初始余额
pallet_balances::GenesisConfig::<Runtime> {
balances: vec![(1, 1000)],
}
.assimilate_storage(&mut t)
.unwrap();
let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| {
// 测试数据
let data = vec![1, 2, 3, 4, 5];
let hash = sp_io::hashing::blake2_256(&data);
// 测试note_preimage
assert_ok!(Preimage::note_preimage(
RuntimeOrigin::signed(1),
data.clone()
));
// 验证数据存储
assert!(Preimage::preimage(hash).is_some());
let stored = Preimage::preimage(hash).unwrap();
assert_eq!(stored, data);
// 测试unnote_preimage
assert_ok!(Preimage::unnote_preimage(
RuntimeOrigin::signed(1),
hash.into()
));
// 验证数据已删除
assert!(Preimage::preimage(hash).is_none());
});
}
关键点说明
- 数据预处理:数据在上链前会计算哈希,哈希作为数据的唯一标识
- 存储机制:数据实际存储在链上,可以通过哈希查询
- 费用处理:存储数据需要支付费用,费用与数据大小相关
- 生命周期管理:可以通过
unnote_preimage
清理不再需要的数据
注意事项
- 数据存储需要支付相应的存储费用
- 大尺寸数据不适合直接存储在链上
- 需要合理管理数据生命周期,避免不必要的存储开销
pallet-preimage为Substrate区块链提供了灵活的数据预处理和存储能力,是构建复杂链上逻辑的重要基础组件。