Rust跨链交互库cumulus-relay-chain-interface的使用,实现Polkadot平行链与中继链高效通信

Rust跨链交互库cumulus-relay-chain-interface的使用,实现Polkadot平行链与中继链高效通信

安装

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

cargo add cumulus-relay-chain-interface

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

cumulus-relay-chain-interface = "0.25.0"

示例代码

以下是使用cumulus-relay-chain-interface实现Polkadot平行链与中继链通信的完整示例:

use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult};
use polkadot_service::client::Client;
use sc_service::Configuration;
use sp_runtime::traits::Block as BlockT;

// 创建中继链接口
async fn create_relay_chain_interface() -> RelayChainResult<impl RelayChainInterface> {
    // 配置中继链连接参数
    let config = Configuration {
        chain_spec: Box::new(polkadot_service::chain_spec::polkadot_config()),
        // 其他配置参数...
        ..Default::default()
    };
    
    // 创建客户端
    let client = Client::new(config).await?;
    
    // 创建中继链接口
    RelayChainInterface::new(client)
}

// 获取中继链最新区块高度
async fn get_relay_chain_block_number(
    relay_chain_interface: &impl RelayChainInterface,
) -> RelayChainResult<u32> {
    relay_chain_interface.best_block_number().await
}

// 提交平行链区块到中继链
async fn submit_parachain_block_to_relay(
    relay_chain_interface: &impl RelayChainInterface,
    parachain_block: Vec<u8>,
) -> RelayChainResult<()> {
    relay_chain_interface
        .submit_block_to_relay_chain(parachain_block)
        .await
}

// 主函数示例
#[tokio::main]
async fn main() -> RelayChainResult<()> {
    // 创建中继链接口
    let relay_chain_interface = create_relay_chain_interface().await?;
    
    // 获取中继链最新区块高度
    let block_number = get_relay_chain_block_number(&relay_chain_interface).await?;
    println!("Relay chain best block number: {}", block_number);
    
    // 模拟平行链区块数据
    let parachain_block = vec![0x1, 0x2, 0x3];
    
    // 提交平行链区块到中继链
    submit_parachain_block_to_relay(&relay_chain_interface, parachain_block).await?;
    
    Ok(())
}

完整示例代码

以下是一个更完整的示例,包含了更多实用功能:

use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult};
use polkadot_service::client::Client;
use sc_service::Configuration;
use sp_runtime::{traits::Block as BlockT, generic::BlockId};

// 创建中继链接口
async fn create_relay_chain_interface() -> RelayChainResult<impl RelayChainInterface> {
    // 配置中继链连接参数
    let config = Configuration {
        chain_spec: Box::new(polkadot_service::chain_spec::polkadot_config()),
        transport: polkadot_service::build_network_transport(),
        ..Default::default()
    };
    
    // 创建客户端
    let client = Client::new(config).await?;
    
    // 创建中继链接口
    RelayChainInterface::new(client)
}

// 获取中继链最新区块头
async fn get_relay_chain_header(
    relay_chain_interface: &impl RelayChainInterface,
) -> RelayChainResult<Option<sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>>> {
    let best_hash = relay_chain_interface.best_block_hash().await?;
    relay_chain_interface.header(BlockId::Hash(best_hash)).await
}

// 监听中继链新块事件
async fn watch_relay_chain_blocks(
    relay_chain_interface: impl RelayChainInterface,
) -> RelayChainResult<()> {
    let mut import_notification_stream = relay_chain_interface.import_notification_stream().await?;
    
    while let Some(notification) = import_notification_stream.next().await {
        println!(
            "New relay chain block: #{} ({})",
            notification.header.number,
            notification.hash
        );
    }
    
    Ok(())
}

// 主函数示例
#[tokio::main]
async fn main() -> RelayChainResult<()> {
    // 创建中继链接口
    let relay_chain_interface = create_relay_chain_interface().await?;
    
    // 获取中继链最新区块信息
    let block_number = get_relay_chain_block_number(&relay_chain_interface).await?;
    println!("Relay chain best block number: {}", block_number);
    
    // 获取最新区块头
    if let Some(header) = get_relay_chain_header(&relay_chain_interface).await? {
        println!("Latest block header: {:?}", header);
    }
    
    // 启动监听线程
    let interface_clone = relay_chain_interface.clone();
    tokio::spawn(async move {
        if let Err(e) = watch_relay_chain_blocks(interface_clone).await {
            eprintln!("Error watching relay chain blocks: {}", e);
        }
    });
    
    // 模拟平行链区块数据
    let parachain_block = vec![0x1, 0x2, 0x3];
    
    // 提交平行链区块到中继链
    submit_parachain_block_to_relay(&relay_chain_interface, parachain_block).await?;
    
    Ok(())
}

主要功能

  1. 创建中继链连接:通过RelayChainInterface::new()建立与中继链的连接
  2. 获取中继链信息:如最新区块高度、区块头等
  3. 监听中继链事件:实时获取新块通知
  4. 提交平行链数据:将平行链区块提交到中继链

注意事项

  • 使用前需要确保正确配置中继链连接参数
  • 所有操作都是异步的,需要使用async/await语法
  • 错误处理通过RelayChainResult类型进行
  • 克隆接口实例可以在多个任务中安全使用

1 回复

以下是根据您提供的内容整理的完整示例demo,首先展示内容中已有的示例,然后提供一个更完整的集成示例:

已提供示例回顾

1. 创建RelayChainInterface实例

use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult};

async fn create_interface() -> RelayChainResult<RelayChainInterface> {
    let relay_chain_interface = RelayChainInterface::new(
        "ws://relay-chain-node:9944", // 中继链节点WS地址
    ).await?;
    
    Ok(relay_chain_interface)
}

2. 查询中继链信息

async fn get_relay_chain_info(interface: &RelayChainInterface) -> RelayChainResult<()> {
    // 获取最新区块哈希
    let best_block_hash = interface.best_block_hash().await?;
    println!("Best block hash: {:?}", best_block_hash);
    
    // 获取最新区块头
    let best_block_header = interface.best_block_header().await?;
    println!("Best block header: {:?}", best_block_header);
    
    // 获取中继链的Runtime版本
    let version = interface.get_runtime_version(None).await?;
    println!("Runtime version: {:?}", version);
    
    Ok(())
}

完整集成示例

use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult};
use sp_core::crypto::AccountId32;
use futures::StreamExt;
use async_std::task;

// 主函数
fn main() -> Result<(), Box<dyn std::error::Error>> {
    task::block_on(async_main())?;
    Ok(())
}

// 异步主逻辑
async fn async_main() -> RelayChainResult<()> {
    // 1. 创建中继链接口
    let interface = create_interface().await?;
    
    // 2. 查询中继链信息
    get_relay_chain_info(&interface).await?;
    
    // 3. 处理中继链区块
    let block_processor = task::spawn(process_relay_blocks(&interface));
    
    // 4. 模拟跨链资产转移
    let recipient = AccountId32::new([0u8; 32]); // 示例账户
    transfer_asset_to_relay(&interface, recipient, 1000).await?;
    
    // 等待区块处理器完成
    block_processor.await?;
    
    Ok(())
}

// 创建中继链接口
async fn create_interface() -> RelayChainResult<RelayChainInterface> {
    let relay_chain_interface = RelayChainInterface::new(
        "ws://relay-chain-node:9944", // 中继链节点WS地址
    ).await?;
    
    Ok(relay_chain_interface)
}

// 查询中继链信息
async fn get_relay_chain_info(interface: &RelayChainInterface) -> RelayChainResult<()> {
    // 获取最新区块哈希
    let best_block_hash = interface.best_block_hash().await?;
    println!("Best block hash: {:?}", best_block_hash);
    
    // 获取最新区块头
    let best_block_header = interface.best_block_header().await?;
    println!("Best block header: {:?}", best_block_header);
    
    // 获取中继链的Runtime版本
    let version = interface.get_runtime_version(None).await?;
    println!("Runtime version: {:?}", version);
    
    Ok(())
}

// 处理中继链区块
async fn process_relay_blocks(interface: &RelayChainInterface) -> RelayChainResult<()> {
    // 订阅新的中继链区块头
    let mut import_stream = interface.import_notification_stream().await?;
    
    while let Some(notification) = import_stream.next().await {
        println!("New relay chain block: {:?}", notification.header.hash());
        
        // 可以在这里处理新的中继链区块
        // 例如验证平行链相关的数据或触发平行链上的操作
    }
    
    Ok(())
}

// 跨链资产转移
async fn transfer_asset_to_relay(
    interface: &RelayChainInterface,
    recipient: AccountId32,
    amount: u128,
) -> RelayChainResult<()> {
    // 构造XCMP消息
    let message = construct_xcmp_message(recipient, amount);
    
    // 发送到中继链
    send_message_to_relay(interface, message).await?;
    
    Ok(())
}

// 构造XCMP消息
fn construct_xcmp_message(recipient: AccountId32, amount: u128) -> Vec<u8> {
    // 这里简化了实际XCMP消息的构造
    // 实际实现需要遵循Polkadot的XCMP协议
    let mut message = Vec::new();
    message.extend_from_slice(&recipient.encode());
    message.extend_from_slice(&amount.encode());
    message
}

// 发送消息到中继链
async fn send_message_to_relay(
    interface: &RelayChainInterface,
    message: Vec<u8>,
) -> RelayChainResult<()> {
    // 创建并发送一个中继链交易
    let tx = interface.create_transaction(message).await?;
    interface.submit_transaction(tx).await?;
    
    Ok(())
}

示例说明

这个完整示例展示了:

  1. 如何初始化中继链接口
  2. 如何查询中继链的基本信息
  3. 如何监听中继链的新区块
  4. 如何构造和发送跨链消息
  5. 如何使用异步任务处理并行操作

注意:

  • 实际使用时需要替换ws://relay-chain-node:9944为真实的中继链节点地址
  • AccountId应该使用真实的接收方账户
  • 资产转移的消息构造需要根据实际XCMP协议实现
回到顶部