synor/crates/synor-rpc/src/api.rs
2026-01-08 05:22:24 +05:30

433 lines
13 KiB
Rust

//! 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<bool>) -> RpcResult<RpcBlock>;
/// Gets blocks by hashes.
#[method(name = "getBlocks")]
async fn get_blocks(
&self,
hashes: Vec<String>,
include_txs: Option<bool>,
) -> RpcResult<Vec<RpcBlock>>;
/// Gets the current tips (DAG tips).
#[method(name = "getTips")]
async fn get_tips(&self) -> RpcResult<Vec<String>>;
/// 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<bool>,
) -> RpcResult<VirtualChainResponse>;
/// Gets block count.
#[method(name = "getBlockCount")]
async fn get_block_count(&self) -> RpcResult<BlockCountResponse>;
/// Gets block DAG info.
#[method(name = "getBlockDagInfo")]
async fn get_block_dag_info(&self) -> RpcResult<RpcDagInfo>;
/// Gets headers between two blocks.
#[method(name = "getHeaders")]
async fn get_headers(
&self,
start_hash: String,
limit: u64,
is_ascending: bool,
) -> RpcResult<Vec<RpcBlockHeader>>;
/// 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<bool>,
) -> RpcResult<Vec<RpcBlock>>;
}
/// 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<String>,
/// Added chain block hashes.
pub added_chain_block_hashes: Vec<String>,
/// Accepted transaction IDs.
pub accepted_transaction_ids: Vec<AcceptedTransactionIds>,
}
/// 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<String>,
}
/// 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<bool>,
) -> RpcResult<SubmitTransactionResponse>;
/// Gets a transaction by ID.
#[method(name = "getTransaction")]
async fn get_transaction(&self, tx_id: String) -> RpcResult<RpcTransaction>;
/// Gets mempool entries.
#[method(name = "getMempoolEntries")]
async fn get_mempool_entries(
&self,
include_orphan_pool: Option<bool>,
filter_tx_in_addresses: Option<bool>,
) -> RpcResult<Vec<RpcMempoolEntry>>;
/// Gets mempool entry by transaction ID.
#[method(name = "getMempoolEntry")]
async fn get_mempool_entry(
&self,
tx_id: String,
include_orphan_pool: Option<bool>,
) -> RpcResult<RpcMempoolEntry>;
/// Gets mempool entries by addresses.
#[method(name = "getMempoolEntriesByAddresses")]
async fn get_mempool_entries_by_addresses(
&self,
addresses: Vec<String>,
include_orphan_pool: Option<bool>,
filter_tx_in_addresses: Option<bool>,
) -> RpcResult<Vec<MempoolEntriesByAddress>>;
/// Estimates transaction fee.
#[method(name = "estimateFee")]
async fn estimate_fee(&self, transaction: RpcTransaction) -> RpcResult<u64>;
/// Gets fee estimate buckets.
#[method(name = "getFeeEstimate")]
async fn get_fee_estimate(&self) -> RpcResult<RpcFeeEstimate>;
}
/// 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<RpcMempoolEntry>,
/// Receiving entries.
pub receiving: Vec<RpcMempoolEntry>,
}
/// 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<String>) -> RpcResult<Vec<RpcUtxo>>;
/// Gets balance by address.
#[method(name = "getBalanceByAddress")]
async fn get_balance_by_address(&self, address: String) -> RpcResult<RpcBalance>;
/// Gets balances by addresses.
#[method(name = "getBalancesByAddresses")]
async fn get_balances_by_addresses(&self, addresses: Vec<String>)
-> RpcResult<Vec<RpcBalance>>;
/// Gets coin supply.
#[method(name = "getCoinSupply")]
async fn get_coin_supply(&self) -> RpcResult<RpcCoinSupply>;
}
/// 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<String>,
) -> RpcResult<RpcBlockTemplate>;
/// Submits a mined block.
#[method(name = "submitBlock")]
async fn submit_block(
&self,
request: RpcSubmitBlockRequest,
) -> RpcResult<RpcSubmitBlockResponse>;
/// Gets current network hashrate.
#[method(name = "getNetworkHashrate")]
async fn get_network_hashrate(&self) -> RpcResult<NetworkHashrateResponse>;
/// Gets current difficulty.
#[method(name = "getDifficulty")]
async fn get_difficulty(&self) -> RpcResult<f64>;
}
/// 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<RpcNetworkInfo>;
/// Gets connected peer info.
#[method(name = "getPeerInfo")]
async fn get_peer_info(&self) -> RpcResult<RpcConnectedPeers>;
/// Gets server info.
#[method(name = "getServerInfo")]
async fn get_server_info(&self) -> RpcResult<RpcServerInfo>;
/// Adds a peer.
#[method(name = "addPeer")]
async fn add_peer(&self, address: String, is_permanent: Option<bool>) -> RpcResult<bool>;
/// Bans a peer.
#[method(name = "banPeer")]
async fn ban_peer(&self, address: String) -> RpcResult<bool>;
/// Unbans a peer.
#[method(name = "unbanPeer")]
async fn unban_peer(&self, address: String) -> RpcResult<bool>;
/// Gets banned peer list.
#[method(name = "getBannedPeers")]
async fn get_banned_peers(&self) -> RpcResult<Vec<BannedPeer>>;
/// 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<DeployContractResponse>;
/// Calls a contract method.
#[method(name = "call")]
async fn call(&self, request: CallContractRequest) -> RpcResult<CallContractResponse>;
/// Estimates gas for a contract call.
#[method(name = "estimateGas")]
async fn estimate_gas(&self, request: CallContractRequest) -> RpcResult<u64>;
/// Gets contract code.
#[method(name = "getCode")]
async fn get_code(&self, address: String) -> RpcResult<String>;
/// Gets contract storage value.
#[method(name = "getStorageAt")]
async fn get_storage_at(&self, address: String, key: String) -> RpcResult<String>;
}
/// 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<String>,
/// Initial value to send.
pub value: Option<u64>,
/// 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<String>,
/// Value to send.
pub value: Option<u64>,
/// Gas limit.
pub gas_limit: Option<u64>,
/// Caller address.
pub from: Option<String>,
}
/// 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<ContractLog>,
}
/// 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<String>,
/// 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<bool>,
) -> jsonrpsee::core::SubscriptionResult;
/// Subscribes to UTXO changes for addresses.
#[subscription(name = "subscribeUtxosChanged", item = UtxosChangedNotification)]
async fn subscribe_utxos_changed(
&self,
addresses: Vec<String>,
) -> 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<RpcUtxo>,
/// Removed UTXOs.
pub removed: Vec<RpcOutpoint>,
}
#[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"));
}
}