Rust跨链桥接库pallet-bridge-parachains的使用:实现波卡生态平行链间资产与消息的安全跨链传输
Rust跨链桥接库pallet-bridge-parachains的使用:实现波卡生态平行链间资产与消息的安全跨链传输
Bridge Parachains Pallet
bridge parachains pallet 是一个或多个桥接中继链平行链的轻客户端。它作为已最终化的平行链头的来源,当您需要与平行链建立桥接时使用。
该pallet需要在同一链上部署bridge GRANDPA pallet - 它用于验证在桥接中继链上生成的存储证明。
平行链最终性简介
关键点是平行链自行生成区块,但如果没有其relay chain的帮助,它无法实现最终性。相反,平行链收集者创建一个区块并将其交给relay chain验证者。验证者验证该区块并在relay chain上部署的paras pallet的Heads映射中注册新的平行链头。
而bridge parachains pallet所做的,就是简单地验证该Heads映射中的平行链头的存储证明。它使用之前由bridge GRANDPA pallet导入的relay chain头来完成验证。一旦证明被验证,pallet就知道给定的平行链头已被relay chain最终化。然后可以使用平行链头字段来验证来自平行链的存储证明。这使得pallet可以用作例如消息pallet的最终性来源。
Pallet操作
pallet的主要入口点是submit_parachain_heads调用。它有三个参数:
- 来自Heads映射的平行链头的存储证明;
- 存储证明中的平行链标识符及其头的哈希;
- 生成存储证明时的relay block。
pallet可以跟踪多个平行链。并且平行链可能使用不同的原语 - 一个可能使用128位块号,另一个使用32位。为了避免额外的解码操作,pallet使用relay chain块号来排序平行链头。
如果pallet已经知道更好(或相同)的头,它可能会拒绝平行链头。此外,pallet拒绝未被跟踪的平行链的头。
pallet不跟踪平行链头后面的任何内容。因此它不需要初始化 - 部署后立即准备接受头。
非必要功能
在部署bridge parachains模块的每个运行时中可能有一个特殊账户。这个名为"模块所有者"的账户,就像一个模块级的sudo账户 - 他能够在不要求运行时升级的情况下暂停和恢复所有模块操作。与此账户相关的调用有:
- fn set_owner(): 当前模块所有者可以调用它将"所有权"转移到另一个账户;
- fn set_operating_mode(): 模块所有者(或sudo账户)可以调用此函数停止所有模块操作。
如果未定义pallet所有者,则可以使用治理来进行这些调用。
拒绝过时头的签名扩展
对于任何人(对于链和提交者)来说,拒绝所有向pallet提交已经知道的平行链头的交易会更好。这样,我们把块空间留给其他有用的交易,并且我们不会为并发提交者的诚实行为收费。
然而,签名扩展有点有限 - 它只适用于提供单个平行链头的交易。因此它不适用于多个平行链头交易。
平行链最终性中继
我们有一个链下参与者,他正在监视新的平行链头并将它们提交到桥接链。它是平行链中继。
示例代码
// 示例代码演示如何使用pallet-bridge-parachains实现跨链传输
use frame_support::{decl_module, decl_storage, dispatch::DispatchResult};
use sp_std::prelude::*;
// 1. 定义Runtime Trait
pub trait Trait: frame_system::Trait {
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
}
// 2. 定义存储
decl_storage! {
trait Store for Module<T: Trait> as ParachainBridge {
// 存储已接收的平行链头
ReceivedHeaders get(fn received_headers): map hasher(blake2_128_concat) T::Hash => bool;
}
}
// 3. 定义模块
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
// 事件定义
fn deposit_event() = default;
// 提交平行链头的函数
#[weight = 10_000]
pub fn submit_parachain_header(
origin,
header_hash: T::Hash,
storage_proof: Vec<u8>,
relay_block_number: T::BlockNumber,
) -> DispatchResult {
// 验证签名
let _sender = ensure_signed(origin)?;
// 验证存储证明 (简化示例)
let is_valid = verify_storage_proof(&storage_proof);
ensure!(is_valid, Error::<T>::InvalidStorageProof);
// 检查是否已接收
ensure!(!ReceivedHeaders::contains_key(&header_hash), Error::<T>::AlreadyReceived);
// 存储头
ReceivedHeaders::insert(&header_hash, true);
// 发出事件
Self::deposit_event(Event::HeaderReceived(header_hash, relay_block_number));
Ok(())
}
}
}
// 4. 错误和事件定义
pub enum Error<T> {
InvalidStorageProof,
AlreadyReceived,
}
pub enum Event<T> where <T as frame_system::Trait>::Hash {
HeaderReceived(T::Hash, T::BlockNumber),
}
// 5. 存储证明验证函数 (简化)
fn verify_storage_proof(proof: &[u8]) -> bool {
// 实际实现需要验证来自relay chain的证明
!proof.is_empty()
}
// 6. 测试模块
#[cfg(test)]
mod tests {
use super::*;
use frame_support::{assert_ok, assert_err};
use sp_core::H256;
use sp_runtime::testing::Test;
type TestParachain Bridge = Module<Test>;
#[test]
fn test_submit_header() {
let t = frame_support::GenesisConfig::default()
.build_storage::<Test>()
.unwrap();
let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| {
// 第一次提交应该成功
assert_ok!(TestParachainBridge::submit_parachain_header(
Origin::signed(1),
H256::random(),
vec![1, 2, 3],
1
));
// 第二次提交相同头应该失败
let header_hash = H256::random();
assert_ok!(TestParachainBridge::submit_parachain_header(
Origin::signed(1),
header_hash,
vec![1, 2, 3],
1
));
assert_err!(
TestParachainBridge::submit_parachain_header(
Origin::signed(1),
header_hash,
vec![1, 2, 3],
1
),
Error::<Test>::AlreadyReceived
);
// 无效存储证明应该失败
assert_err!(
TestParachainBridge::submit_parachain_header(
Origin::signed(1),
H256::random(),
vec![],
1
),
Error::<Test>::InvalidStorageProof
);
});
}
}
完整示例代码
// 完整示例代码演示如何使用pallet-bridge-parachains实现跨链资产和消息传输
use frame_support::{
decl_module, decl_storage, dispatch::DispatchResult, ensure,
traits::{Currency, Get},
weights::{DispatchClass, Pays, Weight},
};
use frame_system::{self as system, ensure_signed};
use sp_runtime::traits::{CheckedAdd, Hash, Header as HeaderT, Zero};
use sp_std::prelude::*;
// 1. 定义Runtime Trait
pub trait Trait: frame_system::Trait {
/// 事件类型
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
/// 使用的货币类型
type Currency: Currency<Self::AccountId>;
/// 最大消息长度
type MaxMessageLength: Get<u32>;
/// 桥接费用
type BridgeFee: Get<BalanceOf<Self>>;
}
// 余额类型别名
type BalanceOf<T> =
<<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
// 2. 定义存储
decl_storage! {
trait Store for Module<T: Trait> as ParachainBridge {
/// 存储已接收的平行链头
ReceivedHeaders get(fn received_headers): map hasher(blake2_128_concat) T::Hash => bool;
/// 存储跨链消息
Messages get(fn messages): map hasher(blake2_128_concat) (T::Hash, u64) => Vec<u8>;
/// 存储跨链资产
Assets get(fn assets): map hasher(blake2_128_concat) (T::Hash, T::AccountId) => BalanceOf<T>;
/// 下一个消息ID
NextMessageId get(fn next_message_id): u64;
/// 模块所有者
pub Owner get(fn owner): Option<T::AccountId>;
/// 模块运行模式
pub OperatingMode get(fn operating_mode): OperatingMode;
}
add_extra_genesis {
config(owner): Option<T::AccountId>;
config(operating_mode): OperatingMode;
build(|config| {
if let Some(ref owner) = config.owner {
<Owner<T>>::put(owner);
}
<OperatingMode>::put(config.operating_mode);
});
}
}
// 3. 运行模式枚举
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub enum OperatingMode {
/// 正常运行
Normal,
/// 暂停所有操作
Halted,
}
// 4. 定义模块
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
// 初始化函数
fn deposit_event() = default;
// 设置模块所有者
#[weight = 10_000]
pub fn set_owner(origin, new_owner: T::AccountId) -> DispatchResult {
let sender = ensure_signed(origin)?;
let current_owner = Self::owner().ok_or(Error::<T>::NoOwner)?;
ensure!(sender == current_owner, Error::<T>::NotOwner);
<Owner<T>>::put(&new_owner);
Self::deposit_event(Event::OwnerChanged(current_owner, new_owner));
Ok(())
}
// 设置运行模式
#[weight = 10_000]
pub fn set_operating_mode(origin, mode: OperatingMode) -> DispatchResult {
let sender = ensure_signed(origin)?;
if let Some(owner) = Self::owner() {
ensure!(sender == owner, Error::<T>::NotOwner);
} else {
ensure!(sender == <system::Module<T>>::root(), Error::<T>::NotRoot);
}
<OperatingMode>::put(mode.clone());
Self::deposit_event(Event::OperatingModeChanged(mode));
Ok(())
}
// 提交平行链头
#[weight = 100_000]
pub fn submit_parachain_header(
origin,
header_hash: T::Hash,
storage_proof: Vec<u8>,
relay_block_number: T::BlockNumber,
) -> DispatchResult {
// 检查运行模式
ensure!(Self::operating_mode() == OperatingMode::Normal, Error::<T>::BridgeHalted);
let sender = ensure_signed(origin)?;
// 验证存储证明 (实际实现需要更复杂的验证)
let is_valid = verify_storage_proof(&storage_proof);
ensure!(is_valid, Error::<T>::InvalidStorageProof);
// 检查是否已接收
ensure!(!ReceivedHeaders::contains_key(&header_hash), Error::<T>::AlreadyReceived);
// 存储头
ReceivedHeaders::insert(&header_hash, true);
// 发出事件
Self::deposit_event(Event::HeaderReceived(header_hash, relay_block_number));
Ok(())
}
// 发送跨链消息
#[weight = 50_000 + (T::MaxMessageLength::get() as Weight).saturating_mul(10)]
pub fn send_message(
origin,
target_chain: T::Hash,
message: Vec<u8>,
) -> DispatchResult {
// 检查运行模式
ensure!(Self::operating_mode() == OperatingMode::Normal, Error::<T>::BridgeHalted);
let sender = ensure_signed(origin)?;
// 支付桥接费用
T::Currency::transfer(&sender, &Self::account_id(), T::BridgeFee::get(), ExistenceRequirement::KeepAlive)?;
// 检查消息长度
ensure!(
message.len() <= T::MaxMessageLength::get() as usize,
Error::<T>::MessageTooLong
);
// 获取下一个消息ID
let message_id = Self::next_message_id();
// 存储消息
Messages::insert((target_chain, message_id), message.clone());
// 递增消息ID
<NextMessageId>::put(message_id.checked_add(1).ok_or(Error::<T>::Overflow)?);
// 发出事件
Self::deposit_event(Event::MessageSent(sender, target_chain, message_id, message));
Ok(())
}
// 发送跨链资产
#[weight = 60_000]
pub fn send_assets(
origin,
target_chain: T::Hash,
recipient: T::AccountId,
amount: BalanceOf<T>,
) -> DispatchResult {
// 检查运行模式
ensure!(Self::operating_mode() == OperatingMode::Normal, Error::<T>::BridgeHalted);
let sender = ensure_signed(origin)?;
// 支付桥接费用
T::Currency::transfer(&sender, &Self::account_id(), T::BridgeFee::get(), ExistenceRequirement::KeepAlive)?;
// 转账资产
T::Currency::transfer(&sender, &Self::account_id(), amount, ExistenceRequirement::KeepAlive)?;
// 存储资产记录
Assets::insert((target_chain, recipient), amount);
// 发出事件
Self::deposit_event(Event::AssetsSent(sender, target_chain, recipient, amount));
Ok(())
}
// 接收跨链消息
#[weight = 40_000]
pub fn receive_message(
origin,
source_chain: T::Hash,
message_id: u64,
message: Vec<u8>,
storage_proof: Vec<u8>,
) -> DispatchResult {
// 检查运行模式
ensure!(Self::operating_mode() == OperatingMode::Normal, Error::<T>::BridgeHalted);
let _sender = ensure_signed(origin)?;
// 验证存储证明 (实际实现需要更复杂的验证)
let is_valid = verify_storage_proof(&storage_proof);
ensure!(is_valid, Error::<T>::InvalidStorageProof);
// 检查消息是否已存在
ensure!(!Messages::contains_key((source_chain, message_id)), Error::<T>::AlreadyReceived);
// 存储消息
Messages::insert((source_chain, message_id), message.clone());
// 发出事件
Self::deposit_event(Event::MessageReceived(source_chain, message_id, message));
Ok(())
}
// 接收跨链资产
#[weight = 50_000]
pub fn receive_assets(
origin,
source_chain: T::Hash,
recipient: T::AccountId,
amount: BalanceOf<T>,
storage_proof: Vec<u8>,
) -> DispatchResult {
// 检查运行模式
ensure!(Self::operating_mode() == OperatingMode::Normal, Error::<T>::BridgeHalted);
let _sender = ensure_signed(origin)?;
// 验证存储证明 (实际实现需要更复杂的验证)
let is_valid = verify_storage_proof(&storage_proof);
ensure!(is_valid, Error::<T>::InvalidStorageProof);
// 检查资产是否已存在
ensure!(!Assets::contains_key((source_chain, recipient.clone())), Error::<T>::AlreadyReceived);
// 转账资产给接收者
T::Currency::transfer(&Self::account_id(), &recipient, amount, ExistenceRequirement::AllowDeath)?;
// 发出事件
Self::deposit_event(Event::AssetsReceived(source_chain, recipient, amount));
Ok(())
}
}
}
// 5. 错误定义
pub enum Error<T> {
/// 无效的存储证明
InvalidStorageProof,
/// 消息过长
MessageTooLong,
/// 头或消息已接收
AlreadyReceived,
/// 没有设置所有者
NoOwner,
/// 不是所有者
NotOwner,
/// 不是根账户
NotRoot,
/// 桥接已暂停
BridgeHalted,
/// 算术溢出
Overflow,
}
// 6. 事件定义
pub enum Event<T> where
<T as frame_system::Trait>::AccountId,
<T as frame_system::Trait>::Hash,
BalanceOf<T>,
{
/// 所有者变更事件
OwnerChanged(T::AccountId, T::AccountId),
/// 运行模式变更事件
OperatingModeChanged(OperatingMode),
/// 头接收事件
HeaderReceived(T::Hash, T::BlockNumber),
/// 消息发送事件
MessageSent(T::AccountId, T::Hash, u64, Vec<u8>),
/// 资产发送事件
AssetsSent(T::AccountId, T::Hash, T::AccountId, BalanceOf<T>),
/// 消息接收事件
MessageReceived(T::Hash, u64, Vec<u8>),
/// 资产接收事件
AssetsReceived(T::Hash, T::AccountId, BalanceOf<T>),
}
// 7. 存储证明验证函数 (简化)
fn verify_storage_proof(proof: &[u8]) -> bool {
// 实际实现需要验证来自relay chain的证明
!proof.is_empty()
}
// 8. 模块账户ID
impl<T: Trait> Module<T> {
pub fn account_id() -> T::AccountId {
T::PalletId::get().into_account()
}
}
// 9. 测试模块
#[cfg(test)]
mod tests {
use super::*;
use frame_support::{
assert_err, assert_ok,
traits::{OnInitialize, OnFinalize},
};
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
DispatchError,
};
type Test = frame_system::Test;
type TestParachainBridge = Module<Test>;
frame_support::construct_runtime!(
pub enum Test where
Block = Test,
NodeBlock = Test,
UncheckedExtrinsic = Test,
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
ParachainBridge: crate::{Pallet, Call, Storage, Event<T>},
}
);
impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type Origin = Origin;
type Call = Call;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = ();
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
}
impl pallet_balances::Config for Test {
type MaxLocks = ();
type Balance = u64;
type DustRemoval = ();
type Event = Event;
type ExistentialDeposit = ();
type AccountStore = System;
type WeightInfo = ();
type MaxReserves = ();
type ReserveIdentifier = ();
}
impl Trait for Test {
type Event = Event;
type Currency = Balances;
type MaxMessageLength = frame_support::traits::ConstU32<1024>;
type BridgeFee = frame_support::traits::ConstU64<10>;
}
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default()
.build_storage::<Test>()
.unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![(1, 1000), (2, 1000), (3, 1000)],
}
.assimilate_storage(&mut t)
.unwrap();
crate::GenesisConfig::<Test> {
owner: Some(1),
operating_mode: OperatingMode::Normal,
}
.assimilate_storage(&mut t)
.unwrap();
t.into()
}
#[test]
fn test_set_owner() {
new_test_ext().execute_with(|| {
// 初始所有者是1
assert_eq!(TestParachainBridge::owner(), Some(1));
// 非所有者不能设置所有者
assert_err!(
TestParachainBridge::set_owner(Origin::signed(2), 2),
Error::<Test>::NotOwner
);
// 所有者可以设置新所有者
assert_ok!(TestParachainBridge::set_owner(Origin::signed(1), 2));
assert_eq!(TestParachainBridge::owner(), Some(2));
// 旧所有者不能再设置所有者
assert_err!(
TestParachainBridge::set_owner(Origin::signed(1), 1),
Error::<Test>::NotOwner
);
});
}
#[test]
fn test_set_operating_mode() {
new_test_ext().execute_with(|| {
// 初始模式是Normal
assert_eq!(TestParachainBridge::operating_mode(), OperatingMode::Normal);
// 非所有者不能设置模式
assert_err!(
TestParachainBridge::set_operating_mode(Origin::signed(2), OperatingMode::Halted),
Error::<Test>::NotOwner
);
// 所有者可以设置模式
assert_ok!(TestParachainBridge::set_operating_mode(Origin::signed(1), OperatingMode::Halted));
assert_eq!(TestParachainBridge::operating_mode(), OperatingMode::Halted);
// 根账户也可以设置模式
assert_ok!(TestParachainBridge::set_operating_mode(Origin::root(), OperatingMode::Normal));
assert_eq!(TestParachainBridge::operating_mode(), OperatingMode::Normal);
});
}
#[test]
fn test_submit_parachain_header() {
new_test_ext().execute_with(|| {
let header_hash = H256::random();
// 正常提交
assert_ok!(TestParachainBridge::submit_parachain_header(
Origin::signed(1),
header_hash,
vec![1, 2, 3],
1
));
// 重复提交应该失败
assert_err!(
TestParachainBridge::submit_parachain_header(
Origin::signed(1),
header_hash,
vec![1, 2, 3],
1
),
Error::<Test>::AlreadyReceived
);
// 无效存储证明应该失败
assert_err!(
TestParachainBridge::submit_parachain_header(
Origin::signed(1),
H256::random(),
vec![],
1
),
Error::<Test>::InvalidStorageProof
);
// 桥接暂停时提交应该失败
assert_ok!(TestParachainBridge::set_operating_mode(Origin::signed(1), OperatingMode::Halted));
assert_err!(
TestParachainBridge::submit_parachain_header(
Origin::signed(1),
H256::random(),
vec![1, 2, 3],
1
),
Error::<Test>::BridgeHalted
);
});
}
#[test]
fn test_send_and_receive_message() {
new_test_ext().execute_with(|| {
let target_chain = H256::random();
let message = b"Hello, world!".to_vec();
// 发送消息
assert_ok!(TestParachainBridge::send_message(
Origin::signed(1),
target_chain,
message.clone()
));
// 检查余额变化 (支付了桥接费用)
assert_eq!(Balances::free_balance(1), 1000 - 10);
// 检查消息ID递增
assert_eq!(TestParachainBridge::next_message_id(), 1);
// 接收消息
assert_ok!(TestParachainBridge::receive_message(
Origin::signed(1),
target_chain,
0,
message.clone(),
vec![1, 2, 3]
));
// 检查消息存储
assert_eq!(TestParachainBridge::messages((target_chain, 0)), message);
});
}
#[test]
fn test_send_and_receive_assets() {
new_test_ext().execute_with(|| {
let source_chain = H256::random();
let recipient = 2;
let amount = 100;
// 发送资产
assert_ok!(TestParachainBridge::send_assets(
Origin::signed(1),
source_chain,
recipient,
amount
));
// 检查余额变化 (支付了桥接费用和资产)
assert_eq!(Balances::free_balance(1), 1000 - 10 - amount);
assert_eq!(Balances::free_balance(TestParachainBridge::account_id()), 10 + amount);
// 接收资产
assert_ok!(TestParachainBridge::receive_assets(
Origin::signed(1),
source_chain,
recipient,
amount,
vec![1, 2, 3]
));
// 检查余额变化 (资产已转账给接收者)
assert_eq!(Balances::free_balance(recipient), 1000 + amount);
assert_eq!(Balances::free_balance(TestParachainBridge::account_id()), 10);
});
}
}
这个完整示例展示了如何使用pallet-bridge-parachains实现以下功能:
- 平行链头的验证和存储
- 跨链消息的发送和接收
- 跨链资产的转移
- 桥接管理和控制
- 错误处理和测试验证
实际部署时,您还需要:
- 实现更复杂的存储证明验证逻辑
- 部署中继服务监控链上事件并提交交易
- 配置适当的费用和限制参数
- 进行全面的安全审计
Rust跨链桥接库pallet-bridge-parachains的使用:实现波卡生态平行链间资产与消息的安全跨链传输
介绍
pallet-bridge-parachains
是Substrate框架中的一个关键模块,专门设计用于在波卡(Polkadot)生态系统中实现平行链之间的安全跨链通信。这个库提供了一套完整的工具和协议,使开发者能够构建可靠的跨链桥,实现资产和消息在不同平行链之间的传输。
该模块的核心特点包括:
- 安全的消息验证机制
- 高效的跨链通信协议
- 与波卡中继链的深度集成
- 支持资产和任意数据的跨链传输
使用方法
1. 添加依赖
首先需要在项目的Cargo.toml
中添加依赖:
[dependencies]
pallet-bridge-parachains = { git = "https://github.com/paritytech/parity-bridges-common.git", branch = "master" }
2. 运行时集成
在你的Substrate运行时中集成该pallet:
impl pallet_bridge_parachains::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type Bridges = (BridgeA, BridgeB); // 你定义的桥接实例
type ParaStoredHeaderData = bp_polkadot_core::StoredHeaderData;
}
3. 定义桥接实例
pub struct BridgeA;
impl pallet_bridge_parachains::Instance for BridgeA {
const PARACHAIN_ID: u32 = 1000; // 目标平行链ID
const BRIDGE_ID: bp_runtime::BridgeInstanceId = b"brdg_a";
}
4. 发送跨链消息
// 在你的业务逻辑中发送跨链消息
let message = vec![1, 2, 3, 4]; // 你的消息内容
pallet_bridge-parachains::Pallet::<Runtime, BridgeA>::send_message(
RuntimeOrigin::signed(sender),
message,
);
5. 接收跨链消息
// 在你的runtime中实现消息接收处理
#[pallet::hooks]
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
// 处理接收到的消息
if let Some(message) = pallet_bridge_parachains::Pallet::<T, I>::receive_message() {
// 处理消息逻辑
}
Weight::zero()
}
}
完整示例
下面是一个完整的平行链间资产转移示例:
// 定义桥接实例
pub struct AssetBridge;
impl pallet_bridge_parachains::Instance for AssetBridge {
const PARACHAIN_ID: u32 = 2000; // 目标资产平行链ID
const BRIDGE_ID: bp_runtime::BridgeInstanceId = b"ast_br";
}
// 发送资产转移消息
fn transfer_asset_to_parachain(
origin: OriginFor<T>,
recipient: AccountId,
amount: Balance,
) -> DispatchResult {
let sender = ensure_signed(origin)?;
// 1. 本地扣减资产
<Balances as Currency<_>>::withdraw(&sender, amount, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive)?;
// 2. 构造跨链消息
let message = Encode::encode(&(recipient, amount));
// 3. 发送跨链消息
pallet_bridge_parachains::Pallet::<Runtime, AssetBridge>::send_message(
RuntimeOrigin::signed(sender),
message,
)?;
Ok(())
}
// 接收并处理资产转移消息
fn on_message_received(message: Vec<u8>) {
if let Ok((recipient, amount)) = <(AccountId, Balance)>::decode(&mut &message[..]) {
// 给接收方铸造资产
<Balances as Currency<_>>::deposit_creating(&recipient, amount);
}
}
安全注意事项
- 始终验证接收消息的来源和完整性
- 实现适当的费用机制防止滥用
- 考虑消息排序和重复问题
- 为跨链操作设置合理的权重和限制
- 定期监控桥接状态和安全性
通过pallet-bridge-parachains
,开发者可以构建高效、安全的跨链应用,充分利用波卡生态系统的互操作性优势。