ckb-rpc 0.107.0

CKB RPC server.
Documentation
use ckb_jsonrpc_types::{AlertMessage, ChainInfo, DeploymentInfo, DeploymentPos, DeploymentsInfo};
use ckb_network_alert::notifier::Notifier as AlertNotifier;
use ckb_shared::shared::Shared;
use ckb_traits::HeaderProvider;
use ckb_types::prelude::Unpack;
use ckb_util::Mutex;
use jsonrpc_core::Result;
use jsonrpc_derive::rpc;
use std::collections::BTreeMap;
use std::sync::Arc;

/// RPC Module Stats for getting various statistic data.
#[rpc(server)]
pub trait StatsRpc {
    /// Returns statistics about the chain.
    ///
    /// ## Examples
    ///
    /// Request
    ///
    /// ```json
    /// {
    ///   "id": 42,
    ///   "jsonrpc": "2.0",
    ///   "method": "get_blockchain_info",
    ///   "params": []
    /// }
    /// ```
    ///
    /// Response
    ///
    /// ```json
    /// {
    ///   "id": 42,
    ///   "jsonrpc": "2.0",
    ///   "result": {
    ///     "alerts": [
    ///       {
    ///         "id": "0x2a",
    ///         "message": "An example alert message!",
    ///         "notice_until": "0x24bcca57c00",
    ///         "priority": "0x1"
    ///       }
    ///     ],
    ///     "chain": "ckb",
    ///     "difficulty": "0x1f4003",
    ///     "epoch": "0x7080018000001",
    ///     "is_initial_block_download": true,
    ///     "median_time": "0x5cd2b105"
    ///   }
    /// }
    /// ```
    #[rpc(name = "get_blockchain_info")]
    fn get_blockchain_info(&self) -> Result<ChainInfo>;

    /// Returns statistics about the chain.
    ///
    /// ## Examples
    ///
    /// Request
    ///
    /// ```json
    /// {
    ///   "id": 42,
    ///   "jsonrpc": "2.0",
    ///   "method": "get_deployments_info",
    ///   "params": []
    /// }
    /// ```
    ///
    /// Response
    ///
    /// ```json
    /// {
    ///   "id": 42,
    ///   "jsonrpc": "2.0",
    ///   "result": {
    ///     "epoch": "0x1",
    ///     "hash": "0xa5f5c85987a15de25661e5a214f2c1449cd803f071acc7999820f25246471f40",
    ///        "deployments": {
    ///            "Testdummy": {
    ///                "bit": 1,
    ///                "min_activation_epoch": "0x0",
    ///                "start": "0x0",
    ///                "state": "Failed",
    ///                "timeout": "0x0"
    ///            }
    ///        }
    ///   }
    /// }
    /// ```
    #[rpc(name = "get_deployments_info")]
    fn get_deployments_info(&self) -> Result<DeploymentsInfo>;
}

pub(crate) struct StatsRpcImpl {
    pub shared: Shared,
    pub alert_notifier: Arc<Mutex<AlertNotifier>>,
}

impl StatsRpc for StatsRpcImpl {
    fn get_blockchain_info(&self) -> Result<ChainInfo> {
        let chain = self.shared.consensus().id.clone();
        let (tip_header, median_time) = {
            let snapshot = self.shared.snapshot();
            let tip_header = snapshot.tip_header().clone();
            let median_time = snapshot.block_median_time(
                &tip_header.hash(),
                self.shared.consensus().median_time_block_count(),
            );
            (tip_header, median_time)
        };
        let epoch = if tip_header.is_genesis() {
            self.shared
                .consensus()
                .genesis_epoch_ext()
                .number_with_fraction(0)
        } else {
            tip_header.epoch()
        };
        let difficulty = tip_header.difficulty();
        let is_initial_block_download = self.shared.is_initial_block_download();
        let alerts: Vec<AlertMessage> = {
            let now = faketime::unix_time_as_millis();
            let mut notifier = self.alert_notifier.lock();
            notifier.clear_expired_alerts(now);
            notifier
                .noticed_alerts()
                .into_iter()
                .map(Into::into)
                .collect()
        };

        Ok(ChainInfo {
            chain,
            median_time: median_time.into(),
            epoch: epoch.into(),
            difficulty,
            is_initial_block_download,
            alerts,
        })
    }

    fn get_deployments_info(&self) -> Result<DeploymentsInfo> {
        let snapshot = self.shared.snapshot();
        let deployments: BTreeMap<DeploymentPos, DeploymentInfo> = self
            .shared
            .consensus()
            .deployments
            .clone()
            .into_iter()
            .filter_map(|(pos, deployment)| {
                self.shared
                    .consensus()
                    .versionbits_state(pos, snapshot.tip_header(), snapshot.as_ref())
                    .map(|state| {
                        let mut info: DeploymentInfo = deployment.into();
                        info.state = state.into();
                        (pos.into(), info)
                    })
            })
            .collect();

        Ok(DeploymentsInfo {
            hash: snapshot.tip_hash().unpack(),
            epoch: snapshot.tip_header().epoch().number().into(),
            deployments,
        })
    }
}