Rust跨链消息传递库xcm-runtime-apis的使用:实现Substrate区块链XCM(Cross-Consensus Messaging)运行时API集成

Rust跨链消息传递库xcm-runtime-apis的使用:实现Substrate区块链XCM(Cross-Consensus Messaging)运行时API集成

安装

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

cargo add xcm-runtime-apis

或者在Cargo.toml中添加以下行:

xcm-runtime-apis = "0.9.0"

使用示例

下面是一个完整的示例,展示如何使用xcm-runtime-apis库实现Substrate区块链的XCM运行时API集成:

// 引入必要的库和模块
use frame_support::{
    traits::{Get, OriginTrait},
    weights::Weight,
};
use xcm::latest::prelude::*;
use xcm_runtime_apis::{
    self as api,
    xcm::{ExecuteXcm, SendXcm},
};

// 实现XCM执行API
pub struct XcmExecuteApi;

impl ExecuteXcm for XcmExecuteApi {
    type Call = super::RuntimeCall;

    fn execute_xcm(
        origin: <Self::Origin as OriginTrait>::PalletsOrigin,
        message: Xcm<()>,
        max_weight: Weight,
    ) -> api::xcm::ExecuteXcmResult {
        // 在这里实现XCM消息的执行逻辑
        // 例如:验证origin、解析message、执行跨链操作等
        Ok(())
    }

    fn execute_xcm_in_credit(
        origin: <Self::Origin as OriginTrait>::PalletsOrigin,
        message: Xcm<()>,
        max_weight: Weight,
        weight_credit: Weight,
    ) -> api::xcm::ExecuteXcmResult {
        // 带权重信用的执行版本
        Ok(())
    }
}

// 实现XCM发送API
pub struct XcmSendApi;

impl SendXcm for XcmSendApi {
    fn send_xcm(
        destination: impl Into<MultiLocation>,
        message: Xcm<()>,
    ) -> api::xcm::SendXcmResult {
        // 在这里实现XCM消息的发送逻辑
        // 例如:验证destination、准备消息、发送到目标链等
        Ok(())
    }
}

// 在Runtime中集成XCM API
impl api::xcm::XcmApi for Runtime {
    type ExecuteXcm = XcmExecuteApi;
    type SendXcm = XcmSendApi;
}

// 示例Runtime配置
pub struct Runtime;

impl frame_system::Config for Runtime {
    type RuntimeCall = RuntimeCall;
    type RuntimeEvent = RuntimeEvent;
    type RuntimeOrigin = RuntimeOrigin;
    // 其他必要的关联类型
}

// 定义RuntimeCall和RuntimeEvent等类型
pub enum RuntimeCall {}
pub enum RuntimeEvent {}
pub struct RuntimeOrigin;

API说明

xcm-runtime-apis提供了以下关键API:

  1. ExecuteXcm - 处理接收到的XCM消息的执行

    • execute_xcm() - 执行XCM消息
    • execute_xcm_in_credit() - 带权重信用的执行版本
  2. SendXcm - 处理XCM消息的发送

    • send_xcm() - 发送XCM消息到目标链
  3. XcmApi - 运行时API的主要接口,组合了执行和发送功能

实现注意事项

  1. 需要为你的Runtime实现frame_system::Config和其他必要的trait
  2. ExecuteXcmSendXcm实现中处理错误情况和边界条件
  3. 考虑权重计算和资源限制
  4. 确保消息验证和安全性

完整示例代码

// 引入必要的库和模块
use frame_support::{
    traits::{Get, OriginTrait},
    weights::Weight,
};
use sp_std::marker::PhantomData;
use xcm::latest::prelude::*;
use xcm_runtime_apis::{
    self as api,
    xcm::{ExecuteXcm, SendXcm},
};

// 定义Runtime类型
pub struct Runtime;

// 实现frame_system::Config
impl frame_system::Config for Runtime {
    type RuntimeCall = RuntimeCall;
    type RuntimeEvent = RuntimeEvent;
    type RuntimeOrigin = RuntimeOrigin;
    type Block = Block;
    type AccountId = u64;
    type BlockHashCount = frame_support::traits::ConstU64<250>;
    type DbWeight = ();
    type BaseCallFilter = frame_support::traits::Everything;
    type Version = ();
    type PalletInfo = PalletInfo;
    type OnNewAccount = ();
    type OnKilledAccount = ();
    type SystemWeightInfo = ();
    type SS58Prefix = ();
    type OnSetCode = ();
    type MaxConsumers = frame_support::traits::ConstU32<16>;
}

// 定义RuntimeCall类型
pub enum RuntimeCall {
    System(SystemCall),
    Xcm(XcmCall),
}

// 定义SystemCall
pub enum SystemCall {
    remark { remark: Vec<u8> },
}

// 定义XcmCall
pub enum XcmCall {
    send { dest: MultiLocation, message: Xcm<()> },
}

// 定义RuntimeEvent类型
pub enum RuntimeEvent {
    System(SystemEvent),
    Xcm(XcmEvent),
}

// 定义SystemEvent
pub enum SystemEvent {
    Remarked { who: u64, hash: [u8; 32] },
}

// 定义XcmEvent
pub enum XcmEvent {
    Sent { message_id: [u8; 32] },
}

// 定义RuntimeOrigin类型
pub struct RuntimeOrigin;

// 实现OriginTrait for RuntimeOrigin
impl OriginTrait for RuntimeOrigin {
    type PalletsOrigin = PalletsOrigin;

    fn add_filter(&mut self, _filter: impl Fn(&Self::PalletsOrigin) -> bool + 'static) {
        unimplemented!()
    }

    fn reset_filter(&mut self) {
        unimplemented!()
    }
}

// 定义PalletsOrigin类型
pub enum PalletsOrigin {
    System,
    Xcm,
}

// 实现XCM执行API
pub struct XcmExecuteApi;

impl ExecuteXcm for XcmExecuteApi {
    type Call = RuntimeCall;

    fn execute_xcm(
        origin: <Self::Origin as OriginTrait>::PalletsOrigin,
        message: Xcm<()>,
        max_weight: Weight,
    ) -> api::xcm::ExecuteXcmResult {
        log::info!("Executing XCM message: {:?}", message);
        // 这里应该添加实际的执行逻辑
        Ok(())
    }

    fn execute_xcm_in_credit(
        origin: <Self::Origin as OriginTrait>::PalletsOrigin,
        message: Xcm<()>,
        max_weight: Weight,
        weight_credit: Weight,
    ) -> api::xcm::ExecuteXcmResult {
        log::info!("Executing XCM message with weight credit: {:?}", message);
        // 这里应该添加实际的执行逻辑
        Ok(())
    }
}

// 实现XCM发送API
pub struct XcmSendApi;

impl SendXcm for XcmSendApi {
    fn send_xcm(
        destination: impl Into<MultiLocation>,
        message: Xcm<()>,
    ) -> api::xcm::SendXcmResult {
        let dest = destination.into();
        log::info!("Sending XCM message to {:?}: {:?}", dest, message);
        // 这里应该添加实际的发送逻辑
        Ok(())
    }
}

// 在Runtime中集成XCM API
impl api::xcm::XcmApi for Runtime {
    type ExecuteXcm = XcmExecuteApi;
    type SendXcm = XcmSendApi;
}

// 其他必要的类型定义
pub struct Block;
pub struct PalletInfo;

这个完整示例扩展了原始示例,添加了更多类型定义和实现细节,包括:

  • 完整的Runtime配置
  • RuntimeCall和RuntimeEvent的具体实现
  • 日志记录
  • 更多必要的关联类型实现
  • 更完整的类型系统定义

1 回复

Rust跨链消息传递库xcm-runtime-apis使用指南

完整示例Demo

以下是一个完整的Substrate链使用xcm-runtime-apis实现跨链通信的示例:

// runtime/src/lib.rs

// 1. 引入必要依赖
use frame_support::{construct_runtime, parameter_types};
use xcm::latest::prelude::*;
use xcm_builder::{
    AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
    AllowTopLevelPaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, IsConcrete,
    LocationInverter, NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
    SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
    SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
};
use xcm_executor::{traits::*, Config as XcmConfig, XcmExecutor};

// 2. 配置XCM参数
parameter_types! {
    pub const RelayLocation: MultiLocation = MultiLocation::parent();
    pub const RelayNetwork: NetworkId = NetworkId::Any;
    pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
    pub Ancestry: MultiLocation = Parachain(1000).into();
    pub CheckingAccount: AccountId = XcmPallet::check_account();
}

// 3. 定义XCM配置类型
pub type LocationToAccountId = (
    ParentIsPreset<AccountId>,
    SiblingParachainConvertsVia<Sibling, AccountId>,
    AccountId32Aliases<RelayNetwork, AccountId>,
);

pub type XcmRouter = (
    // 使用UMP向下游传递消息到中继链
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, (), ()>,
);

impl pallet_xcm::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
    type XcmRouter = XcmRouter;
    type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
    type XcmExecuteFilter = Everything;
    type XcmExecutor = XcmExecutor<XcmConfig>;
    type XcmTeleportFilter = Nothing;
    type XcmReserveTransferFilter = Everything;
    type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
    type UniversalLocation = UniversalLocation;
    type RuntimeOrigin = RuntimeOrigin;
    type RuntimeCall = RuntimeCall;
    
    const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
    type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
}

// 4. 实现XcmRuntimeApi
impl xcm_runtime_apis::XcmRuntimeApi<Block> for Runtime {
    fn send_xcm(
        origin: MultiLocation,
        dest: MultiLocation,
        message: VersionedXcm,
    ) -> Result<XcmHash, SendError> {
        // 转换消息为最新版本
        let message = match message {
            VersionedXcm::V3(msg) => msg,
            _ => return Err(SendError::Unroutable),
        };
        
        // 实际发送逻辑
        XcmPallet::send(origin, dest, message)
    }

    fn execute_xcm(
        origin: MultiLocation,
        message: VersionedXcm,
    ) -> Outcome {
        // 转换消息为最新版本
        let message = match message {
            VersionedXcm::V3(msg) => msg,
            _ => return Outcome::Error(XcmError::Unimplemented),
        };
        
        // 实际执行逻辑
        XcmExecutor::<XcmConfig>::execute_xcm(origin, message)
    }
}

// 5. 构造runtime
construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        // 其他pallet...
        XcmPallet: pallet_xcm,
    }
);

// 6. 使用示例 - 发送跨链资产转移
pub fn transfer_assets_to_parachain(
    dest_para_id: u32,
    beneficiary: AccountId,
    amount: u128,
) -> Result<(), &'static str> {
    // 构建目标位置 (平行链2000)
    let dest = MultiLocation::new(
        1,
        X1(Parachain(dest_para_id))
    );
    
    // 构建受益人位置
    let beneficiary_location = MultiLocation::new(
        0,
        X1(AccountId32 {
            network: None,
            id: beneficiary.into(),
        })
    );
    
    // 构建XCM消息
    let message = Xcm(vec![
        WithdrawAsset((Here, amount).into()),
        BuyExecution {
            fees: (Here, amount / 10).into(), // 支付10%作为费用
            weight_limit: Limited(Weight::from_parts(1_000_000, 1024)),
        },
        DepositAsset {
            assets: All.into(),
            beneficiary: beneficiary_location,
        },
    ]);
    
    // 发送XCM消息
    Runtime::send_xcm(Parent.into(), dest, VersionedXcm::from(message))
        .map_err(|_| "Failed to send XCM message")?;
    
    Ok(())
}

// 7. 使用示例 - 接收并处理XCM消息
pub fn handle_incoming_xcm(
    origin: MultiLocation,
    message: VersionedXcm,
) -> Outcome {
    // 执行XCM消息
    let result = Runtime::execute_xcm(origin, message);
    
    // 处理执行结果
    match result {
        Outcome::Complete(weight) => {
            log::info!("XCM executed successfully, weight used: {}", weight);
            Outcome::Complete(weight)
        },
        Outcome::Incomplete(weight, error) => {
            log::warn!("XCM executed partially: {:?}, weight used: {}", error, weight);
            Outcome::Incomplete(weight, error)
        },
        Outcome::Error(error) => {
            log::error!("XCM execution failed: {:?}", error);
            Outcome::Error(error)
        },
    }
}

关键点说明

  1. XCM配置:定义了如何将位置转换为账户ID、资产处理等核心逻辑
  2. XcmRuntimeApi实现:提供了标准化的XCM消息发送和执行接口
  3. 资产转移示例:展示了如何构建完整的跨链资产转移流程
  4. 消息处理:演示了如何接收和处理传入的XCM消息

实际应用建议

  1. 错误处理:实际应用中需要更完善的错误处理和日志记录
  2. 费用估算:应根据目标链实际情况计算适当的手续费
  3. 版本适配:生产环境需要处理更多XCM版本兼容性问题
  4. 安全审计:关键XCM逻辑应进行充分的安全审计

这个完整示例展示了如何在Substrate链上集成xcm-runtime-apis实现跨链功能,包括发送和处理XCM消息的核心流程。实际使用时需要根据具体链的配置进行调整。

回到顶部