RPC 客户端
RpcClient 是通过 JSON-RPC 2.0 与 Savitri 节点通信的核心传输层。
创建客户端
use savitri_sdk::RpcClient;
// 通过 URL(localhost HTTP 允许)
let client = RpcClient::from_url("http://localhost:8545")?;
// 通过 URL(远程需要 HTTPS)
let client = RpcClient::from_url("https://rpc.savitrinetwork.com")?;
// 使用自定义配置
use savitri_sdk::client::rpc_client::RpcClientConfig;
let client = RpcClient::new(RpcClientConfig {
url: "http://localhost:8545".to_string(),
timeout: Some(60), // 60 second timeout
allow_insecure: false, // enforce HTTPS for remote
})?;
链查询
// 区块高度
let height: u64 = client.get_block_number().await?;
// 按高度获取区块
let block = client.get_block_by_height(42).await?;
println!("Block {} hash: {}", block.height, block.hash);
println!("Proposer: {}", block.proposer);
println!("TX count: {}", block.transaction_count);
// 区块哈希
let hash: String = client.get_block_hash(42).await?;
账户查询
// 完整账户信息
let account = client.get_account("aabbcc...64chars").await?;
println!("Balance: {}", account.balance); // u128 as decimal string
println!("Nonce: {}", account.nonce);
// 仅获取余额
let balance: String = client.get_balance("aabbcc...").await?;
// 仅获取 nonce
let nonce: u64 = client.get_nonce("aabbcc...").await?;
交易操作
// 按哈希获取交易
let tx = client.get_transaction("tx_hash_hex").await?;
println!("From: {} To: {} Amount: {}", tx.from, tx.to, tx.amount);
// 提交已签名的交易
let result = client.send_raw_transaction("signed_tx_hex").await?;
println!("TX hash: {}", result.tx_hash);
// 领取测试网水龙头
let claim = client.faucet_claim("your_address_64hex").await?;
println!("Received: {} (tx: {})", claim.amount, claim.tx_hash);
共识查询
// 本地 PoU 状态
let pou = client.pou_local().await?;
println!("My score: {:?}", pou.local_score);
println!("Leader: {:?} (score: {:?})", pou.leader, pou.leader_score);
println!("Am I leader? {}", pou.local_is_leader);
// 所有节点分数
let peers = client.pou_peers().await?;
for (peer_id, score) in &peers.peers {
println!("{}: {}", peer_id, score);
}
// 分组(仅限主节点)
let groups = client.pou_groups().await?;
for group in &groups.groups {
println!("Group {}: {} members", group.group_id, group.members.len());
}
// 主节点列表(仅限主节点)
let mns = client.pou_masternodes().await?;
for mn in &mns.masternodes {
println!("{}: PoU={} Health={}", mn.node_id, mn.pou_score, mn.health_score);
}
批量请求
在单个 HTTP 请求中发送多个 RPC 调用(最多 100 个):
let responses = client.batch(vec![
("savitri_blockNumber", serde_json::json!([])),
("savitri_health", serde_json::json!([])),
("savitri_getAccount", serde_json::json!(["aabbcc..."])),
]).await?;
for resp in &responses {
println!("{}", resp);
}
原始调用
用于类型化辅助函数未覆盖的方法:
let result: serde_json::Value = client
.call_raw("custom_method", serde_json::json!(["param1", 42]))
.await?;
健康检查
// 类型化健康检查
let health = client.health().await?;
assert_eq!(health.status, "ok");
// 简单 ping(返回 bool)
let is_alive = client.ping().await?;
错误处理
use savitri_sdk::SdkError;
match client.get_account("invalid").await {
Ok(account) => println!("Balance: {}", account.balance),
Err(SdkError::RpcError { code, message, .. }) => {
println!("RPC error {}: {}", code, message);
}
Err(SdkError::HttpError(e)) => {
println!("Network error: {}", e);
}
Err(e) => println!("Other error: {}", e),
}
错误类型:
| 错误 | 描述 |
|---|---|
SdkError::RpcError | 服务器返回的 JSON-RPC 错误(code、message、data) |
SdkError::HttpError | 网络/传输错误 |
SdkError::JsonError | JSON 序列化错误 |
SdkError::InvalidResponse | 意外的响应格式 |
SdkError::NoRpcClient | 调用钱包方法时未建立 RPC 连接 |