Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Transaction payment runtime api: query call info and fee details #11819

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frame/transaction-payment/rpc/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features =
pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment" }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" }
sp-core = { version = "6.0.0", default-features = false, path = "../../../../primitives/core" }

[features]
default = ["std"]
Expand Down
36 changes: 35 additions & 1 deletion frame/transaction-payment/rpc/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#![cfg_attr(not(feature = "std"), no_std)]

use codec::Codec;
use sp_runtime::traits::MaybeDisplay;
use sp_core::Bytes;
use sp_runtime::{traits::MaybeDisplay, DispatchError};
use sp_std::marker::PhantomData;

pub use pallet_transaction_payment::{FeeDetails, InclusionFee, RuntimeDispatchInfo};

Expand All @@ -30,5 +32,37 @@ sp_api::decl_runtime_apis! {
{
fn query_info(uxt: Block::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance>;
fn query_fee_details(uxt: Block::Extrinsic, len: u32) -> FeeDetails<Balance>;
fn query_call_info(encoded_call: Bytes) -> Result<RuntimeDispatchInfo<Balance>, DispatchError>;
fn query_weight_to_fee(encoded_call: Bytes) -> Result<Balance, DispatchError>;
muharem marked this conversation as resolved.
Show resolved Hide resolved
muharem marked this conversation as resolved.
Show resolved Hide resolved
// fn query_call_info(call: GetDispatchInfo, len: u32) -> RuntimeDispatchInfo<Balance>;
// fn query_weight_to_fee(call: GetDispatchInfo) -> Balance;
muharem marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Helper type to implement runtime api functions not included to the pallet
pub struct TransactionPayment<T, Balance>(PhantomData<(T, Balance)>);
impl<T, Balance> TransactionPayment<T, Balance>
where
T: pallet_transaction_payment::Config,
Balance: Codec + MaybeDisplay,
{
fn query_call_info(encoded_call: Bytes) -> Result<RuntimeDispatchInfo<Balance>, DispatchError> {
// let encoded_len = encoded_call.len();
// let call: Call = Call::decode(&mut &*encoded_call).map_err(|e| {
// Error(e) // TODO map decode error to DispatchError::Module to bubble error info
// });
// Ok (RuntimeDispatchInfo {
// weight,
// class,
// partial_fee: pallet_transaction_payment::Pallet::<T>::query_call_info(len, call) })
unimplemented!();
}

fn query_weight_to_fee(encoded_call: Bytes) -> Result<Balance, DispatchError> {
// let call: Call = Call::decode(&mut &*encoded_call).map_err(|e| {
// Error(e) // TODO map decode error to DispatchError::Module to bubble error info
// });
// Ok(pallet_transaction_payment::Pallet::<T>::query_weight_to_fee(call))
unimplemented!();
muharem marked this conversation as resolved.
Show resolved Hide resolved
}
}
32 changes: 32 additions & 0 deletions frame/transaction-payment/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ pub trait TransactionPaymentApi<BlockHash, ResponseType> {
encoded_xt: Bytes,
at: Option<BlockHash>,
) -> RpcResult<FeeDetails<NumberOrHex>>;

#[method(name = "payment_queryCallInfo")]
fn query_call_info(
&self,
encoded_call: Bytes,
at: Option<BlockHash>,
) -> RpcResult<RuntimeDispatchInfo<NumberOrHex>>;

#[method(name = "payment_queryWeightToFee")]
fn query_weight_to_fee(
muharem marked this conversation as resolved.
Show resolved Hide resolved
&self,
encoded_call: Bytes,
at: Option<BlockHash>,
) -> RpcResult<NumberOrHex>;
}

/// Provides RPC methods to query a dispatchable's class, weight and fee.
Expand Down Expand Up @@ -166,4 +180,22 @@ where
tip: Default::default(),
})
}

fn query_call_info(
&self,
encoded_call: Bytes,
at: Option<Block::Hash>,
) -> RpcResult<RuntimeDispatchInfo<NumberOrHex>> {
// TODO call api and map runtime api error to Error
unimplemented!();
}

fn query_weight_to_fee(
&self,
encoded_call: Bytes,
at: Option<Block::Hash>,
) -> RpcResult<NumberOrHex> {
// TODO call api and map runtime api error to Error
unimplemented!();
}
}
80 changes: 80 additions & 0 deletions frame/transaction-payment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,31 @@ where
}
}

/// Query runtime dispatch info of a given `Call`.
pub fn query_call_info<Call: GetDispatchInfo>(
muharem marked this conversation as resolved.
Show resolved Hide resolved
muharem marked this conversation as resolved.
Show resolved Hide resolved
call: Call,
len: u32,
) -> RuntimeDispatchInfo<BalanceOf<T>>
where
T::Call: Dispatchable<Info = DispatchInfo>,
muharem marked this conversation as resolved.
Show resolved Hide resolved
{
let dispatch_info = Call::get_dispatch_info(&call);
let DispatchInfo { weight, class, .. } = dispatch_info;

RuntimeDispatchInfo {
weight,
class,
partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()),
}
}

/// Query weight_to_fee of a given `Call`.
pub fn query_weight_to_fee<Call: GetDispatchInfo>(call: Call) -> BalanceOf<T> {
let dispatch_info = Call::get_dispatch_info(&call);

Self::weight_to_fee(dispatch_info.weight)
}

/// Compute the final fee value for a particular transaction.
pub fn compute_fee(len: u32, info: &DispatchInfoOf<T::Call>, tip: BalanceOf<T>) -> BalanceOf<T>
where
Expand Down Expand Up @@ -1206,6 +1231,61 @@ mod tests {
});
}

#[test]
fn query_call_info_works() {
let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 });
let info = call.get_dispatch_info();
let ext = call.encode();
let len = ext.len() as u32;

ExtBuilder::default().base_weight(5).weight_fee(2).build().execute_with(|| {
// all fees should be x1.5
<NextFeeMultiplier<Runtime>>::put(Multiplier::saturating_from_rational(3, 2));

assert_eq!(
TransactionPayment::query_call_info(call, len),
RuntimeDispatchInfo {
weight: info.weight,
class: info.class,
partial_fee: 5 * 2 /* base * weight_fee */
+ len as u64 /* len * 1 */
+ info.weight.min(BlockWeights::get().max_block) as u64 * 2 * 3 / 2 /* weight */
},
);
});
}

#[test]
fn query_weight_to_fee_works() {
let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 });
let info = call.get_dispatch_info();

let origin = 111111;
let extra = ();
let xt = TestXt::new(call.clone(), Some((origin, extra)));
let xt_info = xt.get_dispatch_info();

let unsigned_xt = TestXt::<_, ()>::new(call.clone(), None);
let unsigned_xt_info = unsigned_xt.get_dispatch_info();

ExtBuilder::default().weight_fee(2).build().execute_with(|| {
assert_eq!(
TransactionPayment::query_weight_to_fee(call),
info.weight.min(BlockWeights::get().max_block) as u64 * 2,
);

assert_eq!(
TransactionPayment::query_weight_to_fee(xt),
xt_info.weight.min(BlockWeights::get().max_block) as u64 * 2,
);

assert_eq!(
TransactionPayment::query_weight_to_fee(unsigned_xt),
unsigned_xt_info.weight.min(BlockWeights::get().max_block) as u64 * 2,
);
});
}

#[test]
fn compute_fee_works_without_multiplier() {
ExtBuilder::default()
Expand Down