1//! `cuprated`'s implementation of [`RpcHandler`].
23use std::task::{Context, Poll};
45use anyhow::Error;
6use futures::future::BoxFuture;
7use monero_serai::block::Block;
8use tower::Service;
910use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
11use cuprate_consensus::BlockchainContextService;
12use cuprate_pruning::PruningSeed;
13use cuprate_rpc_interface::RpcHandler;
14use cuprate_rpc_types::{
15 bin::{BinRequest, BinResponse},
16 json::{JsonRpcRequest, JsonRpcResponse},
17 other::{OtherRequest, OtherResponse},
18};
19use cuprate_txpool::service::TxpoolReadHandle;
20use cuprate_types::BlockTemplate;
2122use crate::rpc::handlers;
2324/// TODO: use real type when public.
25#[derive(Clone)]
26pub enum BlockchainManagerRequest {
27/// Pop blocks off the top of the blockchain.
28 ///
29 /// Input is the amount of blocks to pop.
30PopBlocks { amount: usize },
3132/// Start pruning the blockchain.
33Prune,
3435/// Is the blockchain pruned?
36Pruned,
3738/// Relay a block to the network.
39RelayBlock(
40/// This is [`Box`]ed due to `clippy::large_enum_variant`.
41Box<Block>,
42 ),
4344/// Sync/flush the blockchain database to disk.
45Sync,
4647/// Is the blockchain in the middle of syncing?
48 ///
49 /// This returning `false` does not necessarily
50 /// mean [`BlockchainManagerRequest::Synced`] will
51 /// return `true`, for example, if the network has been
52 /// cut off and we have no peers, this will return `false`,
53 /// however, [`BlockchainManagerRequest::Synced`] may return
54 /// `true` if the latest known chain tip is equal to our height.
55Syncing,
5657/// Is the blockchain fully synced?
58Synced,
5960/// Current target block time.
61Target,
6263/// The height of the next block in the chain.
64TargetHeight,
6566/// Generate new blocks.
67 ///
68 /// This request is only for regtest, see RPC's `generateblocks`.
69GenerateBlocks {
70/// Number of the blocks to be generated.
71amount_of_blocks: u64,
72/// The previous block's hash.
73prev_block: Option<[u8; 32]>,
74/// The starting value for the nonce.
75starting_nonce: u32,
76/// The address that will receive the coinbase reward.
77wallet_address: String,
78 },
7980// // TODO: the below requests actually belong to the block downloader/syncer:
81 // // <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811089758>
82 // /// Get [`Span`] data.
83 // ///
84 // /// This is data that describes an active downloading process,
85 // /// if we are fully synced, this will return an empty [`Vec`].
86 // Spans,
8788 //
89/// Get the next [`PruningSeed`] needed for a pruned sync.
90NextNeededPruningSeed,
9192/// Create a block template.
93CreateBlockTemplate {
94 prev_block: [u8; 32],
95 account_public_address: String,
96 extra_nonce: Vec<u8>,
97 },
9899/// Safely shutdown `cuprated`.
100Stop,
101}
102103/// TODO: use real type when public.
104#[derive(Clone)]
105pub enum BlockchainManagerResponse {
106/// General OK response.
107 ///
108 /// Response to:
109 /// - [`BlockchainManagerRequest::Prune`]
110 /// - [`BlockchainManagerRequest::RelayBlock`]
111 /// - [`BlockchainManagerRequest::Sync`]
112Ok,
113114/// Response to [`BlockchainManagerRequest::PopBlocks`]
115PopBlocks { new_height: usize },
116117/// Response to [`BlockchainManagerRequest::Prune`]
118Prune(PruningSeed),
119120/// Response to [`BlockchainManagerRequest::Pruned`]
121Pruned(bool),
122123/// Response to [`BlockchainManagerRequest::Syncing`]
124Syncing(bool),
125126/// Response to [`BlockchainManagerRequest::Synced`]
127Synced(bool),
128129/// Response to [`BlockchainManagerRequest::Target`]
130Target(std::time::Duration),
131132/// Response to [`BlockchainManagerRequest::TargetHeight`]
133TargetHeight { height: usize },
134135/// Response to [`BlockchainManagerRequest::GenerateBlocks`]
136GenerateBlocks {
137/// Hashes of the blocks generated.
138blocks: Vec<[u8; 32]>,
139/// The new top height. (TODO: is this correct?)
140height: usize,
141 },
142143/// Response to [`BlockchainManagerRequest::NextNeededPruningSeed`].
144NextNeededPruningSeed(PruningSeed),
145146/// Response to [`BlockchainManagerRequest::CreateBlockTemplate`].
147CreateBlockTemplate(Box<BlockTemplate>),
148}
149150/// TODO: use real type when public.
151pub type BlockchainManagerHandle = cuprate_database_service::DatabaseReadService<
152 BlockchainManagerRequest,
153 BlockchainManagerResponse,
154>;
155156/// TODO
157#[derive(Clone)]
158pub struct CupratedRpcHandler {
159/// Should this RPC server be [restricted](RpcHandler::is_restricted)?
160 ///
161 /// This is not `pub` on purpose, as it should not be mutated after [`Self::new`].
162restricted: bool,
163164/// Read handle to the blockchain database.
165pub blockchain_read: BlockchainReadHandle,
166167/// Handle to the blockchain context service.
168pub blockchain_context: BlockchainContextService,
169170/// Handle to the blockchain manager.
171pub blockchain_manager: BlockchainManagerHandle,
172173/// Read handle to the transaction pool database.
174pub txpool_read: TxpoolReadHandle,
175176/// TODO: handle to txpool service.
177pub txpool_manager: std::convert::Infallible,
178}
179180impl CupratedRpcHandler {
181/// Create a new [`Self`].
182pub const fn new(
183 restricted: bool,
184 blockchain_read: BlockchainReadHandle,
185 blockchain_context: BlockchainContextService,
186 blockchain_manager: BlockchainManagerHandle,
187 txpool_read: TxpoolReadHandle,
188 txpool_manager: std::convert::Infallible,
189 ) -> Self {
190Self {
191 restricted,
192 blockchain_read,
193 blockchain_context,
194 blockchain_manager,
195 txpool_read,
196 txpool_manager,
197 }
198 }
199}
200201impl RpcHandler for CupratedRpcHandler {
202fn is_restricted(&self) -> bool {
203self.restricted
204 }
205}
206207impl Service<JsonRpcRequest> for CupratedRpcHandler {
208type Response = JsonRpcResponse;
209type Error = Error;
210type Future = BoxFuture<'static, Result<JsonRpcResponse, Error>>;
211212fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
213 Poll::Ready(Ok(()))
214 }
215216fn call(&mut self, request: JsonRpcRequest) -> Self::Future {
217let state = self.clone();
218 Box::pin(handlers::json_rpc::map_request(state, request))
219 }
220}
221222impl Service<BinRequest> for CupratedRpcHandler {
223type Response = BinResponse;
224type Error = Error;
225type Future = BoxFuture<'static, Result<BinResponse, Error>>;
226227fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
228 Poll::Ready(Ok(()))
229 }
230231fn call(&mut self, request: BinRequest) -> Self::Future {
232let state = self.clone();
233 Box::pin(handlers::bin::map_request(state, request))
234 }
235}
236237impl Service<OtherRequest> for CupratedRpcHandler {
238type Response = OtherResponse;
239type Error = Error;
240type Future = BoxFuture<'static, Result<OtherResponse, Error>>;
241242fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
243 Poll::Ready(Ok(()))
244 }
245246fn call(&mut self, request: OtherRequest) -> Self::Future {
247let state = self.clone();
248 Box::pin(handlers::other_json::map_request(state, request))
249 }
250}