在底层工作?必须了解Runtime APIs。

852 阅读4分钟

各位读者大家好!在这篇博客中,我们将看到什么是Runtime API,以及我们如何创建和使用它。

每个底层节点都包含一个运行时。运行时包含链的业务逻辑。它定义了哪些交易是有效的,哪些是无效的,并决定了链的状态如何响应交易而变化。为了使用运行时的升级,运行时被编译为Wasm。除了运行时以外的一切都被称为 "外部节点",外部节点不编译到Wasm,它只编译到本地。

外层节点负责处理对等发现、交易池、区块和交易八卦、共识,以及回答来自外部世界的RPC调用。在执行这些任务时,外部节点有时需要查询运行时的信息,或向运行时提供信息。Runtime API促进了外部节点和运行时之间的这种通信。在这篇博客中,我们将编写我们自己的最小运行时API。

Runtime API WorkingRuntime API Working

我们的例子

在这个例子中,我们将编写一个名为sum-storage 的托盘,其中有两个存储项,都是u32s。


#![allow(unused)]
fn main() {
decl_storage! {
	trait Store for Module<T: Config> as TemplateModule {
		Thing1 get(fn thing1): Option<u32>;
		Thing2 get(fn thing2): Option<u32>;
	}
}
}

Substrate已经提供了一个用于查询存储值的运行时API,这就是为什么我们可以很容易地从前端查询我们的两个存储值。我们的运行时API将为外部节点提供一种方法来查询这个和的运行时。在我们定义实际的运行时API之前,让我们在托盘中写一个公共辅助函数来进行求和。


#![allow(unused)]
fn main() {
impl<T: Config> Module<T> {
	pub fn get_sum() -> u32 {
		Thing1::get() + Thing2::get()
	}
}
}

到目前为止,我们所做的一切都不是针对运行时API的。在接下来的章节中,我们将在运行时API的实现中使用这个辅助函数。

定义API

在你的运行时中添加运行时API的第一步是使用Rust trait定义它的接口。这是在sum-storage/runtime-api/src/lib.rs 文件中完成的。这个文件可以放在任何你喜欢的地方,但因为它定义了一个与特定托盘密切相关的API,所以将API定义放在托盘的目录中是有意义的。

定义API的代码非常简单,看起来几乎和任何旧的Rust特性一样。额外的一点是,它必须放在decl_runtime_apis! 这个宏里。这个宏允许外部节点在特定的块上查询运行时API。虽然这个运行时API只提供了一个函数,但你可以根据自己的喜好来写。


#![allow(unused)]
fn main() {
sp_api::decl_runtime_apis! {
	pub trait SumStorageApi {
		fn get_sum() -> u32;
	}
}
}

实现API

随着我们的托盘的编写和运行时API的定义,我们现在可以为我们的运行时实现API。这发生在主运行时聚合文件中。在我们的例子中,我们已经在runtimes/api-runtime/src/lib.rs 中提供了api-runtime

和定义API一样,实现一个运行时API看起来和实现任何旧的Rust特性相似,但例外的是,实现必须在impl_runtime_apis! 这个宏中进行。每个运行时都必须使用iml_runtime_apis! ,因为Core API是必需的。我们将为我们自己的API添加一个实现,与这个宏中的其他API一起。我们的实现很简单,因为它只是调用我们之前写的托盘的辅助函数。


#![allow(unused)]
fn main() {
impl_runtime_apis! {
  // --snip--

  impl sum_storage_rpc_runtime_api::SumStorageApi<Block> for Runtime {
		fn get_sum() -> u32 {
			SumStorage::get_sum()
		}
	}
}
}

你可能想知道Block 类型参数,它在这里出现,但不在我们的定义中。所有的运行时API都有这个类型参数,以方便在任意的区块查询运行时。阅读更多关于这个问题的文档 impl_runtime_apis!.

调用运行时API

我们现在已经成功地在我们的运行时中添加了一个运行时API。外部节点现在可以调用这个API来查询运行时的两个存储值之和。给出一个对"客户端 "的引用,我们可以像这样进行调用。


#![allow(unused)]
fn main() {
let sum_at_block_fifty = client.runtime_api().get_sum(&50);
}

这篇博客是关于定义和实现一个自定义的运行时API。请保持联系,以探索这种令人兴奋的话题!!