Rust NEAR协议JSON-RPC客户端库near-jsonrpc-client的使用,实现与NEAR区块链节点的高效交互

Rust NEAR协议JSON-RPC客户端库near-jsonrpc-client的使用

near-jsonrpc-client是一个通过JSON-RPC与NEAR协议交互的低级API库。

使用方法

每个有效的JSON-RPC方法都定义在methods模块中。例如,要创建一个tx请求,你需要从tx模块开始,使用methods::tx::RpcTransactionStatusRequest结构体构建请求。

以下是内容中提供的示例代码:

use near_jsonrpc_client::{methods, JsonRpcClient};
use near_jsonrpc_primitives::types::transactions::TransactionInfo;

let mainnet_client = JsonRpcClient::connect("https://archival-rpc.mainnet.near.org");

let tx_status_request = methods::tx::RpcTransactionStatusRequest {
    transaction_info: TransactionInfo::TransactionId {
        hash: "9FtHUFBQsZ2MG77K3x3MJ9wjX3UT8zE1TczCrhZEcG8U".parse()?,
        account_id: "miraclx.near".parse()?,
    },
};

// 通过连接客户端在服务器上调用方法
let tx_status = mainnet_client.call(tx_status_request).await?;

println!("{:?}", tx_status);

完整示例

下面是一个更完整的示例,展示如何使用near-jsonrpc-client与NEAR区块链节点交互:

use near_jsonrpc_client::{methods, JsonRpcClient};
use near_jsonrpc_primitives::types::transactions::TransactionInfo;
use near_primitives::types::AccountId;
use near_primitives::views::QueryRequest;
use std::str::FromStr;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 连接到NEAR主网节点
    let client = JsonRpcClient::connect("https://archival-rpc.mainnet.near.org");
    
    // 示例1: 查询交易状态
    let tx_request = methods::tx::RpcTransactionStatusRequest {
        transaction_info: TransactionInfo::TransactionId {
            hash: "9FtHUFBQsZ2MG77K3x3MJ9wjX3UT8zE1TczCrhZEcG8U".parse()?,
            account_id: "miraclx.near".parse()?,
        },
    };
    
    let tx_status = client.call(tx_request).await?;
    println!("Transaction status: {:?}", tx_status);
    
    // 示例2: 查询账户信息
    let account_id = AccountId::from_str("near")?;
    let account_request = methods::query::RpcQueryRequest {
        block_reference: near_primitives::types::BlockReference::latest(),
        request: QueryRequest::ViewAccount { account_id },
    };
    
    let account_info = client.call(account_request).await?;
    println!("Account info: {:?}", account_info);
    
    // 示例3: 获取区块状态
    let block_request = methods::block::RpcBlockRequest {
        block_reference: near_primitives::types::BlockReference::latest(),
    };
    
    let block_info = client.call(block_request).await?;
    println!("Latest block: {:?}", block_info);
    
    Ok(())
}

特性

  1. 提供了所有NEAR JSON-RPC方法的低级接口
  2. 异步支持,适合高性能应用
  3. 类型安全的请求和响应结构体
  4. 支持主网和测试网连接

安装

要在项目中使用near-jsonrpc-client,可以运行以下Cargo命令:

cargo add near-jsonrpc-client

或者在Cargo.toml中添加:

near-jsonrpc-client = "0.17.0"

许可证

near-jsonrpc-client采用双重许可:

  • Apache License, Version 2.0
  • MIT license

你可以选择其中任何一种许可证使用。


1 回复

Rust NEAR协议JSON-RPC客户端库near-jsonrpc-client使用指南

near-jsonrpc-client是一个Rust库,用于与NEAR区块链节点通过JSON-RPC协议进行交互。它提供了类型安全的接口来调用NEAR节点的各种RPC方法。

安装

在Cargo.toml中添加依赖:

[dependencies]
near-jsonrpc-client = "0.5.0"
tokio = { version = "1.0", features = ["full"] }  # 需要异步运行时

完整示例代码

use near_jsonrpc_client::{JsonRpcClient, methods};
use near_jsonrpc_primitives::types::query::QueryResponseKind;
use near_primitives::transaction::Transaction;
use near_crypto::{InMemorySigner, SecretKey};
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 创建客户端
    let client = JsonRpcClient::connect("https://archival-rpc.mainnet.near.org");
    
    // 2. 查询区块信息
    get_block_info(&client).await?;
    
    // 3. 查询账户信息
    get_account_info(&client).await?;
    
    // 4. 发送交易 (测试网)
    // send_transaction(&client).await?;
    
    // 5. 批量请求
    batch_requests(&client).await?;
    
    // 6. 订阅区块事件
    // subscribe_blocks(&client).await?;
    
    // 7. 错误处理示例
    handle_errors(&client).await?;
    
    // 8. 并发请求
    concurrent_requests(&client).await?;
    
    Ok(())
}

async fn get_block_info(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    let request = methods::block::RpcBlockRequest {
        block_id: near_primitives::types::BlockId::latest(),
    };
    
    let response = client.call(request).await?;
    
    println!("Latest block height: {}", response.header.height);
    println!("Block hash: {}", response.header.hash);
    
    Ok(())
}

async fn get_account_info(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    let request = methods::query::RpcQueryRequest {
        block_reference: near_primitives::types::BlockReference::latest(),
        request: near_primitives::views::QueryRequest::ViewAccount {
            account_id: "near".parse()?,
        },
    };
    
    let response = client.call(request).await?;
    
    if let QueryResponseKind::ViewAccount(account_view) = response.kind {
        println!("Account ID: {}", account_view.account_id);
        println!("Balance: {} yoctoNEAR", account_view.amount);
        println!("Storage used: {} bytes", account_view.storage_usage);
    }
    
    Ok(())
}

async fn send_transaction(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    // 注意: 实际使用时应从安全存储中获取私钥
    let signer = InMemorySigner::from_secret_key(
        "your_account.testnet".parse()?,
        SecretKey::from_str("ed25519:your_private_key_here")?,
    );
    
    let transaction = Transaction {
        signer_id: "your_account.testnet".parse()?,
        public_key: signer.public_key(),
        nonce: 1,  // 实际应从账户状态查询当前nonce
        receiver_id: "receiver_account.testnet".parse()?,
        block_hash: client.call(methods::block::RpcBlockRequest::latest()).await?.header.hash,
        actions: vec![
            near_primitives::transaction::Action::Transfer(
                near_primitives::transaction::TransferAction {
                    deposit: 1_000_000_000_000_000_000_000_000,  // 1 NEAR
                }
            )
        ],
    };
    
    let request = methods::broadcast_tx_async::RpcBroadcastTxAsyncRequest {
        signed_transaction: transaction.sign(&signer),
    };
    
    let response = client.call(request).await?;
    println!("Transaction sent! Hash: {}", response);
    
    Ok(())
}

async fn batch_requests(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    let batch = vec![
        methods::block::RpcBlockRequest::latest().into(),
        methods::gas_price::RpcGasPriceRequest { block_id: None }.into(),
    ];
    
    let responses = client.batch(batch).await?;
    
    for response in responses {
        match response {
            methods::block::RpcBlockResponse::Ok(block) => {
                println!("Block height: {}", block.header.height);
            },
            methods::gas_price::RpcGasPriceResponse::Ok(gas_price) => {
                println!("Gas price: {:?}", gas_price.gas_price);
            },
            _ => println!("Unexpected response"),
        }
    }
    
    Ok(())
}

async fn subscribe_blocks(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    let mut stream = client.subscribe(methods::block::RpcBlockRequest::latest()).await?;
    
    while let Some(block) = stream.next().await {
        println!("New block: {}", block?.header.height);
    }
    
    Ok(())
}

async fn handle_errors(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    let request = methods::query::RpcQueryRequest {
        block_reference: near_primitives::types::BlockReference::latest(),
        request: near_primitives::views::QueryRequest::ViewAccount {
            account_id: "nonexistent-account.testnet".parse()?,
        },
    };
    
    match client.call(request).await {
        Ok(response) => {
            println!("Account exists: {:?}", response);
        },
        Err(near_jsonrpc_client::errors::RpcError::HandlerError(err)) => {
            eprintln!("Account does not exist: {}", err);
        },
        Err(err) => {
            eprintln!("RPC error: {}", err);
        }
    }
    
    Ok(())
}

async fn concurrent_requests(client: &JsonRpcClient) -> Result<(), Box<dyn std::error::Error>> {
    let futures = vec![
        client.call(methods::block::RpcBlockRequest::latest()),
        client.call(methods::gas_price::RpcGasPriceRequest { block_id: None }),
    ];
    
    let results = futures::future::try_join_all(futures).await?;
    
    if let methods::block::RpcBlockResponse::Ok(block) = &results[0] {
        println!("Latest block height: {}", block.header.height);
    }
    
    if let methods::gas_price::RpcGasPriceResponse::Ok(gas_price) = &results[1] {
        println!("Current gas price: {:?}", gas_price.gas_price);
    }
    
    Ok(())
}

near-jsonrpc-client提供了与NEAR区块链交互的完整功能集,包括查询状态、发送交易、订阅事件等。通过类型安全的API和Rust的强类型系统,可以大大减少运行时错误。

回到顶部