Crate pallet_sudo

source ·
Expand description

Made with Substrate, for Polkadot.

github polkadot

Sudo Pallet

A pallet to provide a way to execute privileged runtime calls using a specified sudo (“superuser do”) account.

Pallet API

See the pallet module for more information about the interfaces this pallet exposes, including its configuration trait, dispatchables, storage items, events and errors.

Overview

In Substrate blockchains, pallets may contain dispatchable calls that can only be called at the system level of the chain (i.e. dispatchables that require a Root origin). Setting a privileged account, called the sudo key, allows you to make such calls as an extrinisic.

Here’s an example of a privileged function in another pallet:

#[frame_support::pallet]
pub mod pallet {
	use super::*;
	use frame_support::pallet_prelude::*;
	use frame_system::pallet_prelude::*;

	#[pallet::pallet]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: frame_system::Config {}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		#[pallet::weight(0)]
        pub fn privileged_function(origin: OriginFor<T>) -> DispatchResult {
            ensure_root(origin)?;

            // do something...

            Ok(())
        }
	}
}

With the Sudo pallet configured in your chain’s runtime you can execute this privileged function by constructing a call using the sudo dispatchable.

To use this pallet in your runtime, a sudo key must be specified in the GenesisConfig of the pallet. You can change this key at anytime once your chain is live using the set_key dispatchable, however only one sudo key can be set at a time. The pallet also allows you to make a call using sudo_unchecked_weight, which allows the sudo account to execute a call with a custom weight.

Note: this pallet is not meant to be used inside other pallets. It is only
meant to be used by constructing runtime calls from outside the runtime.

This pallet also defines a SignedExtension called CheckOnlySudoAccount to ensure that only signed transactions by the sudo account are accepted by the transaction pool. The intended use of this signed extension is to prevent other accounts from spamming the transaction pool for the initial phase of a chain, during which developers may only want a sudo account to be able to make transactions.

Learn more about the Root origin in the RawOrigin type documentation.

Examples

  1. You can make a privileged runtime call using sudo with an account that matches the sudo key.
#[test]
fn sudo_basics() {
	// Configure a default test environment and set the root `key` to 1.
	new_test_ext(1).execute_with(|| {
		// A privileged function should work when `sudo` is passed the root `key` as `origin`.
		let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
			i: 42,
			weight: Weight::from_parts(1_000, 0),
		}));
		assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call));
		assert_eq!(Logger::i32_log(), vec![42i32]);

		// A privileged function should not work when `sudo` is passed a non-root `key` as `origin`.
		let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log {
			i: 42,
			weight: Weight::from_parts(1_000, 0),
		}));
		assert_noop!(Sudo::sudo(RuntimeOrigin::signed(2), call), Error::<Test>::RequireSudo);
	});
}
  1. Only an existing sudo key can set a new one.
#[test]
fn set_key_basics() {
	new_test_ext(1).execute_with(|| {
		// A root `key` can change the root `key`
		assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2));
		assert_eq!(Key::<Test>::get(), Some(2u64));
	});

	new_test_ext(1).execute_with(|| {
		// A non-root `key` will trigger a `RequireSudo` error and a non-root `key` cannot change
		// the root `key`.
		assert_noop!(Sudo::set_key(RuntimeOrigin::signed(2), 3), Error::<Test>::RequireSudo);
	});
}
  1. You can also make non-privileged calls using sudo_as.
#[test]
fn sudo_as_emits_events_correctly() {
	new_test_ext(1).execute_with(|| {
		// A non-privileged function will work when passed to `sudo_as` with the root `key`.
		let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log {
			i: 42,
			weight: Weight::from_parts(1, 0),
		}));
		assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call));
		System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) }));
	});
}

Low Level / Implementation Details

This pallet checks that the caller of its dispatchables is a signed account and ensures that the caller matches the sudo key in storage. A caller of this pallet’s dispatchables does not pay any fees to dispatch a call. If the account making one of these calls is not the sudo key, the pallet returns a Error::RequireSudo error.

Once an origin is verified, sudo calls use dispatch_bypass_filter from the UnfilteredDispatchable trait to allow call execution without enforcing any further origin checks.

Re-exports

Modules

  • The pallet module in each FRAME pallet hosts the most important items needed to construct this pallet.
  • Autogenerated weights for pallet_sudo

Structs

  • Ensure that signed transactions are only valid if they are signed by sudo account.