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, Encode};
20use core::marker::PhantomData;
21use frame_support::{dispatch::DispatchInfo, DefaultNoBound};
22use scale_info::TypeInfo;
23use sp_runtime::{
24	traits::{DispatchInfoOf, Dispatchable, SignedExtension},
25	transaction_validity::{
26		InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,
27	},
28};
29
30/// Check to ensure that the sender is not the zero address.
31#[derive(Encode, Decode, DefaultNoBound, Clone, Eq, PartialEq, TypeInfo)]
32#[scale_info(skip_type_params(T))]
33pub struct CheckNonZeroSender<T>(PhantomData<T>);
34
35impl<T: Config + Send + Sync> core::fmt::Debug for CheckNonZeroSender<T> {
36	#[cfg(feature = "std")]
37	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
38		write!(f, "CheckNonZeroSender")
39	}
40
41	#[cfg(not(feature = "std"))]
42	fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
43		Ok(())
44	}
45}
46
47impl<T: Config + Send + Sync> CheckNonZeroSender<T> {
48	/// Create new `SignedExtension` to check runtime version.
49	pub fn new() -> Self {
50		Self(core::marker::PhantomData)
51	}
52}
53
54impl<T: Config + Send + Sync> SignedExtension for CheckNonZeroSender<T>
55where
56	T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
57{
58	type AccountId = T::AccountId;
59	type Call = T::RuntimeCall;
60	type AdditionalSigned = ();
61	type Pre = ();
62	const IDENTIFIER: &'static str = "CheckNonZeroSender";
63
64	fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> {
65		Ok(())
66	}
67
68	fn pre_dispatch(
69		self,
70		who: &Self::AccountId,
71		call: &Self::Call,
72		info: &DispatchInfoOf<Self::Call>,
73		len: usize,
74	) -> Result<Self::Pre, TransactionValidityError> {
75		self.validate(who, call, info, len).map(|_| ())
76	}
77
78	fn validate(
79		&self,
80		who: &Self::AccountId,
81		_call: &Self::Call,
82		_info: &DispatchInfoOf<Self::Call>,
83		_len: usize,
84	) -> TransactionValidity {
85		if who.using_encoded(|d| d.iter().all(|x| *x == 0)) {
86			return Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner))
87		}
88		Ok(ValidTransaction::default())
89	}
90}
91
92#[cfg(test)]
93mod tests {
94	use super::*;
95	use crate::mock::{new_test_ext, Test, CALL};
96	use frame_support::{assert_noop, assert_ok};
97
98	#[test]
99	fn zero_account_ban_works() {
100		new_test_ext().execute_with(|| {
101			let info = DispatchInfo::default();
102			let len = 0_usize;
103			assert_noop!(
104				CheckNonZeroSender::<Test>::new().validate(&0, CALL, &info, len),
105				InvalidTransaction::BadSigner
106			);
107			assert_ok!(CheckNonZeroSender::<Test>::new().validate(&1, CALL, &info, len));
108		})
109	}
110}