433 lines
13 KiB
Rust
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"));
|
|
}
|
|
}
|