ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Diem JSON-RPC 客户端 SDK 实现清单:构建生产级客户端的完整技术要求与源码验证

Diem JSON-RPC 客户端 SDK 实现清单:构建生产级客户端的完整技术要求与源码验证 Diem JSON-RPC 客户端 SDK 实现清单构建生产级客户端的完整技术要求与源码验证【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址: https://gitcode.com/gh_mirrors/di/diem本文基于 Diem 仓库中的 client_checklist.md 编写。它是一份面向任意语言Java、Python、Go、Rust 等客户端 SDK 实现者的需求与技术细节检查清单覆盖模块结构、JSON-RPC 2.0 协议合规、错误分类、陈旧响应处理、DIP-4/DIP-5 标准支持、交易提交与等待验证、Testnet 测试等全链路要素。读完本文你将掌握一套可逐项勾选、可直接对照源码验证的客户端 SDK 验收标准并了解 Diem 官方 Rust SDK 如何落地这些要求可直接作为自研 SDK 的设计蓝本与测试清单。模块结构一个可测试、可维护的 SDK 骨架清单的 Basics 部分首先定义了客户端 SDK 应有的模块划分。合理的模块边界不仅是代码组织问题更决定了 SDK 是否支持application to do easy mock / stub development方便应用层做 Mock/桩开发。推荐结构如下DiemClientJSON-RPC API 的对外门面接口。所有业务方法都应通过该接口暴露便于应用层注入 Mock 实现进行单元测试。jsonrpcJSON-RPC 客户端接口层包含types数据传输对象DTO类型必须与 Diem JSON-RPC Spec 中定义的服务器端数据类型一一对应对协议版本、批量请求等底层细节的封装。stdlibMove stdlib 脚本工具。用于构造、解码 Move 脚本。testnetTestnet 工具必须包含 FaucetService用于处理 Testnet 上的铸币mint。diem-typesDiem 链上数据结构类型账户地址、签名交易、认证密钥等。utils底层工具集具体包括签名signingsha3 哈希、地址解析与转换、hex 编码/解码[DIP-4] 交易元数据transaction metadata处理[DIP-5] 意图标识符intent identifier与账户标识符account identifier处理。从官方 Rust SDK 的实现看这一结构在 crates/diem-client/src/lib.rs 中得到了完整印证lib.rs通过 feature 开关分别导出BlockingClient阻塞客户端、异步Client、FaucetClient、MethodRequest/MethodResponse请求响应类型并pub use diem_types::{account_address::AccountAddress, transaction::SignedTransaction}直接复用链上数据类型pub use diem_json_rpc_types::{errors, views}复用 JSON-RPC 的视图类型——这正对应清单中jsonrpc/types 应与服务器端 Spec 数据类型匹配的要求。JSON-RPC 2.0 协议合规版本校验与批量请求清单要求客户端处理两类协议层面的问题Spec 版本校验客户端应校验响应的jsonrpc字段是否为2.0。Rust SDK 的做法是在 client.rs 的validate函数中检查resp.jsonrpc ! 2.0并抛出Error::rpc_response(unsupported jsonrpc version ...)同时校验响应必须携带合法的id缺失或类型非法都会报错。JsonRpcVersion枚举则通过 serde 的#[serde(rename 2.0)]声明唯一合法版本。批量请求与响应处理批量请求batch允许一次 HTTP 调用携带多个方法。Rust SDK 的实现要点见 client.rs 的validate_batch按id将响应与请求一一对应出现多余或缺失的响应都会返回Error::batch(...)服务器端对整个批量请求返回单一错误响应而非数组时也能正确识别BatchResponse枚举使用 untagged 反序列化区分成功数组与单个错误对象两种形态。错误处理模型三层错误分类清单明确要求客户端 SDK 必须区分以下三类错误这是应用层决定能否重试的依据错误类别典型场景处理建议传输层错误Transport layer errorHTTP 调用失败、超时、连接断开应用可考虑重试JSON-RPC 协议错误Protocol error服务器响应非 JSON无法解析为 Spec 定义的数据结构缺少result与error字段通常指示服务器端 bugJSON-RPC 错误Server error服务器返回的error对象如交易校验失败需区分 invalid request 与 server errorRust SDK 在 error.rs 中实现了远细于此的分类Kind枚举覆盖了HttpStatus、Timeout、Request、JsonRpcError、RpcResponse、ChainId、StaleResponse、Batch、Decode、InvalidProof、NeedSync、StateStore、Unknown十余种。其中is_retriable()方法精确表达了哪些错误值得重试的判定逻辑HTTP 5xx、Timeout、StaleResponse、NeedSync可重试而RpcResponse、Request、JsonRpcError、ChainId、Batch、Decode等一律不可重试——这与清单三类错误决定重试策略的意图完全一致并补充了更细粒度规则如仅 500-599 的 HTTP 状态可重试。客户端初始化Chain ID 校验与连接管理清单要求以 chain id 与 JSON-RPC 服务器 URL 初始化客户端。Chain id 用于校验 get 方法响应确保连接的是预期网络客户端也可以选择首次服务器调用后初始化 chain idtrust-on-first-use。支持 HTTPS。提供连接池。Rust SDK 的Client::new(url)与new_with_retry(url, retry)接收 URL 并基于 reqwest 构建 HTTP 客户端默认 10 秒超时见 client.rs。Chain id 的校验逻辑在 state.rs 的StateManager::update_state中首次收到响应时直接信任其chain_id此后每次响应若chain_id与已记录值不一致立即返回Error::chain_id(expected, recieved)。陈旧响应处理数据新鲜度追踪与重试策略这是清单中篇幅最重、也最容易被忽视的模块。当一个 Full Node 与 Diem 网络失同步或你连接的是一组 Full Node 中同步滞后的节点时查询类接口可能返回过期的账本数据导致提交成功后查询到的是交易执行前的余额这类令人困惑的结果。Diem JSON-RPC 服务器在每个响应中都携带三个扩展字段见 json-rpc-spec.md 的 Diem Extensions 一节字段类型含义diem_chain_idunsigned int8网络 chain id例如 testnet 为 2diem_ledger_versionunsigned int64服务器端最新账本版本号diem_ledger_timestampusecunsigned int64服务器端最新账本时间戳微秒清单给出的处理规则如下解析上述三个字段并追踪客户端已知的最新账本版本与时间戳校验单调性当响应版本低于客户端已知版本时视为陈旧响应并报错last known blockchain version response version时间戳同理last known blockchain timestamp response timestamp查询方法可重试get_*类方法在遇到陈旧响应错误时应重试提交方法不可重试提交交易调用不应重试——即使提交给陈旧节点交易也能被正确同步若同一笔交易被重复提交反而可能收到 JSON-RPC 错误重试逻辑可在初始化时配置让应用能控制重试行为甚至完全移除重试、以便在异步环境中自行处理。Rust SDK 的对应实现State结构体chain_id、version、timestamp_usecs直接从响应构建state.rsupdate_state比较请求发起时状态与响应状态若响应早于请求时状态则抛出Error::stale并通过max持续记录最新状态。重试配置由 retry.rs 的Retry结构体承载默认Retry::new(20, Duration::from_millis(500))最多 20 次、间隔 500msRetry::none()可完全关闭重试异步与阻塞两种客户端均通过error.is_retriable()决定是否继续。值得注意的是submit在 client.rs 中走send_without_retry(request, true)——第二个参数ignore_stale true正是清单提交不重试、容忍陈旧的源码级体现。数据序列化与兼容性清单对数据层的要求正确处理 unsigned int64 类型JSON 数字精度有限客户端需专门处理 uint64可简单标记为 unsigned int64 并内部使用 int64 承载。响应序列化为类型化结构将 JSON 结果反序列化为强类型 DTO。前后向兼容前向兼容——忽略未知字段后向兼容——新字段必须是可选的。输入参数校验对非法输入如无效账户地址kkk应抛出InvalidArgumentError而非让服务器返回晦涩错误。接口优先使用 AccountAddress 类型而非字符串地址从类型系统层面杜绝非法地址。Rust SDK 中MethodResponse::from_json(method, json)负责将原始 JSON 按方法转换为类型化视图lib.rs反序列化失败返回Error::decodeget_deserialized_resource/get_deserialized_events甚至支持把 Move 资源直接反序列化为 Rust 类型client.rs体现了JSON 结果转类型化结构的高级形态。交易哈希与脚本解码两个容易被忽略但至关重要的细节交易哈希计算从签名交易生成交易哈希的公式为hex-encode(sha3-256([]byte(DIEM::Transaction)) []byte(0) signed transaction bytes)即先对DIEM::Transaction前缀做 sha3-256拼接一个0字节再拼接签名交易原始字节最后整体做 sha3-256 并 hex 编码。该哈希用于提交后验证返回的交易是否为所提交的那笔。交易脚本字节解码由于服务器无需升级即可引入新交易脚本客户端必须能够识别所有链上执行的交易脚本。方法是通过升级客户端侧的 Move stdlib 脚本二进制及其生成的类型信息代码来解码最新的 Move stdlib 脚本。这意味着 SDK 的 stdlib 模块需要可热更新。DIP-4交易元数据支持清单要求客户端 SDK 完整支持 [DIP-4] 交易元数据规范Transaction Metadata Specification覆盖四类场景非托管方到托管方non-custodial to custodial交易元数据托管方到非托管方custodial to non-custodial交易元数据托管方到托管方custodial to custodial交易元数据及其签名退款refund元数据。这部分能力属于合规与互操作性范畴元数据被编码进交易的metadata字段托管方与交易平台依赖其完成归属确认与对账。DIP-4 是 DIPDiem Improvement Proposal体系的一部分客户端 SDK 将其作为独立模块实现以支持受监管场景下的转账识别。DIP-5地址格式化支持清单要求 SDK 支持 [DIP-5] 地址格式化规范bech32 编码/解码账户标识符account identifier的编码与解码意图标识符intent identifier的编码与解码。意图标识符允许用户在不暴露账户余额/序列号的情况下以人类可读的形式如diem://...表达向某账户转账某币种某金额的意图账户标识符则封装了链地址与子地址sub-address支持托管方账户体系。这两项是钱包类应用在 Diem 生态互通的关键。读区块链get_* 方法全集清单列出了客户端必须实现的全部只读方法方法说明Get metadata获取链上元数据chain id、版本、时间戳等Get currencies获取支持的货币列表Get events按事件 key 查询事件Get transactions按版本区间查询交易Get account查询账户状态Get account transaction按账户地址 序列号查询单笔交易Get account transactions按账户查询交易列表Get account events按账户查询事件通常由 Get events 覆盖此外还必须处理错误响应Error response、将结果 JSON 序列化为类型化结构、前向兼容忽略未知字段、后向兼容新字段可选。每个方法的完整参数与响应定义可对照仓库中 method_get_metadata.md、method_get_account.md、method_get_transactions.md、method_get_events.md 等逐一实现。Rust SDK 的对应方法get_metadata、get_account、get_transactions、get_events、get_currencies等全部返回ResponseT其中Response同时携带解析后的State便于调用方持续追踪账本新鲜度client.rs。提交交易与 waitForTransaction提交清单要求至少支持提交 [p2p transfer] 交易peer_to_peer_with_metadata脚本提交其他 Move Stdlib 脚本。Rust SDK 的submit(self, txn: SignedTransaction)接收完整签名交易对象内部序列化后 POST 到服务器且按前文所述不重试、容忍陈旧client.rs。完整的提交流程脚本编码 → 签名 → LCS 序列化 → 提交 → 节点解码校验 → 入 mempool可参考官方实现指南中的 Java 示例client_implementation_guide.md。waitForTransaction等待、校验与错误语义这是客户端 SDK 中语义最丰富的方法。清单定义了两个重载变体一waitForTransaction(accountAddress, sequence, transactionHash, expirationTimeSec, timeout)其中 accountAddress 与 sequence 定位交易、transactionHash 用于确认交易身份、expirationTimeSec 用于判定过期、timeout 为最长等待时间。必须满足在 timeout或 5 秒默认内等待并校验执行结果为executed否则返回/抛出错误标志签名交易哈希校验失败 →TransactionSequenceNumberConflictError即序列号冲突说明该序列号已被其他交易占用交易vm_status类型不是executed→TransactionExecutionFailure交易过期 →TransactionExpiredError比较交易的expirationTimeSec与响应中的最新账本时间戳当响应最新账本时间戳 ≥ expirationTimeSec 时可确定该交易永远不会被成功执行。单位陷阱响应最新账本时间戳单位为微秒而expirationTimeSec单位为秒比较前必须换算。变体二waitForTransaction(submitted signed transaction, timeout)先解码签名交易 → 计算交易哈希 → 委托给变体一。Rust SDK 的实现高度吻合client.rs 的wait_for_transaction默认 60 秒超时、500ms 轮询间隔通过get_account_transaction循环查询查到时校验哈希一致性不匹配返回TransactionHashMismatchError并利用last_known_state的timestamp_usecs / 1_000_000与expiration_time_secs比较实现过期判定TransactionExpired。wait_for_signed_transaction则额外校验vm_status.is_executed()失败返回TransactionExecutionFailed。这些错误类型全部定义在 error.rs 的WaitForTransactionError枚举中。测试与 Testnet 支持清单要求 SDK 附带测试工具链密钥生成生成 ed25519 私钥、从私钥派生公钥认证密钥生成单签Singleauth-keys 与多签MultiSigauth-keys通过 Faucet 服务铸币测试账户必须有余额才能提交转账交易。Testnet 上的 Faucet 服务允许任何人创建账户并铸币是端到端验证客户端的关键基础设施详见 service_testnet_faucet.md该文档进一步指向 crates/diem-faucet 的 README。Rust SDK 的FaucetClient::fund(currency_code, auth_key, amount)会 POST 到 Faucet 服务将返回的十六进制签名交易列表逐个 BCS 反序列化并调用wait_for_signed_transaction等待建账户 铸币两笔交易全部执行成功faucet.rs——这正是mint coins through Faucet service的参考实现。此外client_implementation_guide.md 提供了 Testnet 联调细节可用get_currencies作为第一个实现的方法无需参数、响应恒定可用三个静态账户地址测试get_account——root 账户0000000000000000000000000A550C18存储货币等全局资源、core code 地址00000000000000000000000000000001存储币种类型信息、designed dealer 地址000000000000000000000000000000DDTestnet 铸币专用账户。发布、示例与增强项发布清单要求按语言生态的标准渠道发布正式版本如 Java Maven Central、Python PyPI并建议在 HTTP 请求的User-Agent中携带客户端 SDK 名称与版本便于服务器识别客户端版本。Rust SDK 的做法是USER_AGENT: str concat!(diem-client-sdk-rust / , env!(CARGO_PKG_VERSION))lib.rs并在每次 POST 时设置该头client.rs。示例清单建议提供 p2p transfer 示例、退款 p2p transfer 示例、创建 childVASP 示例、意图标识符编解码示例。Nice to have异步客户端async client连接 Testnet 的 CLI 用于试用功能。Rust SDK 通过 feature 开关同时提供了BlockingClient与异步Client正是该增强项的落地。结语一份合格的 Diem JSON-RPC 客户端 SDK远不止能发 HTTP 请求这么简单。从模块结构、协议合规、三层错误分类到陈旧响应追踪、DIP-4/DIP-5 标准支持、交易哈希与脚本解码、waitForTransaction的完整错误语义再到 Testnet 与 Faucet 联调清单逐项给出了可验收的标准。对照仓库中 crates/diem-client 的 Rust 官方实现每一项要求都能找到对应的源码佐证——它既是自研 SDK 的需求规格书也是验证现有实现完备性的检查表。【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址: https://gitcode.com/gh_mirrors/di/diem创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表