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(())
}
主要功能
- 创建中继链连接:通过
RelayChainInterface::new()
建立与中继链的连接 - 获取中继链信息:如最新区块高度、区块头等
- 监听中继链事件:实时获取新块通知
- 提交平行链数据:将平行链区块提交到中继链
注意事项
- 使用前需要确保正确配置中继链连接参数
- 所有操作都是异步的,需要使用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(())
}
示例说明
这个完整示例展示了:
- 如何初始化中继链接口
- 如何查询中继链的基本信息
- 如何监听中继链的新区块
- 如何构造和发送跨链消息
- 如何使用异步任务处理并行操作
注意:
- 实际使用时需要替换
ws://relay-chain-node:9944
为真实的中继链节点地址 - AccountId应该使用真实的接收方账户
- 资产转移的消息构造需要根据实际XCMP协议实现