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 魔法豆
每月241次下载
1MB
8K SLoC
substrate-api-client
substrate-api-client是一个用于通过RPC连接到基于substrate的节点的Rust库。它特别适用于无std环境(这在可信执行环境或嵌入式设备中很常见)。它提供了类似于Polkadot-js的功能,例如简单的外部提交和状态查询。使用RPC客户端,开发者可以轻松地与任何Polkadot或Kusama链进行交互。有几种不同编程语言的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 库(
jsonrpsee
、tungstenite
和ws
)。有关更多信息和使用限制,请参阅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。示例区分了 sync
和 async
实现。别忘了检查相关 Cargo.toml
中的功能导入。它显示了如何将 api-client 导入为 async
或 sync
库。要运行示例,克隆 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=info
或 RUST_LOG=debug
来设置输出详细程度。
以下异步示例可以在 异步示例 文件夹中找到
- benchmark_bulk_xt:使用一系列交易浮点节点。
- check_extrinsic_events:检查并响应与 extrinsic 相关的事件。
- compose_extrinsic:在不与节点交互或在 no_std 模式下组合 extrinsic。
- contract_instantiate_with_code:在链上实例化合约。
- custom_nonce:组合带有自定义 nonce 的 extrinsic。
- get_account_identity:创建一个用于设置账户身份的自定义 Unchecked Extrinsic,然后使用 getter 获取它。
- get_blocks:从存储中读取头信息、块和已签名的块。
- get_storage:读取存储值。
- print_metadata:以可读的方式打印节点的元数据。
- query_runtime_api:如何查询运行时 API。
- runtime_update_async:如何异步地进行运行时升级。
- staking_batch_payout:验证器的批量奖励支付。
- subscribe_events:订阅并响应事件。
- sudo:创建并发送sudo封装的调用。
以下同步示例可以在同步示例文件夹中找到。
- runtime_update_sync:如何同步进行运行时升级。
- transfer_with_tungstenite_client:使用由种子生成的账户的compose_extrinsic包装器进行令牌传输。
- transfer_with_ws_client:使用由种子生成的账户的compose_extrinsic包装器进行令牌传输。
no_std
构建
除了rpc-clients和少量附加功能外,api-client中的几乎所有内容都与no_std
兼容。许多有用的功能,如外联和调用创建(参见宏)、元数据和事件类型(参见node-api和primitives)在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 存储库 中找到。
- 标签 v0.7.0 -> v0.9.0(不建议升级到 v0.8.0 标签,直接升级到 v0.9.0 可以节省一些额外的工作)。
- 标签 v0.9.0 -> v0.10.0
如果您在升级过程中仍然遇到问题,请不要犹豫,创建一个支持问题。
替代方案
Parity 提供了一个具有类似功能的 Rust 客户端:https://github.com/paritytech/subxt
致谢
substrate-api-client 的发展得到了以下机构的资助:
- web3 基金会
- Integritee
- Kusama 财政部
- Polkadot 财政部
我们还感谢以下团队的贡献:
- Parity Technologies 为构建 substrate 并在开发期间支持我们。
使用 substrate-api-client 的项目
如果您打算使用或正在使用 substrate-api-client,请将您的项目添加到此处 此处
按字母顺序排列
常见问题解答
-
Q: 所有内容都编译通过了,但 Substrate 节点不接受我的 extrinsic 或即使 extrinsic 应该正确也会返回错误。
A: 首先,请确保 api-client 和 Substrate 节点具有匹配的版本。例如,如果节点正在运行
release-polkadot-v1.2.0
,请检出并编译 api-client 的匹配分支。我们使用与 Parity 相同的命名方案。请注意:并非所有 Polkadot 版本都针对所有 api-client 版本发布。在 发行说明 中记录了哪些 Polkadot 版本受哪些 api-client 版本支持。找不到您想要的发布匹配?请随时通过问题请求。 -
Q: 在提交 extrinsic 时,我从节点收到
Bad input data provided to validate_transaction
错误。尽管我已经确保 api-client 和 Polkadot 版本匹配。A: 每个 extrinsic 都包含一些特定于节点的数据。例如,提示可能由
Asset
案板提供,或默认由Balances
案板提供。当前的 api-client 无法访问此信息。因此,这些配置数据必须手动配置。目前,有两个预定义的运行时配置,应与大多数 Substrate 节点匹配。确保您使用的是匹配的配置。如果您不使用提供的配置中配置的默认参数,您必须提供自己的配置,该配置实现了 Config 特性。
-
问:我想通过 api-client 从 substrate 节点查询状态,但我没有得到预期的值,相应的解码失败。这是怎么回事?
答:当指定您自己的状态查询时,您必须提供您要检索的状态的返回类型。这是因为 api-client 只从节点获取字节,必须能够正确反序列化这些字节。没有知道要解码的类型这是不可能的。例如,这个类型可能是一个简单的
u64
,用于检索账户的Balance
。但是小心:如果您正在查看模块代码及其返回类型,不要忘记考虑查询类型。例如,OptionQuery
会自动将返回类型包装到Option
中(有关更多信息,请参阅 substrate 文档“处理查询返回值”)。或者,您始终可以通过 polkadot.js 进行双重检查。如果您直接从运行时导入值,如在这个 示例 中所示,请记住将其适配到您要查询的节点。
依赖关系
~20–37MB
~644K SLoC