//! RPC API method handlers. use jsonrpsee::core::RpcResult; use jsonrpsee::proc_macros::rpc; use crate::types::*; /// Block-related RPC methods. #[rpc(server, client, namespace = "synor")] pub trait BlockApi { /// Gets a block by hash. #[method(name = "getBlock")] async fn get_block(&self, hash: String, include_txs: Option) -> RpcResult; /// Gets blocks by hashes. #[method(name = "getBlocks")] async fn get_blocks( &self, hashes: Vec, include_txs: Option, ) -> RpcResult>; /// Gets the current tips (DAG tips). #[method(name = "getTips")] async fn get_tips(&self) -> RpcResult>; /// Gets the virtual selected parent chain. #[method(name = "getVirtualChainFromBlock")] async fn get_virtual_chain_from_block( &self, start_hash: String, include_accepted_tx_ids: Option, ) -> RpcResult; /// Gets block count. #[method(name = "getBlockCount")] async fn get_block_count(&self) -> RpcResult; /// Gets block DAG info. #[method(name = "getBlockDagInfo")] async fn get_block_dag_info(&self) -> RpcResult; /// Gets headers between two blocks. #[method(name = "getHeaders")] async fn get_headers( &self, start_hash: String, limit: u64, is_ascending: bool, ) -> RpcResult>; /// Gets blocks by blue score. /// Returns blocks with blue score closest to the specified value. /// In a DAG, multiple blocks may exist at similar blue scores. #[method(name = "getBlocksByBlueScore")] async fn get_blocks_by_blue_score( &self, blue_score: u64, include_txs: Option, ) -> RpcResult>; } /// Virtual chain response. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct VirtualChainResponse { /// Removed chain block hashes. pub removed_chain_block_hashes: Vec, /// Added chain block hashes. pub added_chain_block_hashes: Vec, /// Accepted transaction IDs. pub accepted_transaction_ids: Vec, } /// Accepted transaction IDs for a block. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct AcceptedTransactionIds { /// Accepting block hash. pub accepting_block_hash: String, /// Accepted transaction IDs. pub accepted_transaction_ids: Vec, } /// Block count response. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlockCountResponse { /// Block count. pub block_count: u64, /// Header count. pub header_count: u64, } /// Transaction-related RPC methods. #[rpc(server, client, namespace = "synor")] pub trait TransactionApi { /// Submits a transaction. #[method(name = "submitTransaction")] async fn submit_transaction( &self, transaction: RpcTransaction, allow_orphan: Option, ) -> RpcResult; /// Gets a transaction by ID. #[method(name = "getTransaction")] async fn get_transaction(&self, tx_id: String) -> RpcResult; /// Gets mempool entries. #[method(name = "getMempoolEntries")] async fn get_mempool_entries( &self, include_orphan_pool: Option, filter_tx_in_addresses: Option, ) -> RpcResult>; /// Gets mempool entry by transaction ID. #[method(name = "getMempoolEntry")] async fn get_mempool_entry( &self, tx_id: String, include_orphan_pool: Option, ) -> RpcResult; /// Gets mempool entries by addresses. #[method(name = "getMempoolEntriesByAddresses")] async fn get_mempool_entries_by_addresses( &self, addresses: Vec, include_orphan_pool: Option, filter_tx_in_addresses: Option, ) -> RpcResult>; /// Estimates transaction fee. #[method(name = "estimateFee")] async fn estimate_fee(&self, transaction: RpcTransaction) -> RpcResult; /// Gets fee estimate buckets. #[method(name = "getFeeEstimate")] async fn get_fee_estimate(&self) -> RpcResult; } /// Mempool entries by address. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct MempoolEntriesByAddress { /// Address. pub address: String, /// Sending entries. pub sending: Vec, /// Receiving entries. pub receiving: Vec, } /// Submit transaction response. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct SubmitTransactionResponse { /// Transaction ID. pub transaction_id: String, } /// UTXO-related RPC methods. #[rpc(server, client, namespace = "synor")] pub trait UtxoApi { /// Gets UTXOs by addresses. #[method(name = "getUtxosByAddresses")] async fn get_utxos_by_addresses(&self, addresses: Vec) -> RpcResult>; /// Gets balance by address. #[method(name = "getBalanceByAddress")] async fn get_balance_by_address(&self, address: String) -> RpcResult; /// Gets balances by addresses. #[method(name = "getBalancesByAddresses")] async fn get_balances_by_addresses(&self, addresses: Vec) -> RpcResult>; /// Gets coin supply. #[method(name = "getCoinSupply")] async fn get_coin_supply(&self) -> RpcResult; } /// Mining-related RPC methods. #[rpc(server, client, namespace = "synor")] pub trait MiningApi { /// Gets a block template for mining. #[method(name = "getBlockTemplate")] async fn get_block_template( &self, pay_address: String, extra_data: Option, ) -> RpcResult; /// Submits a mined block. #[method(name = "submitBlock")] async fn submit_block( &self, request: RpcSubmitBlockRequest, ) -> RpcResult; /// Gets current network hashrate. #[method(name = "getNetworkHashrate")] async fn get_network_hashrate(&self) -> RpcResult; /// Gets current difficulty. #[method(name = "getDifficulty")] async fn get_difficulty(&self) -> RpcResult; } /// Network hashrate response. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct NetworkHashrateResponse { /// Network hashrate in H/s. pub hashrate: f64, /// Difficulty. pub difficulty: f64, /// Block rate (blocks per second). pub block_rate: f64, } /// Network-related RPC methods. #[rpc(server, client, namespace = "net")] pub trait NetworkApi { /// Gets network info. #[method(name = "getInfo")] async fn get_info(&self) -> RpcResult; /// Gets connected peer info. #[method(name = "getPeerInfo")] async fn get_peer_info(&self) -> RpcResult; /// Gets server info. #[method(name = "getServerInfo")] async fn get_server_info(&self) -> RpcResult; /// Adds a peer. #[method(name = "addPeer")] async fn add_peer(&self, address: String, is_permanent: Option) -> RpcResult; /// Bans a peer. #[method(name = "banPeer")] async fn ban_peer(&self, address: String) -> RpcResult; /// Unbans a peer. #[method(name = "unbanPeer")] async fn unban_peer(&self, address: String) -> RpcResult; /// Gets banned peer list. #[method(name = "getBannedPeers")] async fn get_banned_peers(&self) -> RpcResult>; /// Pings the server. #[method(name = "ping")] async fn ping(&self) -> RpcResult<()>; /// Shuts down the node. #[method(name = "shutdown")] async fn shutdown(&self) -> RpcResult<()>; } /// Banned peer info. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct BannedPeer { /// Peer address. pub address: String, /// Ban reason. pub reason: String, /// Ban time. pub ban_time: u64, /// Ban duration. pub ban_duration: u64, } /// Contract-related RPC methods. #[rpc(server, client, namespace = "contract")] pub trait ContractApi { /// Deploys a contract. #[method(name = "deploy")] async fn deploy(&self, request: DeployContractRequest) -> RpcResult; /// Calls a contract method. #[method(name = "call")] async fn call(&self, request: CallContractRequest) -> RpcResult; /// Estimates gas for a contract call. #[method(name = "estimateGas")] async fn estimate_gas(&self, request: CallContractRequest) -> RpcResult; /// Gets contract code. #[method(name = "getCode")] async fn get_code(&self, address: String) -> RpcResult; /// Gets contract storage value. #[method(name = "getStorageAt")] async fn get_storage_at(&self, address: String, key: String) -> RpcResult; } /// Deploy contract request. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct DeployContractRequest { /// Contract bytecode (hex). pub code: String, /// Constructor arguments (hex). pub args: Option, /// Initial value to send. pub value: Option, /// Gas limit. pub gas_limit: u64, /// Deployer address. pub from: String, } /// Deploy contract response. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct DeployContractResponse { /// Transaction ID. pub transaction_id: String, /// Contract address. pub contract_address: String, } /// Call contract request. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct CallContractRequest { /// Target contract address. pub to: String, /// Method to call. pub method: String, /// Arguments (hex). pub args: Option, /// Value to send. pub value: Option, /// Gas limit. pub gas_limit: Option, /// Caller address. pub from: Option, } /// Call contract response. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct CallContractResponse { /// Return data (hex). pub result: String, /// Gas used. pub gas_used: u64, /// Logs emitted. pub logs: Vec, } /// Contract log. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct ContractLog { /// Contract address. pub address: String, /// Log topics. pub topics: Vec, /// Log data (hex). pub data: String, } /// Subscription-related RPC methods (WebSocket only). #[rpc(server, client, namespace = "synor")] pub trait SubscriptionApi { /// Subscribes to new block headers. #[subscription(name = "subscribeNewBlockHeaders", item = RpcBlockHeader)] async fn subscribe_new_block_headers(&self) -> jsonrpsee::core::SubscriptionResult; /// Subscribes to virtual chain changes. #[subscription(name = "subscribeVirtualChainChanged", item = VirtualChainResponse)] async fn subscribe_virtual_chain_changed( &self, include_accepted_tx_ids: Option, ) -> jsonrpsee::core::SubscriptionResult; /// Subscribes to UTXO changes for addresses. #[subscription(name = "subscribeUtxosChanged", item = UtxosChangedNotification)] async fn subscribe_utxos_changed( &self, addresses: Vec, ) -> jsonrpsee::core::SubscriptionResult; /// Subscribes to virtual DAA score changes. #[subscription(name = "subscribeVirtualDaaScoreChanged", item = u64)] async fn subscribe_virtual_daa_score_changed(&self) -> jsonrpsee::core::SubscriptionResult; } /// UTXO change notification. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct UtxosChangedNotification { /// Added UTXOs. pub added: Vec, /// Removed UTXOs. pub removed: Vec, } #[cfg(test)] mod tests { use super::*; #[test] fn test_submit_response_serialization() { let response = SubmitTransactionResponse { transaction_id: "abc123".to_string(), }; let json = serde_json::to_string(&response).unwrap(); assert!(json.contains("transactionId")); } #[test] fn test_deploy_request() { let request = DeployContractRequest { code: "0x1234".to_string(), args: None, value: Some(1000), gas_limit: 100000, from: "synor:abc123".to_string(), }; let json = serde_json::to_string(&request).unwrap(); assert!(json.contains("gasLimit")); } }