mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-10 16:57:21 +00:00
ec6a428ade
* `payment_queryInfo`: Make it work with `WeighV2` The runtime api for querying the payment info depends on the `Weight` type and broke for old runtimes that still use the `WeighV1`. This pull requests fixes this by: 1. Bumping the version of the runtime api. 2. Making the node side code use the correct runtime api function depending on the version of the runtime api. 3. Make the RPC always return `WeighV1`. Users of the api should switch to `state_call` and decide based on the version of the runtime api which `Weight` type is being returned. * Fix tests * Review comment
198 lines
5.7 KiB
Rust
198 lines
5.7 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! RPC interface for the transaction payment pallet.
|
|
|
|
use std::{convert::TryInto, sync::Arc};
|
|
|
|
use codec::{Codec, Decode};
|
|
use jsonrpsee::{
|
|
core::{Error as JsonRpseeError, RpcResult},
|
|
proc_macros::rpc,
|
|
types::error::{CallError, ErrorCode, ErrorObject},
|
|
};
|
|
use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, InclusionFee, RuntimeDispatchInfo};
|
|
use sp_api::{ApiExt, ProvideRuntimeApi};
|
|
use sp_blockchain::HeaderBackend;
|
|
use sp_core::Bytes;
|
|
use sp_rpc::number::NumberOrHex;
|
|
use sp_runtime::{
|
|
generic::BlockId,
|
|
traits::{Block as BlockT, MaybeDisplay},
|
|
};
|
|
|
|
pub use pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi;
|
|
|
|
#[rpc(client, server)]
|
|
pub trait TransactionPaymentApi<BlockHash, ResponseType> {
|
|
#[method(name = "payment_queryInfo")]
|
|
fn query_info(&self, encoded_xt: Bytes, at: Option<BlockHash>) -> RpcResult<ResponseType>;
|
|
|
|
#[method(name = "payment_queryFeeDetails")]
|
|
fn query_fee_details(
|
|
&self,
|
|
encoded_xt: Bytes,
|
|
at: Option<BlockHash>,
|
|
) -> RpcResult<FeeDetails<NumberOrHex>>;
|
|
}
|
|
|
|
/// Provides RPC methods to query a dispatchable's class, weight and fee.
|
|
pub struct TransactionPayment<C, P> {
|
|
/// Shared reference to the client.
|
|
client: Arc<C>,
|
|
_marker: std::marker::PhantomData<P>,
|
|
}
|
|
|
|
impl<C, P> TransactionPayment<C, P> {
|
|
/// Creates a new instance of the TransactionPayment Rpc helper.
|
|
pub fn new(client: Arc<C>) -> Self {
|
|
Self { client, _marker: Default::default() }
|
|
}
|
|
}
|
|
|
|
/// Error type of this RPC api.
|
|
pub enum Error {
|
|
/// The transaction was not decodable.
|
|
DecodeError,
|
|
/// The call to runtime failed.
|
|
RuntimeError,
|
|
}
|
|
|
|
impl From<Error> for i32 {
|
|
fn from(e: Error) -> i32 {
|
|
match e {
|
|
Error::RuntimeError => 1,
|
|
Error::DecodeError => 2,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<C, Block, Balance>
|
|
TransactionPaymentApiServer<
|
|
<Block as BlockT>::Hash,
|
|
RuntimeDispatchInfo<Balance, sp_weights::OldWeight>,
|
|
> for TransactionPayment<C, Block>
|
|
where
|
|
Block: BlockT,
|
|
C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + Send + Sync + 'static,
|
|
C::Api: TransactionPaymentRuntimeApi<Block, Balance>,
|
|
Balance: Codec + MaybeDisplay + Copy + TryInto<NumberOrHex> + Send + Sync + 'static,
|
|
{
|
|
fn query_info(
|
|
&self,
|
|
encoded_xt: Bytes,
|
|
at: Option<Block::Hash>,
|
|
) -> RpcResult<RuntimeDispatchInfo<Balance, sp_weights::OldWeight>> {
|
|
let api = self.client.runtime_api();
|
|
let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));
|
|
|
|
let encoded_len = encoded_xt.len() as u32;
|
|
|
|
let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| {
|
|
CallError::Custom(ErrorObject::owned(
|
|
Error::DecodeError.into(),
|
|
"Unable to query dispatch info.",
|
|
Some(format!("{:?}", e)),
|
|
))
|
|
})?;
|
|
|
|
fn map_err(error: impl ToString, desc: &'static str) -> CallError {
|
|
CallError::Custom(ErrorObject::owned(
|
|
Error::RuntimeError.into(),
|
|
desc,
|
|
Some(error.to_string()),
|
|
))
|
|
}
|
|
|
|
let api_version = api
|
|
.api_version::<dyn TransactionPaymentRuntimeApi<Block, Balance>>(&at)
|
|
.map_err(|e| map_err(e, "Failed to get transaction payment runtime api version"))?
|
|
.ok_or_else(|| {
|
|
CallError::Custom(ErrorObject::owned(
|
|
Error::RuntimeError.into(),
|
|
"Transaction payment runtime api wasn't found in the runtime",
|
|
None::<String>,
|
|
))
|
|
})?;
|
|
|
|
if api_version < 2 {
|
|
#[allow(deprecated)]
|
|
api.query_info_before_version_2(&at, uxt, encoded_len)
|
|
.map_err(|e| map_err(e, "Unable to query dispatch info.").into())
|
|
} else {
|
|
let res = api
|
|
.query_info(&at, uxt, encoded_len)
|
|
.map_err(|e| map_err(e, "Unable to query dispatch info."))?;
|
|
|
|
Ok(RuntimeDispatchInfo {
|
|
weight: sp_weights::OldWeight(res.weight.ref_time()),
|
|
class: res.class,
|
|
partial_fee: res.partial_fee,
|
|
})
|
|
}
|
|
}
|
|
|
|
fn query_fee_details(
|
|
&self,
|
|
encoded_xt: Bytes,
|
|
at: Option<Block::Hash>,
|
|
) -> RpcResult<FeeDetails<NumberOrHex>> {
|
|
let api = self.client.runtime_api();
|
|
let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));
|
|
|
|
let encoded_len = encoded_xt.len() as u32;
|
|
|
|
let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| {
|
|
CallError::Custom(ErrorObject::owned(
|
|
Error::DecodeError.into(),
|
|
"Unable to query fee details.",
|
|
Some(format!("{:?}", e)),
|
|
))
|
|
})?;
|
|
let fee_details = api.query_fee_details(&at, uxt, encoded_len).map_err(|e| {
|
|
CallError::Custom(ErrorObject::owned(
|
|
Error::RuntimeError.into(),
|
|
"Unable to query fee details.",
|
|
Some(e.to_string()),
|
|
))
|
|
})?;
|
|
|
|
let try_into_rpc_balance = |value: Balance| {
|
|
value.try_into().map_err(|_| {
|
|
JsonRpseeError::Call(CallError::Custom(ErrorObject::owned(
|
|
ErrorCode::InvalidParams.code(),
|
|
format!("{} doesn't fit in NumberOrHex representation", value),
|
|
None::<()>,
|
|
)))
|
|
})
|
|
};
|
|
|
|
Ok(FeeDetails {
|
|
inclusion_fee: if let Some(inclusion_fee) = fee_details.inclusion_fee {
|
|
Some(InclusionFee {
|
|
base_fee: try_into_rpc_balance(inclusion_fee.base_fee)?,
|
|
len_fee: try_into_rpc_balance(inclusion_fee.len_fee)?,
|
|
adjusted_weight_fee: try_into_rpc_balance(inclusion_fee.adjusted_weight_fee)?,
|
|
})
|
|
} else {
|
|
None
|
|
},
|
|
tip: Default::default(),
|
|
})
|
|
}
|
|
}
|