cuprated/rpc/service/
blockchain_context.rs

1//! Functions to send [`BlockChainContextRequest`]s.
2
3use anyhow::{anyhow, Error};
4use monero_serai::block::Block;
5use tower::{Service, ServiceExt};
6
7use cuprate_consensus_context::{
8    BlockChainContextRequest, BlockChainContextResponse, BlockchainContext,
9    BlockchainContextService,
10};
11use cuprate_types::{
12    rpc::{FeeEstimate, HardForkInfo},
13    HardFork,
14};
15
16// FIXME: use `anyhow::Error` over `tower::BoxError` in blockchain context.
17
18/// [`BlockChainContextRequest::HardForkInfo`].
19pub(crate) async fn hard_fork_info(
20    blockchain_context: &mut BlockchainContextService,
21    hard_fork: HardFork,
22) -> Result<HardForkInfo, Error> {
23    let BlockChainContextResponse::HardForkInfo(hf_info) = blockchain_context
24        .ready()
25        .await
26        .map_err(|e| anyhow!(e))?
27        .call(BlockChainContextRequest::HardForkInfo(hard_fork))
28        .await
29        .map_err(|e| anyhow!(e))?
30    else {
31        unreachable!();
32    };
33
34    Ok(hf_info)
35}
36
37/// [`BlockChainContextRequest::FeeEstimate`].
38pub(crate) async fn fee_estimate(
39    blockchain_context: &mut BlockchainContextService,
40    grace_blocks: u64,
41) -> Result<FeeEstimate, Error> {
42    let BlockChainContextResponse::FeeEstimate(fee) = blockchain_context
43        .ready()
44        .await
45        .map_err(|e| anyhow!(e))?
46        .call(BlockChainContextRequest::FeeEstimate { grace_blocks })
47        .await
48        .map_err(|e| anyhow!(e))?
49    else {
50        unreachable!();
51    };
52
53    Ok(fee)
54}
55
56/// [`BlockChainContextRequest::CalculatePow`]
57pub(crate) async fn calculate_pow(
58    blockchain_context: &mut BlockchainContextService,
59    hardfork: HardFork,
60    block: Block,
61    seed_hash: [u8; 32],
62) -> Result<[u8; 32], Error> {
63    let Some(height) = block.number() else {
64        return Err(anyhow!("Block is missing height"));
65    };
66
67    let block = Box::new(block);
68
69    let BlockChainContextResponse::CalculatePow(hash) = blockchain_context
70        .ready()
71        .await
72        .map_err(|e| anyhow!(e))?
73        .call(BlockChainContextRequest::CalculatePow {
74            hardfork,
75            height,
76            block,
77            seed_hash,
78        })
79        .await
80        .map_err(|e| anyhow!(e))?
81    else {
82        unreachable!();
83    };
84
85    Ok(hash)
86}
87
88/// [`BlockChainContextRequest::BatchGetDifficulties`]
89pub async fn batch_get_difficulties(
90    blockchain_context: &mut BlockchainContextService,
91    difficulties: Vec<(u64, HardFork)>,
92) -> Result<Vec<u128>, Error> {
93    let BlockChainContextResponse::BatchDifficulties(resp) = blockchain_context
94        .ready()
95        .await
96        .map_err(|e| anyhow!(e))?
97        .call(BlockChainContextRequest::BatchGetDifficulties(difficulties))
98        .await
99        .map_err(|e| anyhow!(e))?
100    else {
101        unreachable!();
102    };
103
104    Ok(resp)
105}