Skip to content

Rust Client APIs

ParallelChain RPC APIs are the HTTP APIs that Fullnodes make available to clients.

In the section ParallelChain Client Library, we introduce the Rust Library to make RPC calls programatically.

The Client Library allows you to easily submit RPC requests and parse RPC responses without the need to understand the details of HTTP URL, request format or response format. The formation of HTTP APIs is specified in ParallelChain Protocol.

ParallelChain Client Library (Rust)

ParallelChain Client Library is a Rust programming language implementation of ParallelChain RPC API. We will show how to use the library by example code. To use the library in your rust project, first add dependency pchain-client in Cargo.toml file. You will also need the dependency pchain-types for necessary basic types, and the dependency tokio to run the client in asynchronous application.

Cargo.toml:

[dependencies]
pchain-client = "0.4.3"
pchain-types = "0.4.3"
tokio = {version = "1", features = ["full"]}

You can instantiate the struct pchain_client::Client by providing the link to a ParallelChain RPC endpoint.

#[tokio::main]
async fn main() {
    /// Connect to Testnet RPC endpoint
    let client = Client::new("https://pchain-test-rpc02.parallelchain.io");
    /// ...
}

Note

RPC endpoints for Mainnet and Testnet are https://pchain-main-rpc02.parallelchain.io and https://pchain-test-rpc02.parallelchain.io respectively.

submit_transaction

Submit a transaction to the mempool.

// The function submit_transaction creates SubmitTransactionRequest from the input transaction.
let response: SubmitTransactionResponse = client
    .submit_transaction(&Transaction::new(
        &signer,
        nonce,
        vec![Command::Transfer(TransferInput {
            amount,
            recipient,
        })],
        gas_limit,
        max_base_fee_per_gas,
        priority_fee_per_gas,
    ))
    .await
    .unwrap();

Note

The variable signer is the Keypair of the EOA as the signer of the transaction. Check out the module pchain_types::cryptograhy for generating or importing keypair.

In case you need free tokens for submitting transactions to Testnet, check out the Faucet Service for details.

Request

struct SubmitTransactionRequest {
    transaction: Transaction,
}

Response

struct SubmitTransactionResponse {
    error: Option<SubmitTransactionError>,
}

Where SubmitTransactionError:

enum SubmitTransactionError {
    UnacceptableNonce,
    MempoolFull,
    Other,
}


transaction

Get a transaction and optionally its receipt.

let response: TransactionResponse = client
    .transaction(&TransactionRequest {
        transaction_hash,
        include_receipt,
    })
    .await
    .unwrap();

Request

struct TransactionRequest {    
    transaction_hash: CryptoHash,
    include_receipt: bool,
}

Response

struct TransactionResponse {
    transaction: Option<Transaction>,
    receipt: Option<Receipt>,
    block_hash: Option<CryptoHash>,
    position: Option<u32>,
}

transaction_position

Find out where a transaction is in the blockchain.

let response: TransactionPositionResponse = client
    .transaction_position(&TransactionPositionRequest { transaction_hash })
    .await
    .unwrap();

Request

struct TransactionPositionRequest {
    transaction_hash: CryptoHash,
}

Response

struct TransactionPositionResponse {
    transaction_hash: Option<CryptoHash>,
    block_hash: Option<CryptoHash>,
    position: Option<u32>,
}

receipt

Get a transaction's receipt.

let response: ReceiptResponse = client
    .receipt(&ReceiptRequest { transaction_hash })
    .await
    .unwrap();

Request

struct ReceiptRequest {    
    transaction_hash: CryptoHash,
}

Response

struct ReceiptResponse {
    transaction_hash: CryptoHash,
    receipt: Option<Receipt>,
    block_hash: Option<CryptoHash>,
    position: Option<u32>,
}

block

Get a block by its block hash.

let response: BlockResponse = client
    .block(&BlockRequest { block_hash })
    .await
    .unwrap();

Request

struct BlockRequest {
    block_hash: CryptoHash,
}

Response

struct BlockResponse {
    block: Option<Block>,
}

block_header

Get a block header by its block hash.

let response: BlockHeaderResponse = client
    .block_header(&BlockHeaderRequest { block_hash })
    .await
    .unwrap();

Request

struct BlockHeaderRequest {
    block_hash: CryptoHash,
}

Response

struct BlockHeaderResponse {
    block_header: Option<BlockHeader>,
}

block_height_by_hash

Get the height of the block with a given block hash.

let response: BlockHeightByHashResponse = client
    .block_height_by_hash(&BlockHeightByHashRequest { block_hash })
    .await
    .unwrap();

Request

struct BlockHeightByHashRequest {
    block_hash: CryptoHash,
}

Response

struct BlockHeightByHashResponse {
    block_hash: CryptoHash,
    block_height: Option<BlockHeight>,
}

block_hash_by_height

Get the hash of a block at a given height.

let response: BlockHashByHeightResponse = client
    .block_hash_by_height(&BlockHashByHeightRequest { block_height })
    .await
    .unwrap();

Request

struct BlockHashByHeightRequest {
    block_height: BlockHeight,
}

Response

struct BlockHashByHeightResponse {
    block_height: BlockHeight,
    block_hash: Option<CryptoHash>,
}

highest_committed_block

Get the hash of the highest committed block.

let response: HighestCommittedBlockResponse = client
    .highest_committed_block()
    .await
    .unwrap();

Request

None.

Response

struct HighestCommittedBlockResponse {
    block_hash: Option<CryptoHash>,
}

State RPCs return multiple entities in the world state in a single response. This allows clients to get a consistent snapshot of the world state in a single call.

Every response structure includes the hash of the highest committed block when the snapshot is taken.

Some of the following RPCs' response structures reference types unique to this document. These are specified in types referenced in state RPC responses.


state

Get the state of a set of accounts (optionally including their contract code), and/or a set of storage tuples.

let response: StateResponse = client
    .state(&StateRequest {
        accounts,
        include_contract,
        storage_keys,
    })
    .await
    .unwrap();

Request

struct StateRequest {
    accounts: HashSet<PublicAddress>,
    include_contracts: bool,
    storage_keys: HashMap<PublicAddress, HashSet<Vec<u8>>>,
}

Response

struct StateResponse {
    accounts: HashMap<PublicAddress, Account>,
    storage_tuples: HashMap<PublicAddress, HashMap<Vec<u8>, Vec<u8>>>,
    block_hash: CryptoHash,
}

validator_sets

Get the previous, current, and next validator sets, optionally including the stakes delegated to them.

 let response: ValidatorSetsResponse = client
    .validator_sets(&ValidatorSetsRequest {
        include_prev,
        include_prev_delegators,
        include_curr,
        include_curr_delegators,
        include_next,
        include_next_delegators,
    })
    .await
    .unwrap();

Request

struct ValidatorSetsRequest {
    include_prev: bool,
    include_prev_delegators: bool,
    include_curr: bool,
    include_curr_delegators: bool,
    include_next: bool,
    include_next_delegators: bool,
}

Response

struct ValidatorSetsResponse {
    // The inner Option is None if we are at Epoch 0.
    prev_validator_set: Option<Option<ValidatorSet>>,
    curr_validator_set: Option<ValidatorSet>,
    next_validator_set: Option<ValidatorSet>,
    block_hash: CryptoHash,
}

pools

Get a set of pools.

let response = client
    .pools(&PoolsRequest {
        include_stakes,
        operators,
    })
    .await
    .unwrap();

Request

struct PoolsRequest {
    operators: HashSet<Operator>,
    include_stakes: bool,
}

Response

struct PoolsResponse {
    pools: HashMap<Operator, Option<Pool>>,
    block_hash: CryptoHash,
}

deposits

Get a set of deposits.

let response: DepositsResponse = client
    .deposits(&DepositsRequest { stakes })
    .await
    .unwrap();

Request

struct DepositsRequest {
    stakes: HashSet<(Operator, Owner)>,
}

Response

struct DepositsResponse {
    deposits: HashMap<(Operator, Owner), Option<Deposit>>,
    block_hash: CryptoHash,
}

stakes

Get a set of stakes.

let response: StakesResponse = client
    .stakes(&StakesRequest { stakes })
    .await
    .unwrap();

Request

struct StakesRequest {
    stakes: HashSet<(Operator, Owner)>,
}

Response

struct StakesResponse {
    stakes: HashMap<(Operator, Owner), Option<Stake>>,
    block_hash: CryptoHash,
}

view

Call a method in a contract in a read-only way.

let response: ViewResponse = client
    .view(&ViewRequest {
        target,
        method,
        arguments,
    })
    .await
    .unwrap();

Request

struct ViewRequest {
    target: PublicAddress,
    method: Vec<u8>,
    arguments: Option<Vec<Vec<u8>>>,
}

Response

struct ViewResponse {
    receipt: CommandReceipt,
}

Types Referenced in State RPC Responses

enum Account {
    WithContract(AccountWithContract),
    WithoutContract(AccountWithoutContract),
}

struct AccountWithContract {
    nonce: Nonce,
    balance: Balance,
    contract: Option<Vec<u8>>, 
    cbi_version: Option<CBIVersion>,
    storage_hash: Option<CryptoHash>,
}

struct AccountWithoutContract {
    nonce: Nonce,
    balance: Balance,
    cbi_version: Option<CBIVersion>,
    storage_hash: Option<CryptoHash>,
}
enum ValidatorSet {
    WithDelegators(Vec<PoolWithDelegators>),
    WithoutDelegators(Vec<PoolWithoutDelegators>),
}

type Operator = PublicAddress;
type Owner = PublicAddress;

struct PoolWithDelegators {
    operator: PublicAddress,
    power: Balance,
    commission_rate: u8, 
    operator_stake: Option<Stake>,
    delegated_stakes: Vec<Stake>,
}

struct PoolWithoutDelegators {
    operator: PublicAddress,
    power: Balance,
    commission_rate: u8, 
    operator_stake: Stake,
}

struct Deposit {
    owner: PublicAddress,
    balance: u64,
    auto_stake_rewards: bool,
}

struct Stake {
    owner: PublicAddress,
    power: Balance,
}

enum Pool {
    WithStakes(PoolWithStakes),
    WithoutStakes(PoolWithoutStakes),
}