From 507909c3be71f91e060713c5d00aea6750e4140a Mon Sep 17 00:00:00 2001
From: Xiliang Chen <xlchen1291@gmail.com>
Date: Mon, 13 Jan 2020 20:48:34 +1300
Subject: [PATCH] Improve PaysFee trait and dispatch info logic in utility
 module (#4606)

* pass target to PaysFee trait and allow batch call to be free if all its calls are free

* bump version

* fix error
---
 substrate/bin/node/runtime/src/lib.rs   |  4 +--
 substrate/frame/evm/src/lib.rs          |  4 +--
 substrate/frame/example/src/lib.rs      |  4 +--
 substrate/frame/support/src/dispatch.rs | 10 ++++---
 substrate/frame/support/src/weights.rs  |  8 +++---
 substrate/frame/utility/src/lib.rs      | 38 +++++++++++++++----------
 6 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index b3ff8b16283..4266ad7459e 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -80,8 +80,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// and set impl_version to equal spec_version. If only runtime
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
-	spec_version: 202,
-	impl_version: 202,
+	spec_version: 203,
+	impl_version: 203,
 	apis: RUNTIME_API_VERSIONS,
 };
 
diff --git a/substrate/frame/evm/src/lib.rs b/substrate/frame/evm/src/lib.rs
index 48b54a8c867..8d504127245 100644
--- a/substrate/frame/evm/src/lib.rs
+++ b/substrate/frame/evm/src/lib.rs
@@ -141,8 +141,8 @@ impl<T> ClassifyDispatch<T> for WeightForCallCreate {
 	}
 }
 
-impl PaysFee for WeightForCallCreate {
-	fn pays_fee(&self) -> bool {
+impl<T> PaysFee<T> for WeightForCallCreate {
+	fn pays_fee(&self, _: T) -> bool {
 		true
 	}
 }
diff --git a/substrate/frame/example/src/lib.rs b/substrate/frame/example/src/lib.rs
index 853674f6fd0..80569a1b573 100644
--- a/substrate/frame/example/src/lib.rs
+++ b/substrate/frame/example/src/lib.rs
@@ -301,8 +301,8 @@ impl<T: pallet_balances::Trait> ClassifyDispatch<(&BalanceOf<T>,)> for WeightFor
 	}
 }
 
-impl<T: pallet_balances::Trait> PaysFee for WeightForSetDummy<T> {
-	fn pays_fee(&self) -> bool {
+impl<T: pallet_balances::Trait> PaysFee<(&BalanceOf<T>,)> for WeightForSetDummy<T> {
+	fn pays_fee(&self, _target: (&BalanceOf<T>,)) -> bool {
 		true
 	}
 }
diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs
index 7d3750d9d4e..b2d7e6e1d40 100644
--- a/substrate/frame/support/src/dispatch.rs
+++ b/substrate/frame/support/src/dispatch.rs
@@ -1312,8 +1312,9 @@ macro_rules! decl_module {
 							&$weight,
 							($( $param_name, )*)
 						);
-						let pays_fee = <dyn $crate::dispatch::PaysFee>::pays_fee(
-							&$weight
+						let pays_fee = <dyn $crate::dispatch::PaysFee<( $( & $param, )* )>>::pays_fee(
+							&$weight,
+							($( $param_name, )*)
 						);
 						return $crate::dispatch::DispatchInfo { weight, class, pays_fee };
 					}
@@ -1331,8 +1332,9 @@ macro_rules! decl_module {
 					&$crate::dispatch::SimpleDispatchInfo::default(),
 					()
 				);
-				let pays_fee = <dyn $crate::dispatch::PaysFee>::pays_fee(
-					&$crate::dispatch::SimpleDispatchInfo::default()
+				let pays_fee = <dyn $crate::dispatch::PaysFee<_>>::pays_fee(
+					&$crate::dispatch::SimpleDispatchInfo::default(),
+					()
 				);
 				$crate::dispatch::DispatchInfo { weight, class, pays_fee }
 
diff --git a/substrate/frame/support/src/weights.rs b/substrate/frame/support/src/weights.rs
index b4b70def1d3..f1092b50023 100644
--- a/substrate/frame/support/src/weights.rs
+++ b/substrate/frame/support/src/weights.rs
@@ -78,8 +78,8 @@ pub trait WeighBlock<BlockNumber> {
 
 /// Indicates if dispatch function should pay fees or not.
 /// If set to false, the block resource limits are applied, yet no fee is deducted.
-pub trait PaysFee {
-	fn pays_fee(&self) -> bool {
+pub trait PaysFee<T> {
+	fn pays_fee(&self, _target: T) -> bool {
 		true
 	}
 }
@@ -208,8 +208,8 @@ impl<T> ClassifyDispatch<T> for SimpleDispatchInfo {
 	}
 }
 
-impl PaysFee for SimpleDispatchInfo {
-	fn pays_fee(&self) -> bool {
+impl<T> PaysFee<T> for SimpleDispatchInfo {
+	fn pays_fee(&self, _: T) -> bool {
 		match self {
 			SimpleDispatchInfo::FixedNormal(_) => true,
 			SimpleDispatchInfo::MaxNormal => true,
diff --git a/substrate/frame/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs
index 1f7e861373c..9ab2975e295 100644
--- a/substrate/frame/utility/src/lib.rs
+++ b/substrate/frame/utility/src/lib.rs
@@ -204,9 +204,9 @@ impl<Call: GetDispatchInfo> ClassifyDispatch<(&u16, &Box<Call>)> for Passthrough
 		call.get_dispatch_info().class
 	}
 }
-impl<Call: GetDispatchInfo> PaysFee for Passthrough<Call> {
-	fn pays_fee(&self) -> bool {
-		true
+impl<Call: GetDispatchInfo> PaysFee<(&u16, &Box<Call>)> for Passthrough<Call> {
+	fn pays_fee(&self, (_, call): (&u16, &Box<Call>)) -> bool {
+		call.get_dispatch_info().pays_fee
 	}
 }
 
@@ -226,13 +226,21 @@ impl<Call: GetDispatchInfo> WeighData<(&Vec<Call>,)> for BatchPassthrough<Call>
 	}
 }
 impl<Call: GetDispatchInfo> ClassifyDispatch<(&Vec<Call>,)> for BatchPassthrough<Call> {
-	fn classify_dispatch(&self, (_,): (&Vec<Call>,)) -> DispatchClass {
-		DispatchClass::Normal
+	fn classify_dispatch(&self, (calls,): (&Vec<Call>,)) -> DispatchClass {
+		let all_operational = calls.iter()
+			.map(|call| call.get_dispatch_info().class)
+			.all(|class| class == DispatchClass::Operational);
+		if all_operational {
+			DispatchClass::Operational
+		} else {
+			DispatchClass::Normal
+		}
 	}
 }
-impl<Call: GetDispatchInfo> PaysFee for BatchPassthrough<Call> {
-	fn pays_fee(&self) -> bool {
-		true
+impl<Call: GetDispatchInfo> PaysFee<(&Vec<Call>,)> for BatchPassthrough<Call> {
+	fn pays_fee(&self, (calls,): (&Vec<Call>,)) -> bool {
+		calls.iter()
+			.any(|call| call.get_dispatch_info().pays_fee)
 	}
 }
 
@@ -254,16 +262,16 @@ for MultiPassthrough<Call, AccountId, Timepoint>
 impl<Call: GetDispatchInfo, AccountId, Timepoint> ClassifyDispatch<(&u16, &Vec<AccountId>, &Timepoint, &Box<Call>)>
 for MultiPassthrough<Call, AccountId, Timepoint>
 {
-	fn classify_dispatch(&self, (_, _, _, _): (&u16, &Vec<AccountId>, &Timepoint, &Box<Call>))
+	fn classify_dispatch(&self, (_, _, _, call): (&u16, &Vec<AccountId>, &Timepoint, &Box<Call>))
 		-> DispatchClass
 	{
-		DispatchClass::Normal
+		call.get_dispatch_info().class
 	}
 }
-impl<Call: GetDispatchInfo, AccountId, Timepoint> PaysFee
+impl<Call: GetDispatchInfo, AccountId, Timepoint> PaysFee<(&u16, &Vec<AccountId>, &Timepoint, &Box<Call>)>
 for MultiPassthrough<Call, AccountId, Timepoint>
 {
-	fn pays_fee(&self) -> bool {
+	fn pays_fee(&self, _: (&u16, &Vec<AccountId>, &Timepoint, &Box<Call>)) -> bool {
 		true
 	}
 }
@@ -286,16 +294,16 @@ for SigsLen<AccountId, Timepoint>
 impl<AccountId, Timepoint> ClassifyDispatch<(&u16, &Vec<AccountId>, &Timepoint, &[u8; 32])>
 for SigsLen<AccountId, Timepoint>
 {
-	fn classify_dispatch(&self, (_, _, _, _): (&u16, &Vec<AccountId>, &Timepoint, &[u8; 32]))
+	fn classify_dispatch(&self, _: (&u16, &Vec<AccountId>, &Timepoint, &[u8; 32]))
 		-> DispatchClass
 	{
 		DispatchClass::Normal
 	}
 }
-impl<AccountId, Timepoint> PaysFee
+impl<AccountId, Timepoint> PaysFee<(&u16, &Vec<AccountId>, &Timepoint, &[u8; 32])>
 for SigsLen<AccountId, Timepoint>
 {
-	fn pays_fee(&self) -> bool {
+	fn pays_fee(&self, _: (&u16, &Vec<AccountId>, &Timepoint, &[u8; 32])) -> bool {
 		true
 	}
 }
-- 
GitLab