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	/// - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on the
41	///   congestion of the network.
42	/// - `weight_fee`: This amount is computed based on the weight of the transaction. Weight
43	/// accounts for the execution time of a transaction.
44	///
45	/// adjusted_weight_fee = targeted_fee_adjustment * weight_fee
46	pub adjusted_weight_fee: Balance,
47}
48
49impl<Balance: AtLeast32BitUnsigned + Copy> InclusionFee<Balance> {
50	/// Returns the total of inclusion fee.
51	///
52	/// ```ignore
53	/// inclusion_fee = base_fee + len_fee + adjusted_weight_fee
54	/// ```
55	pub fn inclusion_fee(&self) -> Balance {
56		self.base_fee
57			.saturating_add(self.len_fee)
58			.saturating_add(self.adjusted_weight_fee)
59	}
60}
61
62/// The `FeeDetails` is composed of:
63///   - (Optional) `inclusion_fee`: Only the `Pays::Yes` transaction can have the inclusion fee.
64///   - `tip`: If included in the transaction, the tip will be added on top. Only signed
65///     transactions can have a tip.
66#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
67#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
68#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
69pub struct FeeDetails<Balance> {
70	/// The minimum fee for a transaction to be included in a block.
71	pub inclusion_fee: Option<InclusionFee<Balance>>,
72	// Do not serialize and deserialize `tip` as we actually can not pass any tip to the RPC.
73	#[cfg_attr(feature = "std", serde(skip))]
74	pub tip: Balance,
75}
76
77impl<Balance: AtLeast32BitUnsigned + Copy> FeeDetails<Balance> {
78	/// Returns the final fee.
79	///
80	/// ```ignore
81	/// final_fee = inclusion_fee + tip;
82	/// ```
83	pub fn final_fee(&self) -> Balance {
84		self.inclusion_fee
85			.as_ref()
86			.map(|i| i.inclusion_fee())
87			.unwrap_or_else(|| Zero::zero())
88			.saturating_add(self.tip)
89	}
90}
91
92/// Information related to a dispatchable's class, weight, and fee that can be queried from the
93/// runtime.
94#[derive(Eq, PartialEq, Encode, Decode, Default, TypeInfo)]
95#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize, Clone))]
96#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
97#[cfg_attr(
98	feature = "std",
99	serde(bound(serialize = "Balance: std::fmt::Display, Weight: Serialize"))
100)]
101#[cfg_attr(
102	feature = "std",
103	serde(bound(deserialize = "Balance: std::str::FromStr, Weight: Deserialize<'de>"))
104)]
105pub struct RuntimeDispatchInfo<Balance, Weight = frame_support::weights::Weight> {
106	/// Weight of this dispatch.
107	pub weight: Weight,
108	/// Class of this dispatch.
109	pub class: DispatchClass,
110	/// The inclusion fee of this dispatch.
111	///
112	/// This does not include a tip or anything else that
113	/// depends on the signature (i.e. depends on a `TransactionExtension`).
114	#[cfg_attr(feature = "std", serde(with = "serde_balance"))]
115	pub partial_fee: Balance,
116}
117
118#[cfg(feature = "std")]
119mod serde_balance {
120	use serde::{Deserialize, Deserializer, Serializer};
121
122	pub fn serialize<S: Serializer, T: std::fmt::Display>(
123		t: &T,
124		serializer: S,
125	) -> Result<S::Ok, S::Error> {
126		serializer.serialize_str(&t.to_string())
127	}
128
129	pub fn deserialize<'de, D: Deserializer<'de>, T: std::str::FromStr>(
130		deserializer: D,
131	) -> Result<T, D::Error> {
132		let s = String::deserialize(deserializer)?;
133		s.parse::<T>().map_err(|_| serde::de::Error::custom("Parse from string failed"))
134	}
135}
136
137#[cfg(test)]
138mod tests {
139	use super::*;
140	use frame_support::weights::Weight;
141
142	#[test]
143	fn should_serialize_and_deserialize_properly_with_string() {
144		let info = RuntimeDispatchInfo {
145			weight: Weight::from_parts(5, 0),
146			class: DispatchClass::Normal,
147			partial_fee: 1_000_000_u64,
148		};
149
150		let json_str =
151			r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"1000000"}"#;
152
153		assert_eq!(serde_json::to_string(&info).unwrap(), json_str);
154		assert_eq!(serde_json::from_str::<RuntimeDispatchInfo<u64>>(json_str).unwrap(), info);
155
156		// should not panic
157		serde_json::to_value(&info).unwrap();
158	}
159
160	#[test]
161	fn should_serialize_and_deserialize_properly_large_value() {
162		let info = RuntimeDispatchInfo {
163			weight: Weight::from_parts(5, 0),
164			class: DispatchClass::Normal,
165			partial_fee: u128::max_value(),
166		};
167
168		let json_str = r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#;
169
170		assert_eq!(serde_json::to_string(&info).unwrap(), json_str);
171		assert_eq!(serde_json::from_str::<RuntimeDispatchInfo<u128>>(json_str).unwrap(), info);
172
173		// should not panic
174		serde_json::to_value(&info).unwrap();
175	}
176}