use std::sync::Arc; use base64::Engine; use bitcoin::{Block, BlockHash}; use reqwest::{ header::{HeaderMap, AUTHORIZATION}, Client, }; use serde::Deserialize; use serde_json::json; #[derive(Clone)] pub struct BitcoinRpc { client: Arc, url: Arc, } impl BitcoinRpc { pub fn new(config: &crate::config::BitcoinRpc) -> Self { let client = Arc::new( reqwest::ClientBuilder::new() .default_headers({ let mut headers = HeaderMap::new(); headers.insert( AUTHORIZATION, format!( "Basic {}", base64::engine::general_purpose::STANDARD .encode(format!("{}:{}", config.username, config.password)) ) .parse() .unwrap(), ); headers }) .build() .unwrap(), ); Self { client, url: Arc::from(format!("http://{}", config.address)), } } pub async fn get_block_height(&self) -> u64 { self.client .post(&*self.url) .json(&json!({ "jsonrpc": "1.0", "id": 0, "method": "getblockcount", "params": [] })) .send() .await .unwrap() .json::>() .await .unwrap() .result } pub async fn get_block_hash(&self, height: u64) -> BlockHash { self.client .post(&*self.url) .json(&json!({ "jsonrpc": "1.0", "id": 0, "method": "getblockhash", "params": [height], })) .send() .await .unwrap() .json::>() .await .unwrap() .result } pub async fn get_block(&self, hash: &BlockHash) -> Block { let hash = hash.to_string(); let res = self .client .post(&*self.url) .json(&json!({ "jsonrpc": "1.0", "id": 0, "method": "getblock", "params": [hash, 0], })) .send() .await .unwrap() .json::>() .await .unwrap() .result; let bytes: Vec = bitcoin::hashes::hex::FromHex::from_hex(&res).unwrap(); bitcoin::consensus::encode::deserialize(&bytes).unwrap() } } #[derive(Deserialize)] #[allow(dead_code)] pub struct RpcResult { result: T, error: Option, id: u64, }