#polkadot #blockchain #json-rpc #send-request #api #rpc #json

no-std substrate-api-client

支持任何Substrate节点的Json-rpc客户端及其辅助函数

10个不稳定版本 (3个破坏性更新)

0.18.0 2024年7月10日
0.17.0 2024年2月29日
0.11.0 2023年4月18日
0.6.6 2021年7月24日

#1083 in 魔法豆

Download history 16/week @ 2024-05-28 18/week @ 2024-06-04 7/week @ 2024-07-02 198/week @ 2024-07-09 40/week @ 2024-07-16 3/week @ 2024-07-30

每月241次下载

Apache-2.0 和可能 GPL-3.0-only

1MB
8K SLoC

substrate-api-client

substrate-api-client是一个用于通过RPC连接到基于substrate的节点的Rust库。它特别适用于无std环境(这在可信执行环境或嵌入式设备中很常见)。它提供了类似于Polkadot-js的功能,例如简单的外部提交和状态查询。使用RPC客户端,开发者可以轻松地与任何PolkadotKusama链进行交互。有几种不同编程语言的RPC客户端可用。对于Rust,最受欢迎的RPC客户端是subxt。substrate-api-client提供了一种更简单、更少功能的替代方案,专注于为无std环境提供尽可能多的功能。

substrate-api-client 通过 WebSockets 连接到 substrate 的 RPC 接口,允许

  • 组合 extrinsics,异步和同步地发送它们,以及订阅更新(同步)。
  • 支持 no_std 构建。只有 rpc-client 是 std-only。对于 no_std 构建,需要实现自定义 rpc 客户端。
  • 监视事件并在事件上执行代码。
  • 解析并打印节点元数据。
  • 支持异步和同步实现。
  • 支持三种不同的 WebSocket 库(jsonrpseetungstenitews)。有关更多信息和使用限制,请参阅 Cargo.toml

先决条件

为了构建 substrate-api-client 和示例,需要 Rust 和 wasm 目标。对于 Linux

curl https://sh.rustup.rs -sSf | sh
# Install the rust toolchain specified in rust-toolchain.toml
rustup show

Substrate 节点

要执行示例,需要一个正在运行的 substrate 节点。您可以直接从 substrate 下载节点工件:https://github.com/paritytech/substrate 或使用 docker 运行 kitchensink-node

docker run -p 9944:9944 -p 9933:9933 -p 30333:30333 parity/substrate:latest --dev --rpc-external

有关更多信息,请参阅 substrate 存储库。

示例

api-client 提供了几个示例,展示了如何获取节点状态或提交 extrinsic。示例区分了 syncasync 实现。别忘了检查相关 Cargo.toml 中的功能导入。它显示了如何将 api-client 导入为 asyncsync 库。要运行示例,克隆 substrate-api-client 存储库,并直接使用 cargo 命令运行所需的示例

git clone https://github.com/scs/substrate-api-client.git
cd substrate-api-client
# Run an async example:
cargo run -p ac-examples-async --example get_storage
# Run a sync example:
cargo run -p ac-examples-sync --example runtime_update_sync

或从 GitHub Actions 下载已构建的二进制文件,然后运行它们而无需任何先前的构建

# Enter the async or sync example directory and add execution rights to the chosen example.
cd examples-<sync/async>
chmod +x <example>
# And run it.
./<example>

通过在前面添加 RUST_LOG=infoRUST_LOG=debug 来设置输出详细程度。

以下异步示例可以在 异步示例 文件夹中找到

以下同步示例可以在同步示例文件夹中找到。

no_std构建

除了rpc-clients和少量附加功能外,api-client中的几乎所有内容都与no_std兼容。许多有用的功能,如外联和调用创建(参见)、元数据和事件类型(参见node-apiprimitives)在no_std中立即可用。然而,为了直接连接到Substrate节点,需要一个RPC客户端。由于WebSocket连接功能通常与硬件相关,因此一个通用的no_std RPC客户端实现几乎是不可能的。因此,对于大多数用例,需要自行实现的RPC客户端。为了尽可能简化,提供了所有功能的Api接口和提供节点连接的RPC客户端之间的接口保持非常基础。有关更多信息,请参阅以下说明。

导入

要在no_std中导入api-client,请确保默认功能已关闭,并启用disable_target_static_assertions

# In the Cargo.toml import the api-client as following:
substrate-api-client = { git = "https://github.com/scs/substrate-api-client.git", default-features = false, features = ["disable_target_static_assertions"] }

RPC客户端

根据使用情况,RPC客户端需要实现两个特质。您可以选择同步和异步实现。如果您决定使用异步实现,您目前需要使用async-trait库(直到它集成到rust工具链中)。

请求

对于简单的请求(发送一个请求并接收一个回答),需要实现Request特质。

/// Trait to be implemented by the ws-client for sending rpc requests and extrinsic.
pub trait Request {
	/// Sends a RPC request to the substrate node and returns the answer as string.
	(async) fn request<R: DeserializeOwned>(&self, method: &str, params: RpcParams) -> Result<R>;
}

通过使用自定义RPC客户端实现此特质,大多数Api的基本功能就可以使用。目前没有可用的no_std示例。但tungstenite_client提供了一个相对简单的std示例。如果您的no_std环境中提供了WebSocket库,则您的实现可能看起来相似。

订阅

第二个特质Subscribe要复杂一些,它不仅向节点发送订阅请求,还保持监听和相应更新。为此功能需要实现两个特质。首先是Subscribe特质本身

/// Trait to be implemented by the ws-client for subscribing to the substrate node.
pub trait Subscribe {
	type Subscription<Notification>: HandleSubscription<Notification>
	where
		Notification: DeserializeOwned;

	(async) fn subscribe<Notification: DeserializeOwned>(
		&self,
		sub: &str,
		params: RpcParams,
		unsub: &str,
	) -> Result<Self::Subscription<Notification>>;
}

以及由subscribe函数返回的HandleSubscription特质。

/// Trait to use the full functionality of jsonrpseee Subscription type
/// without actually enforcing it.
pub trait HandleSubscription<Notification: DeserializeOwned> {
	/// Returns the next notification from the stream.
	/// This may return `None` if the subscription has been terminated,
	/// which may happen if the channel becomes full or is dropped.
	(async) fn next(&mut self) -> Option<Result<Notification>>;

	/// Unsubscribe and consume the subscription.
	(async) fn unsubscribe(self) -> Result<()>;
}

参考 tungstenite 的 std 示例,HandleSubscription 实现可以在这里查找到 此处。它实现了一个简单的通道接收器,等待 WebSocket 客户端的发送者发送一些内容。Subscribe 实现可以在这里查找到 此处

这是一个更复杂的 RPC 客户端,但功能也更丰富,即 jsonrpsee 客户端。

从旧版本到新版本的示例升级

最近进行了一些 API 变更,以跟上较新的 Substrate 版本并完全支持不同的 Substrate 节点。如何在旧标签之间进行升级的示例项目可以在 Integritee 的 worker 存储库 中找到。

如果您在升级过程中仍然遇到问题,请不要犹豫,创建一个支持问题。

替代方案

Parity 提供了一个具有类似功能的 Rust 客户端:https://github.com/paritytech/subxt

致谢

substrate-api-client 的发展得到了以下机构的资助:

我们还感谢以下团队的贡献:

使用 substrate-api-client 的项目

如果您打算使用或正在使用 substrate-api-client,请将您的项目添加到此处 此处

按字母顺序排列

常见问题解答

  1. Q: 所有内容都编译通过了,但 Substrate 节点不接受我的 extrinsic 或即使 extrinsic 应该正确也会返回错误。

    A: 首先,请确保 api-client 和 Substrate 节点具有匹配的版本。例如,如果节点正在运行 release-polkadot-v1.2.0,请检出并编译 api-client 的匹配分支。我们使用与 Parity 相同的命名方案。请注意:并非所有 Polkadot 版本都针对所有 api-client 版本发布。在 发行说明 中记录了哪些 Polkadot 版本受哪些 api-client 版本支持。找不到您想要的发布匹配?请随时通过问题请求。

  2. Q: 在提交 extrinsic 时,我从节点收到 Bad input data provided to validate_transaction 错误。尽管我已经确保 api-client 和 Polkadot 版本匹配。

    A: 每个 extrinsic 都包含一些特定于节点的数据。例如,提示可能由 Asset 案板提供,或默认由 Balances 案板提供。当前的 api-client 无法访问此信息。因此,这些配置数据必须手动配置。目前,有两个预定义的运行时配置,应与大多数 Substrate 节点匹配。

    确保您使用的是匹配的配置。如果您不使用提供的配置中配置的默认参数,您必须提供自己的配置,该配置实现了 Config 特性

  3. 问:我想通过 api-client 从 substrate 节点查询状态,但我没有得到预期的值,相应的解码失败。这是怎么回事?

    答:当指定您自己的状态查询时,您必须提供您要检索的状态的返回类型。这是因为 api-client 只从节点获取字节,必须能够正确反序列化这些字节。没有知道要解码的类型这是不可能的。例如,这个类型可能是一个简单的 u64,用于检索账户的 Balance。但是小心:如果您正在查看模块代码及其返回类型,不要忘记考虑查询类型。例如,OptionQuery 会自动将返回类型包装到 Option 中(有关更多信息,请参阅 substrate 文档“处理查询返回值”)。或者,您始终可以通过 polkadot.js 进行双重检查。如果您直接从运行时导入值,如在这个 示例 中所示,请记住将其适配到您要查询的节点。

依赖关系

~20–37MB
~644K SLoC