referrerpolicy=no-referrer-when-downgrade

pallet_transaction_payment/
types.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Types for transaction-payment RPC.
19
20use codec::{Decode, Encode};
21#[cfg(feature = "std")]
22use serde::{Deserialize, Serialize};
23
24use scale_info::TypeInfo;
25
26use sp_runtime::traits::{AtLeast32BitUnsigned, Zero};
27
28use frame_support::dispatch::DispatchClass;
29
30/// The base fee and adjusted weight and length fees constitute the _inclusion fee_.
31#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
32#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
33#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
34pub struct InclusionFee<Balance> {
35	/// This is the minimum amount a user pays for a transaction. It is declared
36	/// as a base _weight_ in the runtime and converted to a fee using `WeightToFee`.
37	pub base_fee: Balance,
38	/// The length fee, the amount paid for the encoded length (in bytes) of the transaction.
39	pub len_fee: Balance,
40	///
41	/// - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on the
42	///   congestion of the network.
43	/// - `weight_fee`: This amount is computed based on the weight of the transaction. Weight
44	/// accounts for the execution time of a transaction.
45	///
46	/// adjusted_weight_fee = targeted_fee_adjustment * weight_fee
47	pub adjusted_weight_fee: Balance,
48}
49
50impl<Balance: AtLeast32BitUnsigned + Copy> InclusionFee<Balance> {
51	/// Returns the total of inclusion fee.
52	///
53	/// ```ignore
54	/// inclusion_fee = base_fee + len_fee + adjusted_weight_fee
55	/// ```
56	pub fn inclusion_fee(&self) -> Balance {
57		self.base_fee
58			.saturating_add(self.len_fee)
59			.saturating_add(self.adjusted_weight_fee)
60	}
61}
62
63/// The `FeeDetails` is composed of:
64///   - (Optional) `inclusion_fee`: Only the `Pays::Yes` transaction can have the inclusion fee.
65///   - `tip`: If included in the transaction, the tip will be added on top. Only signed
66///     transactions can have a tip.
67#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
68#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
69#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
70pub struct FeeDetails<Balance> {
71	/// The minimum fee for a transaction to be included in a block.
72	pub inclusion_fee: Option<InclusionFee<Balance>>,
73	// Do not serialize and deserialize `tip` as we actually can not pass any tip to the RPC.
74	#[cfg_attr(feature = "std", serde(skip))]
75	pub tip: Balance,
76}
77
78impl<Balance: AtLeast32BitUnsigned + Copy> FeeDetails<Balance> {
79	/// Returns the final fee.
80	///
81	/// ```ignore
82	/// final_fee = inclusion_fee + tip;
83	/// ```
84	pub fn final_fee(&self) -> Balance {
85		self.inclusion_fee
86			.as_ref()
87			.map(|i| i.inclusion_fee())
88			.unwrap_or_else(|| Zero::zero())
89			.saturating_add(self.tip)
90	}
91}
92
93/// Information related to a dispatchable's class, weight, and fee that can be queried from the
94/// runtime.
95#[derive(Eq, PartialEq, Encode, Decode, Default, TypeInfo)]
96#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize, Clone))]
97#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
98#[cfg_attr(
99	feature = "std",
100	serde(bound(serialize = "Balance: std::fmt::Display, Weight: Serialize"))
101)]
102#[cfg_attr(
103	feature = "std",
104	serde(bound(deserialize = "Balance: std::str::FromStr, Weight: Deserialize<'de>"))
105)]
106pub struct RuntimeDispatchInfo<Balance, Weight = frame_support::weights::Weight> {
107	/// Weight of this dispatch.
108	pub weight: Weight,
109	/// Class of this dispatch.
110	pub class: DispatchClass,
111	/// The inclusion fee of this dispatch.
112	///
113	/// This does not include a tip or anything else that
114	/// depends on the signature (i.e. depends on a `TransactionExtension`).
115	#[cfg_attr(feature = "std", serde(with = "serde_balance"))]
116	pub partial_fee: Balance,
117}
118
119#[cfg(feature = "std")]
120mod serde_balance {
121	use serde::{Deserialize, Deserializer, Serializer};
122
123	pub fn serialize<S: Serializer, T: std::fmt::Display>(
124		t: &T,
125		serializer: S,
126	) -> Result<S::Ok, S::Error> {
127		serializer.serialize_str(&t.to_string())
128	}
129
130	pub fn deserialize<'de, D: Deserializer<'de>, T: std::str::FromStr>(
131		deserializer: D,
132	) -> Result<T, D::Error> {
133		let s = String::deserialize(deserializer)?;
134		s.parse::<T>().map_err(|_| serde::de::Error::custom("Parse from string failed"))
135	}
136}
137
138#[cfg(test)]
139mod tests {
140	use super::*;
141	use frame_support::weights::Weight;
142
143	#[test]
144	fn should_serialize_and_deserialize_properly_with_string() {
145		let info = RuntimeDispatchInfo {
146			weight: Weight::from_parts(5, 0),
147			class: DispatchClass::Normal,
148			partial_fee: 1_000_000_u64,
149		};
150
151		let json_str =
152			r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"1000000"}"#;
153
154		assert_eq!(serde_json::to_string(&info).unwrap(), json_str);
155		assert_eq!(serde_json::from_str::<RuntimeDispatchInfo<u64>>(json_str).unwrap(), info);
156
157		// should not panic
158		serde_json::to_value(&info).unwrap();
159	}
160
161	#[test]
162	fn should_serialize_and_deserialize_properly_large_value() {
163		let info = RuntimeDispatchInfo {
164			weight: Weight::from_parts(5, 0),
165			class: DispatchClass::Normal,
166			partial_fee: u128::max_value(),
167		};
168
169		let json_str = r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#;
170
171		assert_eq!(serde_json::to_string(&info).unwrap(), json_str);
172		assert_eq!(serde_json::from_str::<RuntimeDispatchInfo<u128>>(json_str).unwrap(), info);
173
174		// should not panic
175		serde_json::to_value(&info).unwrap();
176	}
177}