kaspa_rpc_core/api/
rpc.rs

1//!
2//! The main [`RpcApi`] trait that defines all RPC methods available in the Rusty Kaspa p2p node.
3//!
4//! Rpc = External RPC Service
5//! All data provided by the RPC server can be trusted by the client
6//! No data submitted by the client to the node can be trusted
7//!
8
9use crate::api::connection::DynRpcConnection;
10use crate::{model::*, notify::connection::ChannelConnection, RpcResult};
11use async_trait::async_trait;
12use downcast::{downcast_sync, AnySync};
13use kaspa_notify::{listener::ListenerId, scope::Scope, subscription::Command};
14use std::sync::Arc;
15
16pub const MAX_SAFE_WINDOW_SIZE: u32 = 10_000;
17
18/// Client RPC Api
19///
20/// The [`RpcApi`] trait defines RPC calls taking a request message as unique parameter.
21///
22/// For each RPC call a matching readily implemented function taking detailed parameters is also provided.
23#[async_trait]
24pub trait RpcApi: Sync + Send + AnySync {
25    ///
26    async fn ping(&self) -> RpcResult<()> {
27        self.ping_call(None, PingRequest {}).await?;
28        Ok(())
29    }
30    async fn ping_call(&self, connection: Option<&DynRpcConnection>, request: PingRequest) -> RpcResult<PingResponse>;
31
32    // ---
33
34    async fn get_system_info(&self) -> RpcResult<GetSystemInfoResponse> {
35        Ok(self.get_system_info_call(None, GetSystemInfoRequest {}).await?)
36    }
37    async fn get_system_info_call(
38        &self,
39        connection: Option<&DynRpcConnection>,
40        request: GetSystemInfoRequest,
41    ) -> RpcResult<GetSystemInfoResponse>;
42
43    // ---
44
45    async fn get_connections(&self, include_profile_data: bool) -> RpcResult<GetConnectionsResponse> {
46        self.get_connections_call(None, GetConnectionsRequest { include_profile_data }).await
47    }
48    async fn get_connections_call(
49        &self,
50        connection: Option<&DynRpcConnection>,
51        request: GetConnectionsRequest,
52    ) -> RpcResult<GetConnectionsResponse>;
53
54    // ---
55
56    async fn get_metrics(
57        &self,
58        process_metrics: bool,
59        connection_metrics: bool,
60        bandwidth_metrics: bool,
61        consensus_metrics: bool,
62        storage_metrics: bool,
63        custom_metrics: bool,
64    ) -> RpcResult<GetMetricsResponse> {
65        self.get_metrics_call(
66            None,
67            GetMetricsRequest {
68                process_metrics,
69                connection_metrics,
70                bandwidth_metrics,
71                consensus_metrics,
72                storage_metrics,
73                custom_metrics,
74            },
75        )
76        .await
77    }
78    async fn get_metrics_call(
79        &self,
80        connection: Option<&DynRpcConnection>,
81        request: GetMetricsRequest,
82    ) -> RpcResult<GetMetricsResponse>;
83
84    // get_info alternative that carries only version, network_id (full), is_synced, virtual_daa_score
85    // these are the only variables needed to negotiate a wRPC connection (besides the wRPC handshake)
86    async fn get_server_info(&self) -> RpcResult<GetServerInfoResponse> {
87        self.get_server_info_call(None, GetServerInfoRequest {}).await
88    }
89    async fn get_server_info_call(
90        &self,
91        connection: Option<&DynRpcConnection>,
92        request: GetServerInfoRequest,
93    ) -> RpcResult<GetServerInfoResponse>;
94
95    // Get current sync status of the node (should be converted to a notification subscription)
96    async fn get_sync_status(&self) -> RpcResult<bool> {
97        Ok(self.get_sync_status_call(None, GetSyncStatusRequest {}).await?.is_synced)
98    }
99    async fn get_sync_status_call(
100        &self,
101        connection: Option<&DynRpcConnection>,
102        request: GetSyncStatusRequest,
103    ) -> RpcResult<GetSyncStatusResponse>;
104
105    // ---
106
107    /// Requests the network the node is currently running against.
108    async fn get_current_network(&self) -> RpcResult<RpcNetworkType> {
109        Ok(self.get_current_network_call(None, GetCurrentNetworkRequest {}).await?.network)
110    }
111    async fn get_current_network_call(
112        &self,
113        connection: Option<&DynRpcConnection>,
114        request: GetCurrentNetworkRequest,
115    ) -> RpcResult<GetCurrentNetworkResponse>;
116
117    /// Submit a block into the DAG.
118    ///
119    /// Blocks are generally expected to have been generated using the get_block_template call.
120    async fn submit_block(&self, block: RpcRawBlock, allow_non_daa_blocks: bool) -> RpcResult<SubmitBlockResponse> {
121        self.submit_block_call(None, SubmitBlockRequest::new(block, allow_non_daa_blocks)).await
122    }
123    async fn submit_block_call(
124        &self,
125        connection: Option<&DynRpcConnection>,
126        request: SubmitBlockRequest,
127    ) -> RpcResult<SubmitBlockResponse>;
128
129    /// Request a current block template.
130    ///
131    /// Callers are expected to solve the block template and submit it using the submit_block call.
132    async fn get_block_template(&self, pay_address: RpcAddress, extra_data: RpcExtraData) -> RpcResult<GetBlockTemplateResponse> {
133        self.get_block_template_call(None, GetBlockTemplateRequest::new(pay_address, extra_data)).await
134    }
135    async fn get_block_template_call(
136        &self,
137        connection: Option<&DynRpcConnection>,
138        request: GetBlockTemplateRequest,
139    ) -> RpcResult<GetBlockTemplateResponse>;
140
141    /// Requests the list of known kaspad addresses in the current network (mainnet, testnet, etc.)
142    async fn get_peer_addresses(&self) -> RpcResult<GetPeerAddressesResponse> {
143        self.get_peer_addresses_call(None, GetPeerAddressesRequest {}).await
144    }
145    async fn get_peer_addresses_call(
146        &self,
147        connection: Option<&DynRpcConnection>,
148        request: GetPeerAddressesRequest,
149    ) -> RpcResult<GetPeerAddressesResponse>;
150
151    /// requests the hash of the current virtual's selected parent.
152    async fn get_sink(&self) -> RpcResult<GetSinkResponse> {
153        self.get_sink_call(None, GetSinkRequest {}).await
154    }
155    async fn get_sink_call(&self, connection: Option<&DynRpcConnection>, request: GetSinkRequest) -> RpcResult<GetSinkResponse>;
156
157    /// Requests information about a specific transaction in the mempool.
158    async fn get_mempool_entry(
159        &self,
160        transaction_id: RpcTransactionId,
161        include_orphan_pool: bool,
162        filter_transaction_pool: bool,
163    ) -> RpcResult<RpcMempoolEntry> {
164        Ok(self
165            .get_mempool_entry_call(None, GetMempoolEntryRequest::new(transaction_id, include_orphan_pool, filter_transaction_pool))
166            .await?
167            .mempool_entry)
168    }
169    async fn get_mempool_entry_call(
170        &self,
171        connection: Option<&DynRpcConnection>,
172        request: GetMempoolEntryRequest,
173    ) -> RpcResult<GetMempoolEntryResponse>;
174
175    /// Requests information about all the transactions currently in the mempool.
176    async fn get_mempool_entries(&self, include_orphan_pool: bool, filter_transaction_pool: bool) -> RpcResult<Vec<RpcMempoolEntry>> {
177        Ok(self
178            .get_mempool_entries_call(None, GetMempoolEntriesRequest::new(include_orphan_pool, filter_transaction_pool))
179            .await?
180            .mempool_entries)
181    }
182    async fn get_mempool_entries_call(
183        &self,
184        connection: Option<&DynRpcConnection>,
185        request: GetMempoolEntriesRequest,
186    ) -> RpcResult<GetMempoolEntriesResponse>;
187
188    /// requests information about all the p2p peers currently connected to this node.
189    async fn get_connected_peer_info(&self) -> RpcResult<GetConnectedPeerInfoResponse> {
190        self.get_connected_peer_info_call(None, GetConnectedPeerInfoRequest {}).await
191    }
192    async fn get_connected_peer_info_call(
193        &self,
194        connection: Option<&DynRpcConnection>,
195        request: GetConnectedPeerInfoRequest,
196    ) -> RpcResult<GetConnectedPeerInfoResponse>;
197
198    /// Adds a peer to the node's outgoing connection list.
199    ///
200    /// This will, in most cases, result in the node connecting to said peer.
201    async fn add_peer(&self, peer_address: RpcContextualPeerAddress, is_permanent: bool) -> RpcResult<()> {
202        self.add_peer_call(None, AddPeerRequest::new(peer_address, is_permanent)).await?;
203        Ok(())
204    }
205    async fn add_peer_call(&self, connection: Option<&DynRpcConnection>, request: AddPeerRequest) -> RpcResult<AddPeerResponse>;
206
207    /// Submits a transaction to the mempool.
208    async fn submit_transaction(&self, transaction: RpcTransaction, allow_orphan: bool) -> RpcResult<RpcTransactionId> {
209        Ok(self.submit_transaction_call(None, SubmitTransactionRequest { transaction, allow_orphan }).await?.transaction_id)
210    }
211    async fn submit_transaction_call(
212        &self,
213        connection: Option<&DynRpcConnection>,
214        request: SubmitTransactionRequest,
215    ) -> RpcResult<SubmitTransactionResponse>;
216
217    /// Submits a transaction replacement to the mempool, applying a mandatory Replace by Fee policy.
218    ///
219    /// Returns the ID of the inserted transaction and the transaction the submission replaced in the mempool.
220    async fn submit_transaction_replacement(&self, transaction: RpcTransaction) -> RpcResult<SubmitTransactionReplacementResponse> {
221        self.submit_transaction_replacement_call(None, SubmitTransactionReplacementRequest { transaction }).await
222    }
223    async fn submit_transaction_replacement_call(
224        &self,
225        connection: Option<&DynRpcConnection>,
226        request: SubmitTransactionReplacementRequest,
227    ) -> RpcResult<SubmitTransactionReplacementResponse>;
228
229    /// Requests information about a specific block.
230    async fn get_block(&self, hash: RpcHash, include_transactions: bool) -> RpcResult<RpcBlock> {
231        Ok(self.get_block_call(None, GetBlockRequest::new(hash, include_transactions)).await?.block)
232    }
233    async fn get_block_call(&self, connection: Option<&DynRpcConnection>, request: GetBlockRequest) -> RpcResult<GetBlockResponse>;
234
235    /// Requests information about a specific subnetwork.
236    async fn get_subnetwork(&self, subnetwork_id: RpcSubnetworkId) -> RpcResult<GetSubnetworkResponse> {
237        self.get_subnetwork_call(None, GetSubnetworkRequest::new(subnetwork_id)).await
238    }
239    async fn get_subnetwork_call(
240        &self,
241        connection: Option<&DynRpcConnection>,
242        request: GetSubnetworkRequest,
243    ) -> RpcResult<GetSubnetworkResponse>;
244
245    /// Requests the virtual selected parent chain from some `start_hash` to this node's current virtual.
246    async fn get_virtual_chain_from_block(
247        &self,
248        start_hash: RpcHash,
249        include_accepted_transaction_ids: bool,
250    ) -> RpcResult<GetVirtualChainFromBlockResponse> {
251        self.get_virtual_chain_from_block_call(
252            None,
253            GetVirtualChainFromBlockRequest::new(start_hash, include_accepted_transaction_ids),
254        )
255        .await
256    }
257    async fn get_virtual_chain_from_block_call(
258        &self,
259        connection: Option<&DynRpcConnection>,
260        request: GetVirtualChainFromBlockRequest,
261    ) -> RpcResult<GetVirtualChainFromBlockResponse>;
262
263    /// Requests blocks between a certain block `low_hash` up to this node's current virtual.
264    async fn get_blocks(
265        &self,
266        low_hash: Option<RpcHash>,
267        include_blocks: bool,
268        include_transactions: bool,
269    ) -> RpcResult<GetBlocksResponse> {
270        self.get_blocks_call(None, GetBlocksRequest::new(low_hash, include_blocks, include_transactions)).await
271    }
272    async fn get_blocks_call(&self, connection: Option<&DynRpcConnection>, request: GetBlocksRequest) -> RpcResult<GetBlocksResponse>;
273
274    /// Requests the current number of blocks in this node.
275    ///
276    /// Note that this number may decrease as pruning occurs.
277    async fn get_block_count(&self) -> RpcResult<GetBlockCountResponse> {
278        self.get_block_count_call(None, GetBlockCountRequest {}).await
279    }
280    async fn get_block_count_call(
281        &self,
282        connection: Option<&DynRpcConnection>,
283        request: GetBlockCountRequest,
284    ) -> RpcResult<GetBlockCountResponse>;
285
286    /// Requests general information about the current state of this node's DAG.
287    async fn get_block_dag_info(&self) -> RpcResult<GetBlockDagInfoResponse> {
288        self.get_block_dag_info_call(None, GetBlockDagInfoRequest {}).await
289    }
290    async fn get_block_dag_info_call(
291        &self,
292        connection: Option<&DynRpcConnection>,
293        request: GetBlockDagInfoRequest,
294    ) -> RpcResult<GetBlockDagInfoResponse>;
295
296    ///
297    async fn resolve_finality_conflict(&self, finality_block_hash: RpcHash) -> RpcResult<()> {
298        self.resolve_finality_conflict_call(None, ResolveFinalityConflictRequest::new(finality_block_hash)).await?;
299        Ok(())
300    }
301    async fn resolve_finality_conflict_call(
302        &self,
303        connection: Option<&DynRpcConnection>,
304        request: ResolveFinalityConflictRequest,
305    ) -> RpcResult<ResolveFinalityConflictResponse>;
306
307    /// Shuts down this node.
308    async fn shutdown(&self) -> RpcResult<()> {
309        self.shutdown_call(None, ShutdownRequest {}).await?;
310        Ok(())
311    }
312    async fn shutdown_call(&self, connection: Option<&DynRpcConnection>, request: ShutdownRequest) -> RpcResult<ShutdownResponse>;
313
314    /// Requests headers between the given `start_hash` and the current virtual, up to the given limit.
315    async fn get_headers(&self, start_hash: RpcHash, limit: u64, is_ascending: bool) -> RpcResult<Vec<RpcHeader>> {
316        Ok(self.get_headers_call(None, GetHeadersRequest::new(start_hash, limit, is_ascending)).await?.headers)
317    }
318    async fn get_headers_call(
319        &self,
320        connection: Option<&DynRpcConnection>,
321        request: GetHeadersRequest,
322    ) -> RpcResult<GetHeadersResponse>;
323
324    /// Returns the total balance in unspent transactions towards a given address.
325    ///
326    /// This call is only available when this node was started with `--utxoindex`.
327    async fn get_balance_by_address(&self, address: RpcAddress) -> RpcResult<u64> {
328        Ok(self.get_balance_by_address_call(None, GetBalanceByAddressRequest::new(address)).await?.balance)
329    }
330    async fn get_balance_by_address_call(
331        &self,
332        connection: Option<&DynRpcConnection>,
333        request: GetBalanceByAddressRequest,
334    ) -> RpcResult<GetBalanceByAddressResponse>;
335
336    ///
337    async fn get_balances_by_addresses(&self, addresses: Vec<RpcAddress>) -> RpcResult<Vec<RpcBalancesByAddressesEntry>> {
338        Ok(self.get_balances_by_addresses_call(None, GetBalancesByAddressesRequest::new(addresses)).await?.entries)
339    }
340    async fn get_balances_by_addresses_call(
341        &self,
342        connection: Option<&DynRpcConnection>,
343        request: GetBalancesByAddressesRequest,
344    ) -> RpcResult<GetBalancesByAddressesResponse>;
345
346    /// Requests all current UTXOs for the given node addresses.
347    ///
348    /// This call is only available when this node was started with `--utxoindex`.
349    async fn get_utxos_by_addresses(&self, addresses: Vec<RpcAddress>) -> RpcResult<Vec<RpcUtxosByAddressesEntry>> {
350        Ok(self.get_utxos_by_addresses_call(None, GetUtxosByAddressesRequest::new(addresses)).await?.entries)
351    }
352    async fn get_utxos_by_addresses_call(
353        &self,
354        connection: Option<&DynRpcConnection>,
355        request: GetUtxosByAddressesRequest,
356    ) -> RpcResult<GetUtxosByAddressesResponse>;
357
358    /// Requests the blue score of the current selected parent of the virtual block.
359    async fn get_sink_blue_score(&self) -> RpcResult<u64> {
360        Ok(self.get_sink_blue_score_call(None, GetSinkBlueScoreRequest {}).await?.blue_score)
361    }
362    async fn get_sink_blue_score_call(
363        &self,
364        connection: Option<&DynRpcConnection>,
365        request: GetSinkBlueScoreRequest,
366    ) -> RpcResult<GetSinkBlueScoreResponse>;
367
368    /// Bans the given ip.
369    async fn ban(&self, ip: RpcIpAddress) -> RpcResult<()> {
370        self.ban_call(None, BanRequest::new(ip)).await?;
371        Ok(())
372    }
373    async fn ban_call(&self, connection: Option<&DynRpcConnection>, request: BanRequest) -> RpcResult<BanResponse>;
374
375    /// Unbans the given ip.
376    async fn unban(&self, ip: RpcIpAddress) -> RpcResult<()> {
377        self.unban_call(None, UnbanRequest::new(ip)).await?;
378        Ok(())
379    }
380    async fn unban_call(&self, connection: Option<&DynRpcConnection>, request: UnbanRequest) -> RpcResult<UnbanResponse>;
381
382    /// Returns info about the node.
383    async fn get_info(&self) -> RpcResult<GetInfoResponse> {
384        self.get_info_call(None, GetInfoRequest {}).await
385    }
386    async fn get_info_call(&self, connection: Option<&DynRpcConnection>, request: GetInfoRequest) -> RpcResult<GetInfoResponse>;
387
388    ///
389    async fn estimate_network_hashes_per_second(&self, window_size: u32, start_hash: Option<RpcHash>) -> RpcResult<u64> {
390        Ok(self
391            .estimate_network_hashes_per_second_call(None, EstimateNetworkHashesPerSecondRequest::new(window_size, start_hash))
392            .await?
393            .network_hashes_per_second)
394    }
395    async fn estimate_network_hashes_per_second_call(
396        &self,
397        connection: Option<&DynRpcConnection>,
398        request: EstimateNetworkHashesPerSecondRequest,
399    ) -> RpcResult<EstimateNetworkHashesPerSecondResponse>;
400
401    ///
402    async fn get_mempool_entries_by_addresses(
403        &self,
404        addresses: Vec<RpcAddress>,
405        include_orphan_pool: bool,
406        filter_transaction_pool: bool,
407    ) -> RpcResult<Vec<RpcMempoolEntryByAddress>> {
408        Ok(self
409            .get_mempool_entries_by_addresses_call(
410                None,
411                GetMempoolEntriesByAddressesRequest::new(addresses, include_orphan_pool, filter_transaction_pool),
412            )
413            .await?
414            .entries)
415    }
416    async fn get_mempool_entries_by_addresses_call(
417        &self,
418        connection: Option<&DynRpcConnection>,
419        request: GetMempoolEntriesByAddressesRequest,
420    ) -> RpcResult<GetMempoolEntriesByAddressesResponse>;
421
422    ///
423    async fn get_coin_supply(&self) -> RpcResult<GetCoinSupplyResponse> {
424        self.get_coin_supply_call(None, GetCoinSupplyRequest {}).await
425    }
426    async fn get_coin_supply_call(
427        &self,
428        connection: Option<&DynRpcConnection>,
429        request: GetCoinSupplyRequest,
430    ) -> RpcResult<GetCoinSupplyResponse>;
431
432    async fn get_daa_score_timestamp_estimate(&self, daa_scores: Vec<u64>) -> RpcResult<Vec<u64>> {
433        Ok(self.get_daa_score_timestamp_estimate_call(None, GetDaaScoreTimestampEstimateRequest { daa_scores }).await?.timestamps)
434    }
435    async fn get_daa_score_timestamp_estimate_call(
436        &self,
437        connection: Option<&DynRpcConnection>,
438        request: GetDaaScoreTimestampEstimateRequest,
439    ) -> RpcResult<GetDaaScoreTimestampEstimateResponse>;
440
441    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
442    // Fee estimation API
443
444    async fn get_fee_estimate(&self) -> RpcResult<RpcFeeEstimate> {
445        Ok(self.get_fee_estimate_call(None, GetFeeEstimateRequest {}).await?.estimate)
446    }
447    async fn get_fee_estimate_call(
448        &self,
449        connection: Option<&DynRpcConnection>,
450        request: GetFeeEstimateRequest,
451    ) -> RpcResult<GetFeeEstimateResponse>;
452
453    async fn get_fee_estimate_experimental(&self, verbose: bool) -> RpcResult<GetFeeEstimateExperimentalResponse> {
454        self.get_fee_estimate_experimental_call(None, GetFeeEstimateExperimentalRequest { verbose }).await
455    }
456    async fn get_fee_estimate_experimental_call(
457        &self,
458        connection: Option<&DynRpcConnection>,
459        request: GetFeeEstimateExperimentalRequest,
460    ) -> RpcResult<GetFeeEstimateExperimentalResponse>;
461
462    ///
463    async fn get_current_block_color(&self, hash: RpcHash) -> RpcResult<GetCurrentBlockColorResponse> {
464        Ok(self.get_current_block_color_call(None, GetCurrentBlockColorRequest { hash }).await?)
465    }
466    async fn get_current_block_color_call(
467        &self,
468        connection: Option<&DynRpcConnection>,
469        request: GetCurrentBlockColorRequest,
470    ) -> RpcResult<GetCurrentBlockColorResponse>;
471
472    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
473    // Notification API
474
475    /// Register a new listener and returns an id identifying it.
476    fn register_new_listener(&self, connection: ChannelConnection) -> ListenerId;
477
478    /// Unregister an existing listener.
479    ///
480    /// Stop all notifications for this listener, unregister the id and its associated connection.
481    async fn unregister_listener(&self, id: ListenerId) -> RpcResult<()>;
482
483    /// Start sending notifications of some type to a listener.
484    async fn start_notify(&self, id: ListenerId, scope: Scope) -> RpcResult<()>;
485
486    /// Stop sending notifications of some type to a listener.
487    async fn stop_notify(&self, id: ListenerId, scope: Scope) -> RpcResult<()>;
488
489    /// Execute a subscription command leading to either start or stop sending notifications
490    /// of some type to a listener.
491    async fn execute_subscribe_command(&self, id: ListenerId, scope: Scope, command: Command) -> RpcResult<()> {
492        match command {
493            Command::Start => self.start_notify(id, scope).await,
494            Command::Stop => self.stop_notify(id, scope).await,
495        }
496    }
497}
498
499pub type DynRpcService = Arc<dyn RpcApi>;
500
501downcast_sync!(dyn RpcApi);