Rust区块链开发库sc-block-builder的使用:Substrate框架中的区块构建工具与链上功能扩展
Rust区块链开发库sc-block-builder的使用:Substrate框架中的区块构建工具与链上功能扩展
概述
sc-block-builder
是Substrate框架中的一个重要工具库,提供了BlockBuilder
实用工具和对应的运行时API。该库主要作为节点中对运行时API的抽象层,用于以下操作:
- 初始化区块
- 推送交易(extrinsics)
- 完成区块
许可证
GPL-3.0-or-later WITH Classpath-exception-2.0
安装
在项目目录中运行以下Cargo命令:
cargo add sc-block-builder
或者在Cargo.toml中添加以下行:
sc-block-builder = "0.46.0"
使用示例
以下是使用sc-block-builder
构建区块的基本示例:
use sc_block_builder::BlockBuilder;
use sp_api::ProvideRuntimeApi;
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
// 假设我们有以下类型定义
type Block = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;
type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
// 创建区块构建器
fn build_block<B, C>(
client: &C,
at: BlockId<B>,
) -> Result<(), sp_blockchain::Error>
where
B: BlockT,
C: ProvideRuntimeApi<B> + 'static,
C::Api: sp_api::ApiExt<B> + sp_block_builder::BlockBuilder<B>,
{
// 获取父区块哈希
let parent_hash = client
.runtime_api()
.block_hash(&at, 0)?
.expect("Genesis block always exists; qed");
// 创建新的区块构建器
let mut block_builder = BlockBuilder::new(
client,
at,
parent_hash,
Default::default(),
)?;
// 这里可以添加交易(extrinsics)
// block_builder.push(extrinsic)?;
// 完成区块构建
let block = block_builder.build()?;
println!("构建的新区块: {:?}", block);
Ok(())
}
完整示例
下面是一个更完整的示例,展示如何使用sc-block-builder
构建包含交易的区块:
use sc_block_builder::BlockBuilder;
use sp_api::{ProvideRuntimeApi, BlockId};
use sp_runtime::{
generic::Block,
traits::{BlakeTwo256, Block as BlockT, Header as HeaderT},
OpaqueExtrinsic,
};
// 定义区块类型
type BlockNumber = u32;
type Header = sp_runtime::generic::Header<BlockNumber, BlakeTwo256>;
type TestBlock = Block<Header, OpaqueExtrinsic>;
// 模拟客户端
struct TestClient;
impl ProvideRuntimeApi<TestBlock> for TestClient {
type Api = TestRuntimeApi;
fn runtime_api(&self) -> &Self::Api {
&TestRuntimeApi
}
}
// 模拟运行时API
struct TestRuntimeApi;
impl sp_api::ApiExt<TestBlock> for TestRuntimeApi {
fn map_api_result<F: FnOnce() -> Result<R, E>, R, E>(
&self,
f: F
) -> Result<R, E> {
f()
}
fn record_proof(&mut self) {}
fn extract_proof(&mut self) -> Option<sp_state_machine::StorageProof> {
None
}
}
impl sp_block_builder::BlockBuilder<TestBlock> for TestRuntimeApi {}
fn main() -> Result<(), sp_blockchain::Error> {
let client = TestClient;
let at = BlockId::Number(0);
let parent_hash = BlakeTwo256::hash(&[0u8; 32]);
// 创建区块构建器
let mut block_builder = BlockBuilder::new(
&client,
at,
parent_hash,
Default::default(),
)?;
// 模拟添加交易
let extrinsic = OpaqueExtrinsic::from(vec![1, 2, 3]);
block_builder.push(extrinsic)?;
// 构建区块
let built_block = block_builder.build()?;
println!("构建的区块头: {:?}", built_block.block.header);
println!("包含的交易数量: {}", built_block.block.extrinsics.len());
Ok(())
}
功能说明
-
区块初始化:
BlockBuilder::new()
方法用于初始化一个新的区块构建器,需要提供客户端、区块ID、父区块哈希和其他参数。 -
添加交易:使用
push()
方法可以将交易(extrinsics)添加到区块中。 -
构建区块:
build()
方法完成区块构建,返回包含区块头和交易的完整区块。 -
错误处理:所有操作都返回Result类型,可以处理可能出现的错误。
1 回复
以下是关于sc-block-builder
的完整示例代码,基于您提供的内容整理:
use sc_block_builder::{BlockBuilder, BlockBuilderApi};
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
// 自定义区块构建器实现
struct CustomBlockBuilder<Block: BlockT, Client> {
inner: BlockBuilder<Block, Client>,
custom_logs: Vec<String>,
}
impl<Block, Client> BlockBuilderApi<Block> for CustomBlockBuilder<Block, Client>
where
Block: BlockT,
Client: ProvideRuntimeApi<Block> + HeaderBackend<Block> + Send + Sync + 'static,
{
fn push(&mut self, extrinsic: Block::Extrinsic) -> Result<(), sp_blockchain::Error> {
// 记录交易哈希到自定义日志
let tx_hash = format!("{:?}", extrinsic.hash());
self.custom_logs.push(format!("Added extrinsic: {}", tx_hash));
// 调用内部构建器处理交易
self.inner.push(extrinsic)
}
fn build(self) -> Result<sc_block_builder::BuiltBlock<Block>, sp_blockchain::Error> {
// 构建前输出自定义日志
println!("Block construction logs:");
for log in &self.custom_logs {
println!("- {}", log);
}
// 调用内部构建器构建区块
self.inner.build()
}
}
// 使用示例
fn build_custom_block<Block, Client>(
client: &Client,
parent_hash: Block::Hash,
extrinsics: Vec<Block::Extrinsic>,
) -> Result<(), sp_blockchain::Error>
where
Block: BlockT,
Client: ProvideRuntimeApi<Block> + HeaderBackend<Block> + Send + Sync + 'static,
{
// 创建基础区块构建器
let block_builder = BlockBuilder::new(
client,
&BlockId::Hash(parent_hash),
Default::default(), // inherent_data
Default::default(), // inherent_digests
false, // record_proof
Default::default(), // inherent_digests
&sp_state_machine::Backend::new(), // backend
)?;
// 包装成自定义构建器
let mut custom_builder = CustomBlockBuilder {
inner: block_builder,
custom_logs: Vec::new(),
};
// 添加交易
for extrinsic in extrinsics {
custom_builder.push(extrinsic)?;
}
// 构建区块
let built_block = custom_builder.build()?;
println!("Block built: {:?}", built_block.block);
Ok(())
}
这个完整示例展示了:
- 自定义
CustomBlockBuilder
结构体,包装了原始的BlockBuilder
并添加了日志功能 - 实现了
BlockBuilderApi
trait的自定义逻辑 - 完整的区块构建流程:
- 创建基础构建器
- 添加交易(记录自定义日志)
- 构建区块(输出构建日志)
- 类型安全约束确保兼容Substrate框架
使用说明:
- 将此代码放入Substrate节点的适当位置(如service.rs)
- 确保正确传递client、parent_hash和extrinsics参数
- 可以通过扩展
CustomBlockBuilder
添加更多自定义逻辑
这个示例保持了与Substrate框架的兼容性,同时展示了如何通过sc-block-builder
扩展区块构建功能。