cuprated/blockchain/
chain_service.rs1use std::task::{Context, Poll};
2
3use futures::{future::BoxFuture, FutureExt, TryFutureExt};
4use tower::Service;
5
6use cuprate_blockchain::service::BlockchainReadHandle;
7use cuprate_fast_sync::validate_entries;
8use cuprate_p2p::block_downloader::{ChainSvcRequest, ChainSvcResponse};
9use cuprate_p2p_core::NetworkZone;
10use cuprate_types::blockchain::{BlockchainReadRequest, BlockchainResponse};
11
12#[derive(Clone)]
17pub struct ChainService(pub BlockchainReadHandle);
18
19impl<N: NetworkZone> Service<ChainSvcRequest<N>> for ChainService {
20 type Response = ChainSvcResponse<N>;
21 type Error = tower::BoxError;
22 type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
23
24 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
25 self.0.poll_ready(cx).map_err(Into::into)
26 }
27
28 fn call(&mut self, req: ChainSvcRequest<N>) -> Self::Future {
29 #[expect(
30 clippy::wildcard_enum_match_arm,
31 reason = "other requests should be unreachable"
32 )]
33 let map_res = |res: BlockchainResponse| match res {
34 BlockchainResponse::CompactChainHistory {
35 block_ids,
36 cumulative_difficulty,
37 } => ChainSvcResponse::CompactHistory {
38 block_ids,
39 cumulative_difficulty,
40 },
41 BlockchainResponse::FindFirstUnknown(res) => ChainSvcResponse::FindFirstUnknown(res),
42 _ => unreachable!(),
43 };
44
45 match req {
46 ChainSvcRequest::CompactHistory => self
47 .0
48 .call(BlockchainReadRequest::CompactChainHistory)
49 .map_ok(map_res)
50 .map_err(Into::into)
51 .boxed(),
52 ChainSvcRequest::FindFirstUnknown(req) => self
53 .0
54 .call(BlockchainReadRequest::FindFirstUnknown(req))
55 .map_ok(map_res)
56 .map_err(Into::into)
57 .boxed(),
58 ChainSvcRequest::CumulativeDifficulty => self
59 .0
60 .call(BlockchainReadRequest::CompactChainHistory)
61 .map_ok(|res| {
62 let BlockchainResponse::CompactChainHistory {
65 cumulative_difficulty,
66 ..
67 } = res
68 else {
69 unreachable!()
70 };
71
72 ChainSvcResponse::CumulativeDifficulty(cumulative_difficulty)
73 })
74 .map_err(Into::into)
75 .boxed(),
76 ChainSvcRequest::ValidateEntries(entries, start_height) => {
77 let mut blockchain_read_handle = self.0.clone();
78
79 async move {
80 let (valid, unknown) =
81 validate_entries(entries, start_height, &mut blockchain_read_handle)
82 .await?;
83
84 Ok(ChainSvcResponse::ValidateEntries { valid, unknown })
85 }
86 .boxed()
87 }
88 }
89 }
90}