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/// cuprated's RPC handler service.
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/// Read handle to the transaction pool database.
171pub txpool_read: TxpoolReadHandle,
172// TODO: handle to txpool service.
173}
174175impl CupratedRpcHandler {
176/// Create a new [`Self`].
177pub const fn new(
178 restricted: bool,
179 blockchain_read: BlockchainReadHandle,
180 blockchain_context: BlockchainContextService,
181 txpool_read: TxpoolReadHandle,
182 ) -> Self {
183Self {
184 restricted,
185 blockchain_read,
186 blockchain_context,
187 txpool_read,
188 }
189 }
190}
191192impl RpcHandler for CupratedRpcHandler {
193fn is_restricted(&self) -> bool {
194self.restricted
195 }
196}
197198impl Service<JsonRpcRequest> for CupratedRpcHandler {
199type Response = JsonRpcResponse;
200type Error = Error;
201type Future = BoxFuture<'static, Result<JsonRpcResponse, Error>>;
202203fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
204 Poll::Ready(Ok(()))
205 }
206207fn call(&mut self, request: JsonRpcRequest) -> Self::Future {
208let state = self.clone();
209 Box::pin(handlers::json_rpc::map_request(state, request))
210 }
211}
212213impl Service<BinRequest> for CupratedRpcHandler {
214type Response = BinResponse;
215type Error = Error;
216type Future = BoxFuture<'static, Result<BinResponse, Error>>;
217218fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
219 Poll::Ready(Ok(()))
220 }
221222fn call(&mut self, request: BinRequest) -> Self::Future {
223let state = self.clone();
224 Box::pin(handlers::bin::map_request(state, request))
225 }
226}
227228impl Service<OtherRequest> for CupratedRpcHandler {
229type Response = OtherResponse;
230type Error = Error;
231type Future = BoxFuture<'static, Result<OtherResponse, Error>>;
232233fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
234 Poll::Ready(Ok(()))
235 }
236237fn call(&mut self, request: OtherRequest) -> Self::Future {
238let state = self.clone();
239 Box::pin(handlers::other_json::map_request(state, request))
240 }
241}