rialo-cdk 0.2.0-alpha.0

Rialo CDK - A comprehensive toolkit for building with the Rialo blockchain
Documentation
// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Client context for simplified RPC interaction.
//!
//! Provides a convenience wrapper that implements RpcClient for use
//! in benchmarks and tests without the full CLI configuration overhead.

use crate::rpc::{client::HttpRpcClient, traits::RpcClient, types::*};

/// A simplified client context for benchmark and test usage.
///
/// This struct wraps an HttpRpcClient and provides a simple interface
/// for RPC operations without requiring full configuration management.
/// It's designed for use cases where you just need basic RPC functionality
/// without the complexity of the full CLI client context.
///
/// # Example
///
/// ```no_run
/// use rialo_cdk::ClientContext;
/// use rialo_cdk::RpcClient as _;
///
/// #[tokio::main]
/// async fn main() -> rialo_cdk::Result<()> {
///     let url = "http://127.0.0.1:4104".to_string();
///     let context = ClientContext::new(url);
///     
///     // Use it as an RpcClient
///     let block_height = context.get_block_height().await?;
///     println!("Block height: {}", block_height);
///     
///     Ok(())
/// }
/// ```
pub struct ClientContext {
    http_client: HttpRpcClient,
}

impl ClientContext {
    /// Creates a new ClientContext with the given RPC URL.
    ///
    /// # Arguments
    ///
    /// * `json_rpc_url` - The URL of the RPC endpoint to connect to (as a String)
    ///
    /// # Example
    ///
    /// ```no_run
    /// use rialo_cdk::ClientContext;
    ///
    /// let url = "http://127.0.0.1:4104".to_string();
    /// let context = ClientContext::new(url);
    /// ```
    pub fn new(json_rpc_url: String) -> Self {
        let http_client = HttpRpcClient::new(json_rpc_url);
        Self { http_client }
    }

    /// Creates a new ClientContext for benchmarks.
    ///
    /// This is a convenience method that creates a minimal context
    /// suitable for benchmark usage. It's functionally identical to `new()`,
    /// but the name makes the intent clearer in benchmark code.
    ///
    /// # Arguments
    ///
    /// * `json_rpc_url` - The URL of the RPC endpoint to connect to (as a String)
    ///
    /// # Example
    ///
    /// ```no_run
    /// use rialo_cdk::ClientContext;
    ///
    /// let url = "http://127.0.0.1:4104".to_string();
    /// let context = ClientContext::new_for_benchmarks(url);
    /// ```
    pub fn new_for_benchmarks(json_rpc_url: String) -> Self {
        Self::new(json_rpc_url)
    }

    /// Returns a reference to the underlying HTTP client.
    ///
    /// This can be useful if you need direct access to the HttpRpcClient's
    /// specific functionality beyond what the RpcClient trait provides.
    pub fn http_client(&self) -> &HttpRpcClient {
        &self.http_client
    }
}

// Implement RpcClient by delegating all methods to the inner HttpRpcClient
#[async_trait::async_trait]
impl RpcClient for ClientContext {
    async fn call_with_json(
        &self,
        method: &str,
        params: serde_json::Value,
    ) -> crate::error::Result<serde_json::Value> {
        self.http_client.call_with_json(method, params).await
    }

    async fn get_balance(&self, pubkey: &Pubkey) -> crate::error::Result<u64> {
        self.http_client.get_balance(pubkey).await
    }

    async fn send_transaction(
        &self,
        transaction: &[u8],
        options: Option<SendTransactionOptions>,
    ) -> crate::error::Result<Signature> {
        self.http_client
            .send_transaction(transaction, options)
            .await
    }

    async fn get_secret_sharing_pubkey(
        &self,
    ) -> crate::error::Result<GetSecretSharingPubkeyResponse> {
        self.http_client.get_secret_sharing_pubkey().await
    }

    async fn send_admin_transaction(
        &self,
        params: SubmitEpochChangeRequest,
    ) -> crate::error::Result<SubmitEpochChangeResponse> {
        self.http_client.send_admin_transaction(params).await
    }

    async fn get_account_info(&self, pubkey: &Pubkey) -> crate::error::Result<AccountInfo> {
        self.http_client.get_account_info(pubkey).await
    }

    async fn get_block_height(&self) -> crate::error::Result<u64> {
        self.http_client.get_block_height().await
    }

    async fn get_block_height_with_config(
        &self,
        min_context_slot: Option<u64>,
    ) -> crate::error::Result<u64> {
        self.http_client
            .get_block_height_with_config(min_context_slot)
            .await
    }

    async fn get_transaction(
        &self,
        signature: &Signature,
    ) -> crate::error::Result<TransactionResponse> {
        self.http_client.get_transaction(signature).await
    }

    async fn get_transaction_count(&self) -> crate::error::Result<u64> {
        self.http_client.get_transaction_count().await
    }

    async fn get_minimum_balance_for_rent_exemption(&self, size: u64) -> crate::error::Result<u64> {
        self.http_client
            .get_minimum_balance_for_rent_exemption(size)
            .await
    }

    async fn get_signature_statuses(
        &self,
        signatures: &[Signature],
    ) -> crate::error::Result<Vec<SignatureStatus>> {
        self.http_client.get_signature_statuses(signatures).await
    }

    async fn get_subscription(
        &self,
        subscriber: &Pubkey,
        nonce: &str,
    ) -> crate::error::Result<GetSubscriptionResponse> {
        self.http_client.get_subscription(subscriber, nonce).await
    }

    async fn get_triggered_transactions(
        &self,
        subscription_account: &Pubkey,
        limit: Option<u32>,
    ) -> crate::error::Result<GetTriggeredTransactionsResponse> {
        self.http_client
            .get_triggered_transactions(subscription_account, limit)
            .await
    }

    async fn get_workflow_lineage(
        &self,
        request: &GetWorkflowLineageRequest,
    ) -> crate::error::Result<GetWorkflowLineageResponse> {
        self.http_client.get_workflow_lineage(request).await
    }

    async fn request_airdrop(
        &self,
        pubkey: &Pubkey,
        amount: u64,
    ) -> crate::error::Result<Signature> {
        self.http_client.request_airdrop(pubkey, amount).await
    }

    async fn get_epoch_info(&self) -> crate::error::Result<EpochInfoResponse> {
        self.http_client.get_epoch_info().await
    }

    async fn get_fee_for_message(
        &self,
        message: &str,
    ) -> crate::error::Result<GetFeeForMessageResponse> {
        self.http_client.get_fee_for_message(message).await
    }

    async fn get_multiple_accounts(
        &self,
        pubkeys: &[Pubkey],
    ) -> crate::error::Result<MultipleAccountsResponse> {
        self.http_client.get_multiple_accounts(pubkeys).await
    }

    async fn get_signatures_for_address(
        &self,
        address: &Pubkey,
        config: Option<GetSignaturesForAddressConfig>,
    ) -> crate::error::Result<GetSignaturesForAddressResponse> {
        self.http_client
            .get_signatures_for_address(address, config)
            .await
    }

    async fn is_blockhash_valid(
        &self,
        blockhash: &Hash,
    ) -> crate::error::Result<IsBlockhashValidResponse> {
        self.http_client.is_blockhash_valid(blockhash).await
    }

    async fn get_health(&self) -> crate::error::Result<GetHealthResponse> {
        self.http_client.get_health().await
    }

    async fn get_validator_health(&self) -> crate::error::Result<GetValidatorHealthResponse> {
        self.http_client.get_validator_health().await
    }

    async fn get_connected_full_nodes(
        &self,
    ) -> crate::error::Result<GetConnectedFullNodesResponse> {
        self.http_client.get_connected_full_nodes().await
    }

    async fn get_transactions(
        &self,
        config: Option<GetTransactionsConfig>,
    ) -> crate::error::Result<GetTransactionsResponse> {
        self.http_client.get_transactions(config).await
    }

    async fn get_accounts_by_owner(
        &self,
        owner: &Pubkey,
    ) -> crate::error::Result<GetAccountsByOwnerResponse> {
        self.http_client.get_accounts_by_owner(owner).await
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_client_context_creation() {
        let url = "http://127.0.0.1:4104".to_string();
        let _context = ClientContext::new(url);
    }

    #[test]
    fn test_client_context_for_benchmarks() {
        let url = "http://127.0.0.1:4104".to_string();
        let _context = ClientContext::new_for_benchmarks(url);
    }

    #[tokio::test]
    async fn test_client_context_implements_rpc_client() {
        // This test just verifies that ClientContext implements RpcClient
        // We'll use a real context for testing
        let url = "http://127.0.0.1:4104".to_string();
        let context = ClientContext::new(url);
        let _ = context.get_block_height().await;
    }
}