use super::RpcHandler; use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] struct BitcoinInfo { block_height: u64, sync_progress: f64, chain: String, difficulty: f64, mempool_size: u64, mempool_tx_count: u64, verification_progress: f64, } #[derive(Debug, Deserialize)] struct BitcoinRpcResponse { result: Option, error: Option, } #[derive(Debug, Deserialize)] struct BlockchainInfo { chain: Option, blocks: Option, difficulty: Option, #[serde(rename = "verificationprogress")] verification_progress: Option, } #[derive(Debug, Deserialize)] struct MempoolInfo { size: Option, bytes: Option, } impl RpcHandler { pub(super) async fn handle_bitcoin_getinfo(&self) -> Result { let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(10)) .build() .context("Failed to create HTTP client")?; let blockchain_info = self .bitcoin_rpc_call::(&client, "getblockchaininfo", &[]) .await .context("Failed to query getblockchaininfo")?; let mempool_info = self .bitcoin_rpc_call::(&client, "getmempoolinfo", &[]) .await .unwrap_or(MempoolInfo { size: Some(0), bytes: Some(0), }); let info = BitcoinInfo { block_height: blockchain_info.blocks.unwrap_or(0), sync_progress: blockchain_info .verification_progress .unwrap_or(0.0), chain: blockchain_info.chain.unwrap_or_else(|| "unknown".into()), difficulty: blockchain_info.difficulty.unwrap_or(0.0), mempool_size: mempool_info.bytes.unwrap_or(0), mempool_tx_count: mempool_info.size.unwrap_or(0), verification_progress: blockchain_info .verification_progress .unwrap_or(0.0), }; Ok(serde_json::to_value(info)?) } async fn bitcoin_rpc_call( &self, client: &reqwest::Client, method: &str, params: &[serde_json::Value], ) -> Result { let body = serde_json::json!({ "jsonrpc": "1.0", "id": "archy", "method": method, "params": params, }); let resp = client .post("http://127.0.0.1:8332/") .basic_auth("archipelago", Some("archipelago123")) .json(&body) .send() .await .context("Bitcoin RPC connection failed")?; let rpc_resp: BitcoinRpcResponse = resp .json() .await .context("Failed to parse Bitcoin RPC response")?; if let Some(err) = rpc_resp.error { anyhow::bail!("Bitcoin RPC error: {}", err); } rpc_resp .result .ok_or_else(|| anyhow::anyhow!("Bitcoin RPC returned null result")) } }