pallet_frequency_tx_payment_rpc/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(clippy::too_many_arguments)]
3#![allow(clippy::unnecessary_mut_passed)]
4#![allow(rustdoc::bare_urls)]
5#![deny(
7 rustdoc::broken_intra_doc_links,
8 rustdoc::missing_crate_level_docs,
9 rustdoc::invalid_codeblock_attributes,
10 missing_docs
11)]
12
13use std::{convert::TryInto, sync::Arc};
21
22use jsonrpsee::{
23 core::{async_trait, RpcResult},
24 proc_macros::rpc,
25 types::{error::ErrorCode, ErrorObject},
26};
27use pallet_frequency_tx_payment_runtime_api::{FeeDetails, InclusionFee};
28use parity_scale_codec::{Codec, Decode};
29use sp_api::ProvideRuntimeApi;
30use sp_blockchain::HeaderBackend;
31use sp_core::Bytes;
32use sp_rpc::number::NumberOrHex;
33use sp_runtime::traits::{Block as BlockT, MaybeDisplay};
34
35pub use pallet_frequency_tx_payment_runtime_api::CapacityTransactionPaymentRuntimeApi;
36
37#[cfg(test)]
38mod tests;
39
40#[rpc(client, server)]
42pub trait CapacityPaymentApi<BlockHash, Balance> {
43 #[method(name = "frequencyTxPayment_computeCapacityFeeDetails")]
45 fn compute_capacity_fee_details(
46 &self,
47 encoded_xt: Bytes,
48 at: Option<BlockHash>,
49 ) -> RpcResult<FeeDetails<NumberOrHex>>;
50}
51
52pub struct CapacityPaymentHandler<C, P> {
54 client: Arc<C>,
56 _marker: std::marker::PhantomData<P>,
57}
58
59impl<C, P> CapacityPaymentHandler<C, P> {
60 pub fn new(client: Arc<C>) -> Self {
62 Self { client, _marker: Default::default() }
63 }
64}
65
66pub enum Error {
68 DecodeError,
70 RuntimeError,
72}
73
74impl From<Error> for i32 {
75 fn from(e: Error) -> i32 {
76 match e {
77 Error::RuntimeError => 1,
78 Error::DecodeError => 2,
79 }
80 }
81}
82
83#[async_trait]
84impl<C, Block, Balance> CapacityPaymentApiServer<<Block as BlockT>::Hash, Balance>
85 for CapacityPaymentHandler<C, Block>
86where
87 Block: BlockT,
88 C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
89 C::Api: CapacityTransactionPaymentRuntimeApi<Block, Balance>,
90 Balance: Codec + MaybeDisplay + Copy + TryInto<NumberOrHex> + Send + Sync + 'static,
91{
92 fn compute_capacity_fee_details(
93 &self,
94 encoded_xt: Bytes,
95 at: Option<Block::Hash>,
96 ) -> RpcResult<FeeDetails<NumberOrHex>> {
97 let api = self.client.runtime_api();
98 let at_hash = at.unwrap_or_else(|| self.client.info().best_hash);
99
100 let encoded_len = encoded_xt.len() as u32;
101 let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| {
102 ErrorObject::owned(
103 Error::DecodeError.into(),
104 "Unable to query capacity fee details.",
105 Some(format!("{e:?}")),
106 )
107 })?;
108 let fee_details = api.compute_capacity_fee(at_hash, uxt, encoded_len).map_err(|e| {
109 ErrorObject::owned(
110 Error::RuntimeError.into(),
111 "Unable to query capacity fee details.",
112 Some(format!("{e:?}")),
113 )
114 })?;
115
116 let try_into_rpc_balance = |value: Balance| {
117 value.try_into().map_err(|_| {
118 ErrorObject::owned(
119 ErrorCode::InvalidParams.code(),
120 format!("{value} doesn't fit in NumberOrHex representation"),
121 None::<()>,
122 )
123 })
124 };
125
126 Ok(FeeDetails {
127 inclusion_fee: if let Some(inclusion_fee) = fee_details.inclusion_fee {
128 Some(InclusionFee {
129 base_fee: try_into_rpc_balance(inclusion_fee.base_fee)?,
130 len_fee: try_into_rpc_balance(inclusion_fee.len_fee)?,
131 adjusted_weight_fee: try_into_rpc_balance(inclusion_fee.adjusted_weight_fee)?,
132 })
133 } else {
134 None
135 },
136 tip: Default::default(),
137 })
138 }
139}