referrerpolicy=no-referrer-when-downgrade

frame_system/extensions/
check_non_zero_sender.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
18use crate::Config;
19use codec::{Decode, DecodeWithMemTracking, Encode};
20use core::marker::PhantomData;
21use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, DefaultNoBound};
22use scale_info::TypeInfo;
23use sp_runtime::{
24	impl_tx_ext_default,
25	traits::{DispatchInfoOf, TransactionExtension},
26	transaction_validity::InvalidTransaction,
27};
28
29/// Check to ensure that the sender is not the zero address.
30#[derive(Encode, Decode, DecodeWithMemTracking, DefaultNoBound, Clone, Eq, PartialEq, TypeInfo)]
31#[scale_info(skip_type_params(T))]
32pub struct CheckNonZeroSender<T>(PhantomData<T>);
33
34impl<T: Config + Send + Sync> core::fmt::Debug for CheckNonZeroSender<T> {
35	#[cfg(feature = "std")]
36	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
37		write!(f, "CheckNonZeroSender")
38	}
39
40	#[cfg(not(feature = "std"))]
41	fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
42		Ok(())
43	}
44}
45
46impl<T: Config + Send + Sync> CheckNonZeroSender<T> {
47	/// Create new `TransactionExtension` to check runtime version.
48	pub fn new() -> Self {
49		Self(core::marker::PhantomData)
50	}
51}
52
53impl<T: Config + Send + Sync> TransactionExtension<T::RuntimeCall> for CheckNonZeroSender<T> {
54	const IDENTIFIER: &'static str = "CheckNonZeroSender";
55	type Implicit = ();
56	type Val = ();
57	type Pre = ();
58
59	fn weight(&self, _: &T::RuntimeCall) -> sp_weights::Weight {
60		<T::ExtensionsWeightInfo as super::WeightInfo>::check_non_zero_sender()
61	}
62
63	fn validate(
64		&self,
65		origin: <T as Config>::RuntimeOrigin,
66		_call: &T::RuntimeCall,
67		_info: &DispatchInfoOf<T::RuntimeCall>,
68		_len: usize,
69		_self_implicit: Self::Implicit,
70		_inherited_implication: &impl Encode,
71		_source: TransactionSource,
72	) -> sp_runtime::traits::ValidateResult<Self::Val, T::RuntimeCall> {
73		if let Some(who) = origin.as_signer() {
74			if who.using_encoded(|d| d.iter().all(|x| *x == 0)) {
75				return Err(InvalidTransaction::BadSigner.into())
76			}
77		}
78		Ok((Default::default(), (), origin))
79	}
80	impl_tx_ext_default!(T::RuntimeCall; prepare);
81}
82
83#[cfg(test)]
84mod tests {
85	use super::*;
86	use crate::mock::{new_test_ext, Test, CALL};
87	use frame_support::{assert_ok, dispatch::DispatchInfo};
88	use sp_runtime::{
89		traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, TxBaseImplication},
90		transaction_validity::{TransactionSource::External, TransactionValidityError},
91	};
92
93	#[test]
94	fn zero_account_ban_works() {
95		new_test_ext().execute_with(|| {
96			let info = DispatchInfo::default();
97			let len = 0_usize;
98			assert_eq!(
99				CheckNonZeroSender::<Test>::new()
100					.validate_only(Some(0).into(), CALL, &info, len, External, 0)
101					.unwrap_err(),
102				TransactionValidityError::from(InvalidTransaction::BadSigner)
103			);
104			assert_ok!(CheckNonZeroSender::<Test>::new().validate_only(
105				Some(1).into(),
106				CALL,
107				&info,
108				len,
109				External,
110				0,
111			));
112		})
113	}
114
115	#[test]
116	fn unsigned_origin_works() {
117		new_test_ext().execute_with(|| {
118			let info = DispatchInfo::default();
119			let len = 0_usize;
120			let (_, _, origin) = CheckNonZeroSender::<Test>::new()
121				.validate(None.into(), CALL, &info, len, (), &TxBaseImplication(CALL), External)
122				.unwrap();
123			assert!(!origin.is_transaction_authorized());
124		})
125	}
126}