Rust NEAR协议JSON-RPC基础库near-jsonrpc-primitives的使用,实现区块链节点交互与数据查询

Rust NEAR协议JSON-RPC基础库near-jsonrpc-primitives的使用,实现区块链节点交互与数据查询

安装

在项目目录中运行以下Cargo命令:

cargo add near-jsonrpc-primitives

或者在Cargo.toml中添加以下行:

near-jsonrpc-primitives = "0.30.3"

基本使用示例

以下是一个使用near-jsonrpc-primitives库与NEAR区块链节点交互的完整示例:

use near_jsonrpc_primitives::types::query::RpcQueryRequest;
use near_jsonrpc_client::{methods, JsonRpcClient};
use near_primitives::types::{AccountId, BlockReference};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建JSON-RPC客户端连接NEAR主网节点
    let client = JsonRpcClient::connect("https://rpc.mainnet.near.org");

    // 示例1: 查询区块状态
    let block_request = methods::block::RpcBlockRequest {
        block_reference: BlockReference::latest(),
    };
    let block_response = client.call(block_request).await?;
    println!("Latest block height: {}", block_response.header.height);

    // 示例2: 查询账户信息
    let account_id: AccountId = "example.near".parse()?;
    let account_request = methods::query::RpcQueryRequest {
        block_reference: BlockReference::latest(),
        request: RpcQueryRequest::ViewAccount {
            account_id: account_id.clone(),
        },
    };
    let account_response = client.call(account_request).await?;
    
    if let methods::query::RpcQueryResponse::ViewAccount(result) = account_response {
        println!("Account {} balance: {} yoctoNEAR", account_id, result.amount);
    }

    // 示例3: 查询合约状态
    let contract_id: AccountId = "guest-book.near".parse()?;
    let contract_request = methods::query::RpcQueryRequest {
        block_reference: BlockReference::latest(),
        request: RpcQueryRequest::ViewState {
            account_id: contract_id.clone(),
            prefix: near_primitives::types::StoreKey::from(vec![]),
        },
    };
    let contract_response = client.call(contract_request).await?;
    
    if let methods::query::RpcQueryResponse::ViewState(result) = contract_response {
        println!("Contract {} state size: {}", contract_id, result.values.len());
    }

    Ok(())
}

完整示例扩展

以下是一个更完整的示例,展示了更多功能:

use near_jsonrpc_primitives::types::query::RpcQueryRequest;
use near_jsonrpc_client::{methods, JsonRpcClient};
use near_primitives::types::{AccountId, BlockReference, Finality};
use near_primitives::views::QueryRequest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 连接到测试网节点
    let client = JsonRpcClient::connect("https://rpc.testnet.near.org");

    // 1. 查询最新区块
    let block_request = methods::block::RpcBlockRequest {
        block_reference: BlockReference::Finality(Finality::Final),
    };
    let block = client.call(block_request).await?;
    println!("Final block height: {}", block.header.height);

    // 2. 查询账户详情
    let account_id: AccountId = "test.near".parse()?;
    let account_query = methods::query::RpcQueryRequest {
        block_reference: BlockReference::latest(),
        request: RpcQueryRequest::ViewAccount {
            account_id: account_id.clone(),
        },
    };
    let account = client.call(account_query).await?;
    
    // 3. 查询合约方法
    let contract_id: AccountId = "demo.testnet".parse()?;
    let method_query = methods::query::RpcQueryRequest {
        block_reference: BlockReference::latest(),
        request: RpcQueryRequest::CallFunction {
            account_id: contract_id.clone(),
            method_name: "get_value".to_string(),
            args: near_primitives::types::FunctionArgs::from(vec![]),
        },
    };
    let method_response = client.call(method_query).await?;

    // 4. 查询交易状态
    let tx_hash = "9FtHUFBQs9...".to_string(); // 替换为实际交易哈希
    let tx_status = methods::tx::RpcTransactionStatusRequest {
        transaction_info: near_jsonrpc_primitives::types::transactions::TransactionInfo::TransactionId {
            hash: tx_hash.parse()?,
            account_id: "sender.testnet".parse()?,
        },
    };
    let tx_result = client.call(tx_status).await?;

    Ok(())
}

功能说明

  1. 区块查询:通过methods::block::RpcBlockRequest可以查询区块链的最新区块或指定区块的信息。

  2. 账户查询:使用RpcQueryRequest::ViewAccount可以查询NEAR账户的余额、合约代码等信息。

  3. 合约状态查询:通过RpcQueryRequest::ViewState可以查询合约的存储状态。

  4. 合约方法调用:使用RpcQueryRequest::CallFunction可以调用合约的只读方法。

  5. 交易查询:通过methods::tx::RpcTransactionStatusRequest可以查询交易状态。

注意事项

  • 需要异步运行时(如tokio)来执行RPC调用
  • 所有RPC方法都返回Result类型,需要处理可能的错误
  • 对于主网查询,建议使用公共RPC节点或自己运行的节点
  • 查询响应需要匹配相应的枚举变体来获取具体数据

许可证

该库采用MIT或Apache-2.0双重许可。


1 回复

Rust NEAR协议JSON-RPC基础库near-jsonrpc-primitives使用指南

near-jsonrpc-primitives是一个用于与NEAR区块链节点交互的Rust库,它提供了JSON-RPC客户端功能,可以查询区块链数据、发送交易等操作。

安装方法

在Cargo.toml中添加依赖:

[dependencies]
near-jsonrpc-primitives = "0.1.0"
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }

基本使用方法

1. 创建客户端连接

use near_jsonrpc_primitives::client::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new("https://rpc.mainnet.near.org");
    
    // 使用客户端进行各种查询...
    
    Ok(())
}

2. 查询区块信息

use near_jsonrpc_primitives::types::blocks::RpcBlockRequest;

async fn get_block(client: &Client, block_id: u64) {
    let request = RpcBlockRequest {
        block_id: block_id.into(),
    };
    
    match client.block(request).await {
        Ok(response) => println!("Block info: {:?}", response),
        Err(e) => eprintln!("Error getting block: {}", e),
    }
}

3. 查询账户信息

use near_jsonrpc_primitives::types::account::RpcAccountViewRequest;

async fn get_account_info(client: &Client, account_id: &str) {
    let request = RpcAccountViewRequest {
        account_id: account_id.parse().unwrap(),
    };
    
    match client.account_view(request).await {
        Ok(response) => println!("Account info: {:?}", response),
        Err(e) => eprintln!("Error getting account info: {}", e),
    }
}

4. 查询交易状态

use near_jsonrpc_primitives::types::transactions::RpcTransactionStatusRequest;
use near_primitives::transaction::Transaction;

async fn get_transaction_status(client: &Client, transaction: Transaction) {
    let request = RpcTransactionStatusRequest {
        transaction,
    };
    
    match client.transaction_status(request).await {
        Ok(response) => println!("Transaction status: {:?}", response),
        Err(e) => eprintln!("Error getting transaction status: {}", e),
    }
}

高级用法

批量请求

use near_jsonrpc_primitives::client::BatchClient;
use near_jsonrpc_primitives::types::blocks::RpcBlockRequest;

async fn batch_request(client: &Client) {
    let batch_client = BatchClient::new(client);
    
    let requests = vec![
        RpcBlockRequest { block_id: 极好的.into() }.into(),
        RpcBlockRequest { block_id: 2.into() }.into(),
    ];
    
    match batch_client.batch(requests).await {
        Ok(responses) => {
            for response in responses {
                println!("Batch response: {:?}", response);
            }
        }
        Err(e) => eprintln!("Batch request failed: {}", e),
    }
}

自定义请求

use near_jsonrpc_primitives::client::Method;
use serde_json::json;

async fn custom_request(client: &Client) {
    let method = Method::Query("query".to_string());
    let params = json!({
        "request_type": "call_function",
        "account_id": "contract.near",
        "method_name": "get_info",
        "args_base64": "",
        "finality": "optimistic"
    });
    
    match client.call(method, params).await {
        Ok(response) => println!("Custom response: {:?}", response),
        Err(e) => eprintln!("Custom request failed: {}", e),
    }
}

错误处理

use near_jsonrpc_primitives::errors极好的::RpcError;

async fn handle_errors(client: &Client) {
    match client.block(RpcBlockRequest { block_id: 9999999.into() }).await {
        Ok(response) => println!("Got block: {:?}", response),
        Err(RpcError::ServerError(code, message)) => {
            eprintln!("Server error ({}): {}", code, message);
        }
        Err(RpcError::TransportError(e)) => {
            eprintln!("Network error: {}", e);
        }
        Err(e) => {
            eprintln!("Other error: {}", e);
        }
    }
}

完整示例代码

use near_jsonrpc_primitives::{
    client::{Client, BatchClient},
    types::{
        blocks::RpcBlockRequest,
        account::RpcAccountViewRequest,
        transactions::RpcTransactionStatusRequest
    },
    errors::RpcError
};
use near_primitives::transaction::Transaction;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 创建客户端连接
    let client = Client::new("https://rpc.testnet.near.org");
    
    // 2. 查询区块信息
    get_block(&client, 1).await;
    
    // 3. 查询账户信息
    get_account_info(&client, "example.testnet").await;
    
    // 4. 批量请求示例
    batch_request(&client).await;
    
    // 5. 错误处理示例
    handle_errors(&client).await;
    
    Ok(())
}

async fn get_block(client: &Client, block_id: u64) {
    println!("\n--- 查询区块信息 ---");
    let request = RpcBlockRequest {
        block_id: block_id.into(),
    };
    
    match client.block(request).await {
        Ok(response) => println!("区块信息: {:#?}", response),
        Err(e) => eprintln!("查询区块错误: {}", e),
    }
}

async fn get_account_info(client: &Client, account_id: &str) {
    println!("\n--- 查询账户信息 ---");
    let request = RpcAccountViewRequest {
        account_id: account_id.parse().unwrap(),
    };
    
    match client.account_view(request).await {
        Ok(response) => println!("账户信息: {:#?}", response),
        Err(e) => eprintln!("查询账户错误: {}", e),
    }
}

async fn batch_request(client: &Client) {
    println!("\n--- 批量请求示例 ---");
    let batch_client = BatchClient::new(client);
    
    let requests = vec![
        RpcBlockRequest { block_id: 1.into() }.into(),
        RpcBlockRequest { block_id: 2.into() }.into(),
    ];
    
    match batch_client.batch(requests).await {
        Ok(responses) => {
            for (i, response) in responses.iter().enumerate() {
                println!("批量响应 {}: {:#?}", i+1, response);
            }
        }
        Err(e) => eprintln!("批量请求失败: {}", e),
    }
}

async fn handle_errors(client: &Client) {
    println!("\n--- 错误处理示例 ---");
    match client.block(RpcBlockRequest { block_id: 9999999.into() }).await {
        Ok(response) => println!("获取区块成功: {:?}", response),
        Err(RpcError::ServerError(code, message)) => {
            eprintln!("服务器错误 ({}): {}", code, message);
        }
        Err(RpcError::TransportError(e)) => {
            eprintln!("网络错误: {}", e);
        }
        Err(e) => {
            eprintln!("其他错误: {}", e);
        }
    }
}

注意事项

  1. 所有API调用都是异步的,需要使用async/await
  2. 生产环境中应该添加适当的重试逻辑和错误处理
  3. 对于频繁查询,考虑使用NEAR Indexer框架获取更高效的数据访问
  4. 主网和测试网的RPC端点不同:
    • 主网: https://rpc.mainnet.near.org
    • 测试网: https://rpc.testnet.near.org

这个库提供了与NEAR区块链交互的基础功能,适合需要直接与NEAR节点通信的应用场景。

回到顶部