Rust客户端API库sc-client-api的使用,为Substrate区块链客户端提供核心接口与功能扩展

Rust客户端API库sc-client-api的使用,为Substrate区块链客户端提供核心接口与功能扩展

概述

sc-client-api 是 Substrate 区块链客户端的核心接口库,提供了与区块链客户端交互的基本API和功能扩展能力。该库遵循 GPL-3.0-or-later WITH Classpath-exception-2.0 许可证。

安装

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

cargo add sc-client-api

或者在 Cargo.toml 中添加:

sc-client-api = "41.0.0"

基本使用示例

下面是一个使用 sc-client-api 与 Substrate 区块链交互的完整示例:

use sc_client_api::{Backend, BlockBackend, BlockchainEvents};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use std::sync::Arc;

// 定义我们的区块链类型
type Block = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;
type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;

// 客户端结构体
struct Client<B: Backend<Block>> {
    backend: Arc<B>,
}

impl<B: Backend<Block>> Client<B> {
    fn new(backend: Arc<B>) -> Self {
        Client { backend }
    }

    // 获取最新区块头
    fn latest_header(&self) -> Option<<Block as BlockT>::Header> {
        self.backend.blockchain().header(BlockId::Latest).ok()?
    }

    // 订阅新区块
    fn subscribe_blocks(&self) -> sc_client_api::blockchain::BlockchainEvents<Block> {
        self.backend.blockchain().events()
    }
}

// 示例使用
fn main() {
    // 注意:实际使用中需要替换为具体的后端实现
    // let backend = create_actual_backend();
    // let client = Client::new(backend);
    
    // println!("Latest block header: {:?}", client.latest_header());
    
    // let mut subscription = client.subscribe_blocks();
    // while let Some(notification) = subscription.next() {
    //     println!("New block notification: {:?}", notification);
    // }
}

完整示例代码

下面是一个更完整的示例,展示如何使用sc-client-api与Substrate区块链交互:

use sc_client_api::{
    Backend, BlockBackend, BlockchainEvents, 
    ExecutionExtensions, ExecutorProvider, 
    StorageProvider
};
use sp_runtime::{
    generic::BlockId,
    traits::{Block as BlockT, Header as HeaderT},
};
use std::sync::Arc;

// 定义区块链类型
type Block = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;
type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;

// 自定义客户端结构体
struct SubstrateClient<B: Backend<Block>> {
    backend: Arc<B>,
}

impl<B: Backend<Block>> SubstrateClient<B> {
    pub fn new(backend: Arc<B>) -> Self {
        SubstrateClient { backend }
    }

    // 获取指定高度的区块头
    pub fn get_block_header(&self, number: u32) -> Option<<Block as BlockT>::Header> {
        self.backend.blockchain().header(BlockId::Number(number)).ok()?
    }

    // 获取最新区块头
    pub fn latest_header(&self) -> Option<<Block as BlockT>::Header> {
        self.backend.blockchain().header(BlockId::Latest).ok()?
    }

    // 订阅新区块事件
    pub fn subscribe_blocks(&self) -> sc_client_api::blockchain::BlockchainEvents<Block> {
        self.backend.blockchain().events()
    }

    // 获取指定区块的存储数据
    pub fn get_storage(&self, block: BlockId<Block>, key: &[u8]) -> Option<Vec<u8>> {
        self.backend.blockchain().storage(block, key).ok()?
    }
}

// 示例主函数
fn main() {
    // 注意:实际应用中需要替换为真实的后端实现
    // let backend = create_actual_backend();
    // let client = SubstrateClient::new(backend);
    
    // 示例用法
    // if let Some(header) = client.latest_header() {
    //     println!("Latest block header: {:?}", header);
    // }
    
    // 订阅新区块通知
    // let mut subscription = client.subscribe_blocks();
    // while let Some(notification) = subscription.next() {
    //     println!("New block: {:?}", notification.header);
    // }
}

核心功能

sc-client-api 提供了以下主要功能接口:

  1. 区块链数据访问:通过 BlockBackend trait 提供区块、头、存储等数据的访问
  2. 事件订阅:通过 BlockchainEvents trait 提供区块导入、最终化等事件的订阅
  3. 执行环境:提供区块构建和执行的接口
  4. 状态访问:提供区块链状态的访问方法

高级功能扩展

您可以通过实现 sc-client-api 中定义的各种 trait 来扩展客户端功能。例如,自定义存储后端:

use sc_client_api::{Backend, AuxStore};
use sp_runtime::traits::Block as BlockT;

// 自定义后端实现
#[derive(Clone)]
struct CustomBackend<Block: BlockT> {
    // 这里添加自定义存储字段
}

impl<Block: BlockT> Backend<Block> for CustomBackend<Block> {
    // 实现所需的Backend trait方法
}

impl<Block: BlockT> AuxStore for CustomBackend<Block> {
    // 实现辅助存储方法
    fn insert_aux<
        'a,
        'b: 'a,
        'c: 'a,
        I: IntoIterator<Item = &'a(&'c [u8], &'c [u8])>,
        D: IntoIterator<Item = &'a &'b [u8]>,
    >(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
        // 实现具体逻辑
        Ok(())
    }
    
    fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
        // 实现具体逻辑
        Ok(None)
    }
}

注意事项

  1. 该库主要面向需要与 Substrate 区块链客户端深度交互的高级用户
  2. 使用时需要熟悉 Substrate 区块链的基本概念
  3. 实际使用时需要结合具体的后端实现

1 回复

Rust客户端API库sc-client-api的使用指南

概述

sc-client-api是Substrate区块链框架中的一个核心库,为区块链客户端提供了一系列基础接口和功能扩展点。这个库定义了客户端与服务之间的关键交互协议,允许开发者构建自定义区块链客户端或扩展现有客户端功能。

主要功能

  1. 提供区块链客户端核心接口
  2. 定义客户端后端抽象
  3. 支持区块导入和验证
  4. 提供状态查询功能
  5. 支持执行运行时调用
  6. 提供证明生成和验证

基本使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
sc-client-api = { git = "https://github.com/paritytech/substrate.git", branch = "master" }

基本客户端初始化

use sc_client_api::{Backend, BlockchainEvents, ExecutionStrategies};
use sp_runtime::traits::Block as BlockT;

struct MyBackend<Block: BlockT> {
    // 实现你的后端
}

impl<Block: BlockT> Backend<Block> for MyBackend<Block> {
    // 实现必要的trait方法
}

// 创建客户端配置
let client_config = sc_client_api::ClientConfig {
    backend: Box::new(MyBackend::new()),
    execution_strategies: ExecutionStrategies {
        syncing: ExecutionStrategy::NativeElseWasm,
        importing: ExecutionStrategy::NativeElseWasm,
        block_construction: ExecutionStrategy::AlwaysWasm,
        other: ExecutionStrategy::NativeElseWasm,
    },
    // 其他配置...
};

区块导入示例

use sc_client_api::BlockImport;
use sp_runtime::generic::BlockId;
use sp_runtime::traits::Header;

async fn import_block<B, Block>(
    client: &Arc<B>,
    block: Block,
) -> Result<(), sp_blockchain::Error>
where
    B: sc_client_api::BlockBackend<Block>,
    Block: sp_runtime::traits::Block,
{
    let import = sc_client_api::BlockImportParams {
        origin: sp_consensus::BlockOrigin::NetworkBroadcast,
        header: block.header().clone(),
        body: Some(block.extrinsics().to_vec()),
        // 其他导入参数...
    };
    
    client.import_block(import, Default::default()).await
}

状态查询示例

use sc_client_api::StorageProvider;

fn query_storage<B, Block>(
    client: &Arc<B>,
    block: BlockId<Block>,
    key: &[u8],
) -> Result<Option<Vec<u8>>, sp_blockchain::Error>
where
    B: sc_client_api::StorageProvider<Block>,
    Block: sp_runtime::traits::Block,
{
    client.storage(&block, key)
}

高级功能

自定义客户端扩展

use sc_client_api::{ClientInfo, ExecutionExtension};

struct MyExtension;

impl<Block, Client> ExecutionExtension<Block, Client> for MyExtension
where
    Block: sp_runtime::traits::Block,
    Client: sc_client_api::BlockBackend<Block> + Send + Sync + 'static,
{
    // 实现你的扩展逻辑
}

// 注册扩展
let mut extensions = sc_client_api::Extensions::new();
extensions.register(MyExtension);

订阅区块链事件

use futures::StreamExt;
use sc_client_api::BlockchainEvents;

async fn subscribe_to_blocks<B, Block>(
    client: Arc<B>,
) where
    B: sc_client_api::BlockchainEvents<Block>,
    Block: sp_runtime::traits::Block,
{
    let mut import_notification_stream = client.import_notification_stream();
    
    while let Some(notification) = import_notification_stream.next().await {
        println!("New block imported: {:?}", notification.hash);
    }
}

完整示例

下面是一个完整的Substrate客户端示例,演示了如何使用sc-client-api构建一个基本的区块链客户端:

use sc_client_api::{
    Backend, BlockBackend, BlockchainEvents, ExecutionStrategies, 
    BlockImport, StorageProvider, ClientConfig
};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::generic::BlockId;
use std::sync::Arc;

// 定义简单的内存后端
struct InMemoryBackend<Block: BlockT> {
    blocks: std::collections::HashMap<Block::Hash, Block>,
}

impl<Block: BlockT> InMemoryBackend<Block> {
    fn new() -> Self {
        Self {
            blocks: Default::default(),
        }
    }
}

// 实现Backend trait
impl<Block: BlockT> Backend<Block> for InMemoryBackend<Block> {
    // 简化实现 - 实际使用时需要完整实现所有方法
}

// 主客户端结构
struct SubstrateClient<Block: BlockT, Backend> {
    backend: Arc<Backend>,
    // 其他客户端状态
}

impl<Block, Backend> SubstrateClient<Block, Backend>
where
    Block: BlockT,
    Backend: Backend<Block>,
{
    fn new(backend: Backend) -> Self {
        Self {
            backend: Arc::new(backend),
        }
    }
}

// 实现BlockBackend trait
impl<Block, Backend> BlockBackend<Block> for SubstrateClient<Block, Backend>
where
    Block: BlockT,
    Backend: Backend<Block>,
{
    fn block(&self, id: &BlockId<Block>) -> Result<Option<Block>, sp_blockchain::Error> {
        match id {
            BlockId::Hash(hash) => Ok(self.backend.blocks.get(hash).cloned()),
            _ => Ok(None), // 简化实现
        }
    }
}

#[tokio::main]
async fn main() {
    // 初始化内存后端
    let backend = InMemoryBackend::<sp_runtime::generic::Block<_, _>>::new();
    
    // 创建客户端配置
    let config = ClientConfig {
        backend: Box::new(backend),
        execution_strategies: ExecutionStrategies {
            syncing: ExecutionStrategy::NativeElseWasm,
            importing: ExecutionStrategy::NativeElseWasm,
            block_construction: ExecutionStrategy::AlwaysWasm,
            other: ExecutionStrategy::NativeElseWasm,
        },
    };
    
    // 创建客户端实例
    let client = SubstrateClient::new(config.backend);
    
    // 示例:查询不存在的块
    let block = client.block(&BlockId::Number(0));
    println!("Block query result: {:?}", block);
}

最佳实践

  1. 尽量使用提供的trait而不是具体实现,以提高代码的可移植性
  2. 对于资源密集型操作,考虑使用异步执行
  3. 合理处理错误和边缘情况
  4. 注意线程安全,特别是当客户端在多个线程间共享时

注意事项

  1. 该库通常与Substrate的其他组件一起使用,如sc-servicesp-api
  2. API可能会随着Substrate版本的更新而变化
  3. 生产环境使用时需要仔细考虑性能和安全因素

通过sc-client-api,开发者可以构建高度定制化的区块链客户端,同时保持与Substrate生态系统的兼容性。

回到顶部