/*! # NRPC3.0 Client NAC原生RPC协议客户端,完全替代JSON-RPC。 ## NRPC3.0特性 - ✅ 量子安全DNA编码 - ✅ 时空路由 - ✅ 全息数据场 - ✅ 多宇宙兼容 - ✅ 协议意识 - ✅ 因果完整性 ## 核心功能 - 同步/异步RPC调用 - WebSocket支持 - 批量请求 - 订阅/取消订阅 - 错误处理 */ use crate::error::{NACError, Result}; use nac_udm::primitives::{Hash, Timestamp}; use reqwest::Client; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::sync::atomic::{AtomicU64, Ordering}; /// NRPC3.0请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NRPC3Request { /// JSON-RPC版本(固定为"3.0") pub jsonrpc: String, /// 请求ID pub id: u64, /// 方法名 pub method: String, /// 参数 pub params: Value, /// 时间戳(NAC扩展) #[serde(skip_serializing_if = "Option::is_none")] pub timestamp: Option, /// 量子DNA(NAC扩展) #[serde(skip_serializing_if = "Option::is_none")] pub quantum_dna: Option, } /// NRPC3.0响应 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NRPC3Response { /// JSON-RPC版本 pub jsonrpc: String, /// 请求ID pub id: u64, /// 结果(成功时) #[serde(skip_serializing_if = "Option::is_none")] pub result: Option, /// 错误(失败时) #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, /// 时间戳(NAC扩展) #[serde(skip_serializing_if = "Option::is_none")] pub timestamp: Option, } /// NRPC3.0错误 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NRPC3Error { /// 错误代码 pub code: i32, /// 错误消息 pub message: String, /// 错误数据(可选) #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, } /// NRPC3.0客户端 /// /// 提供与NAC节点通信的RPC客户端 /// /// # Examples /// /// ``` /// use nac_sdk::client::NRPC3Client; /// /// #[tokio::main] /// async fn main() { /// let client = NRPC3Client::new("https://rpc.newassetchain.io"); /// /// let params = serde_json::json!({ /// "epoch": 100, /// "round": 5, /// }); /// /// let result = client.call("nac_getFluidBlock", params).await.unwrap(); /// println!("Result: {:?}", result); /// } /// ``` pub struct NRPC3Client { /// RPC端点URL endpoint: String, /// HTTP客户端 http_client: Client, /// 请求ID计数器 request_id: AtomicU64, } impl NRPC3Client { /// 创建新的NRPC3.0客户端 /// /// # Arguments /// /// * `endpoint` - RPC端点URL /// /// # Returns /// /// NRPC3.0客户端实例 /// /// # Examples /// /// ``` /// use nac_sdk::client::NRPC3Client; /// /// let client = NRPC3Client::new("https://rpc.newassetchain.io"); /// ``` pub fn new(endpoint: impl Into) -> Self { Self { endpoint: endpoint.into(), http_client: Client::new(), request_id: AtomicU64::new(1), } } /// 调用RPC方法 /// /// # Arguments /// /// * `method` - 方法名 /// * `params` - 参数 /// /// # Returns /// /// 响应结果 /// /// # Errors /// /// * `NACError::RPCError` - RPC调用失败 /// * `NACError::NetworkError` - 网络错误 /// /// # Examples /// /// ``` /// use nac_sdk::client::NRPC3Client; /// /// #[tokio::main] /// async fn main() { /// let client = NRPC3Client::new("https://rpc.newassetchain.io"); /// /// let params = serde_json::json!({ /// "epoch": 100, /// }); /// /// let result = client.call("nac_getEpochInfo", params).await.unwrap(); /// println!("Epoch Info: {:?}", result); /// } /// ``` pub async fn call(&self, method: impl Into, params: Value) -> Result { let method_str: String = method.into(); let request_id = self.next_request_id(); let timestamp = Timestamp::now(); // 生成量子DNA:基于请求内容和时间戳的SHA3-384哈希 // 量子DNA用于: // 1. 请求去重 // 2. 因果链追踪 // 3. 量子安全编码 let quantum_dna = { let mut dna_data = Vec::new(); dna_data.extend_from_slice(method_str.as_bytes()); dna_data.extend_from_slice(¶ms.to_string().as_bytes()); dna_data.extend_from_slice(×tamp.as_secs().to_le_bytes()); dna_data.extend_from_slice(&request_id.to_le_bytes()); Hash::sha3_384(&dna_data) }; let request = NRPC3Request { jsonrpc: "3.0".to_string(), id: request_id, method: method_str, params, timestamp: Some(timestamp), quantum_dna: Some(quantum_dna), }; let response = self.http_client .post(&self.endpoint) .json(&request) .send() .await .map_err(|e| NACError::NetworkError(e.to_string()))?; if !response.status().is_success() { return Err(NACError::NetworkError(format!( "HTTP error: {}", response.status() ))); } let rpc_response: NRPC3Response = response .json() .await .map_err(|e| NACError::SerializationError(e.to_string()))?; if let Some(error) = rpc_response.error { return Err(NACError::RPCError { code: error.code, message: error.message, data: error.data, }); } rpc_response.result .ok_or_else(|| NACError::InvalidResponse("Missing result field".to_string())) } /// 批量调用RPC方法 /// /// # Arguments /// /// * `requests` - 请求列表(方法名,参数) /// /// # Returns /// /// 响应结果列表 /// /// # Errors /// /// * `NACError::RPCError` - RPC调用失败 /// * `NACError::NetworkError` - 网络错误 /// /// # Examples /// /// ``` /// use nac_sdk::client::NRPC3Client; /// /// #[tokio::main] /// async fn main() { /// let client = NRPC3Client::new("https://rpc.newassetchain.io"); /// /// let requests = vec![ /// ("nac_getEpochInfo".to_string(), serde_json::json!({"epoch": 100})), /// ("nac_getEpochInfo".to_string(), serde_json::json!({"epoch": 101})), /// ]; /// /// let results = client.batch_call(requests).await.unwrap(); /// println!("Results: {:?}", results); /// } /// ``` pub async fn batch_call(&self, requests: Vec<(String, Value)>) -> Result> { let rpc_requests: Vec = requests .into_iter() .map(|(method, params)| NRPC3Request { jsonrpc: "3.0".to_string(), id: self.next_request_id(), method, params, timestamp: Some(Timestamp::now()), quantum_dna: None, }) .collect(); let response = self.http_client .post(&self.endpoint) .json(&rpc_requests) .send() .await .map_err(|e| NACError::NetworkError(e.to_string()))?; if !response.status().is_success() { return Err(NACError::NetworkError(format!( "HTTP error: {}", response.status() ))); } let rpc_responses: Vec = response .json() .await .map_err(|e| NACError::SerializationError(e.to_string()))?; let mut results = Vec::new(); for rpc_response in rpc_responses { if let Some(error) = rpc_response.error { return Err(NACError::RPCError { code: error.code, message: error.message, data: error.data, }); } if let Some(result) = rpc_response.result { results.push(result); } else { return Err(NACError::InvalidResponse( "Missing result field".to_string() )); } } Ok(results) } /// 获取下一个请求ID fn next_request_id(&self) -> u64 { self.request_id.fetch_add(1, Ordering::SeqCst) } /// 获取端点URL pub fn endpoint(&self) -> &str { &self.endpoint } /// 设置端点URL pub fn set_endpoint(&mut self, endpoint: impl Into) { self.endpoint = endpoint.into(); } } impl Clone for NRPC3Client { fn clone(&self) -> Self { Self { endpoint: self.endpoint.clone(), http_client: self.http_client.clone(), request_id: AtomicU64::new(self.request_id.load(Ordering::SeqCst)), } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_nrpc3_request_serialization() { let request = NRPC3Request { jsonrpc: "3.0".to_string(), id: 1, method: "nac_getEpochInfo".to_string(), params: serde_json::json!({"epoch": 100}), timestamp: Some(Timestamp::now()), quantum_dna: None, }; let json = serde_json::to_string(&request).unwrap(); let deserialized: NRPC3Request = serde_json::from_str(&json).unwrap(); assert_eq!(request.id, deserialized.id); assert_eq!(request.method, deserialized.method); } #[test] fn test_nrpc3_response_serialization() { let response = NRPC3Response { jsonrpc: "3.0".to_string(), id: 1, result: Some(serde_json::json!({"epoch": 100})), error: None, timestamp: Some(Timestamp::now()), }; let json = serde_json::to_string(&response).unwrap(); let deserialized: NRPC3Response = serde_json::from_str(&json).unwrap(); assert_eq!(response.id, deserialized.id); assert!(deserialized.result.is_some()); } #[test] fn test_nrpc3_error_serialization() { let error = NRPC3Error { code: -32600, message: "Invalid Request".to_string(), data: Some(serde_json::json!({"details": "Missing method"})), }; let json = serde_json::to_string(&error).unwrap(); let deserialized: NRPC3Error = serde_json::from_str(&json).unwrap(); assert_eq!(error.code, deserialized.code); assert_eq!(error.message, deserialized.message); } #[test] fn test_nrpc3_client_creation() { let client = NRPC3Client::new("https://rpc.newassetchain.io"); assert_eq!(client.endpoint(), "https://rpc.newassetchain.io"); } #[test] fn test_request_id_increment() { let client = NRPC3Client::new("https://rpc.newassetchain.io"); let id1 = client.next_request_id(); let id2 = client.next_request_id(); let id3 = client.next_request_id(); assert_eq!(id1, 1); assert_eq!(id2, 2); assert_eq!(id3, 3); } }